Hello,

It seems my last email was marked spam. It's strange that the bug tracker has received my reply but the mailing list didn't. Please correct me if I misunderstand the situation.

My previous reply can be viewed at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=852757

The patch is attached again for convenience. This patch implemented Anders's idea. The signal handler will only set a flag. After signal handler completed, the pselect() in pkgDPkgPM::Go() will return immediately with errno set to EINTR. Then, progress->Pluse() is called by pkgDPkgPM::Go(), and PackageManagerFancy::Pluse() will redraw the status bar.

I looked around for similar bugs. I found #947279 might be the same bug, but I don't have much evidence.

Best regards,
Zhang Boyang
From 6cdd7fe9476a8149bc5bf18f70f9a8a30ba92d3a Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang...@gmail.com>
Date: Wed, 24 Nov 2021 23:34:04 +0800
Subject: [PATCH] Fix incorrect SIGWINCH handling

Previously, status line is redrawn in signal handler. However, the
drawing code make heavy use of std::string and other syscalls, which may
not be async-signal-safe. This will cause deadlock, overwritten errno,
even silent memory corruption.

With this patch, the signal handler will only set a flag, which is
async-signal-safe, and actual redrawing will be deferred to Pulse().

Closes: #852757
---
 apt-pkg/install-progress.cc | 31 +++++++++++++++++++++----------
 apt-pkg/install-progress.h  |  8 +++++---
 2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/apt-pkg/install-progress.cc b/apt-pkg/install-progress.cc
index aadd28e51..99f16bffa 100644
--- a/apt-pkg/install-progress.cc
+++ b/apt-pkg/install-progress.cc
@@ -222,22 +222,22 @@ PackageManagerFancy::PackageManagerFancy()
    : d(NULL), child_pty(-1)
 {
    // setup terminal size
-   old_SIGWINCH = signal(SIGWINCH, PackageManagerFancy::staticSIGWINCH);
-   instances.push_back(this);
+   if (instances++ == 0)
+      old_SIGWINCH = signal(SIGWINCH, PackageManagerFancy::staticSIGWINCH);
 }
-std::vector<PackageManagerFancy*> PackageManagerFancy::instances;
+int PackageManagerFancy::instances = 0;
+sighandler_t PackageManagerFancy::old_SIGWINCH;
+volatile sig_atomic_t PackageManagerFancy::SIGWINCH_flag = 0;
 
 PackageManagerFancy::~PackageManagerFancy()
 {
-   instances.erase(find(instances.begin(), instances.end(), this));
-   signal(SIGWINCH, old_SIGWINCH);
+   if (--instances == 0)
+      signal(SIGWINCH, old_SIGWINCH);
 }
 
-void PackageManagerFancy::staticSIGWINCH(int signum)
+void PackageManagerFancy::staticSIGWINCH(int)
 {
-   std::vector<PackageManagerFancy *>::const_iterator I;
-   for(I = instances.begin(); I != instances.end(); ++I)
-      (*I)->HandleSIGWINCH(signum);
+   SIGWINCH_flag = 1;
 }
 
 PackageManagerFancy::TermSize
@@ -294,13 +294,24 @@ void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows)
      }
 }
 
-void PackageManagerFancy::HandleSIGWINCH(int)
+void PackageManagerFancy::HandleSIGWINCH()
 {
    int const nr_terminal_rows = GetTerminalSize().rows;
    SetupTerminalScrollArea(nr_terminal_rows);
    DrawStatusLine();
 }
 
+void PackageManagerFancy::Pulse()
+{
+   if (SIGWINCH_flag)
+   {
+      SIGWINCH_flag = 0;
+      int errsv = errno;
+      HandleSIGWINCH();
+      errno = errsv;
+   }
+}
+
 void PackageManagerFancy::Start(int a_child_pty)
 {
    child_pty = a_child_pty;
diff --git a/apt-pkg/install-progress.h b/apt-pkg/install-progress.h
index 94b66ed9b..d1dd3eb8a 100644
--- a/apt-pkg/install-progress.h
+++ b/apt-pkg/install-progress.h
@@ -125,12 +125,14 @@ namespace Progress {
     void * const d;
  private:
     APT_HIDDEN static void staticSIGWINCH(int);
-    static std::vector<PackageManagerFancy*> instances;
+    static int instances;
+    static sighandler_t old_SIGWINCH;
+    static volatile sig_atomic_t SIGWINCH_flag;
     APT_HIDDEN bool DrawStatusLine();
 
  protected:
     void SetupTerminalScrollArea(int nr_rows);
-    void HandleSIGWINCH(int);
+    void HandleSIGWINCH();
 
     typedef struct {
        int rows;
@@ -138,12 +140,12 @@ namespace Progress {
     } TermSize;
     TermSize GetTerminalSize();
 
-    sighandler_t old_SIGWINCH;
     int child_pty;
 
  public:
     PackageManagerFancy();
     virtual ~PackageManagerFancy();
+    virtual void Pulse() APT_OVERRIDE;
     virtual void Start(int child_pty=-1) APT_OVERRIDE;
     virtual void Stop() APT_OVERRIDE;
     virtual bool StatusChanged(std::string PackageName,
-- 
2.30.2

Reply via email to