[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#945188: xpdf: memory leak when changing page



Control: tags -1 + patch


Dear Maintainer,
I tried to have a look and found something.

This issue might be in the package since poppler-0.71.patch.
This patch makes some changes how containers get accessed.

Following I found and tried to change in attached patch:
- std::erase, std::clear, std::remove:
  These methods of STL containers containing pointer to objects do
  not delete the objects pointed to.
- In continuousView in PDFCore::addPage the next page was inserted
  at the first position.

For running with valgrind it was nice to have the additional cflag
HAVE_XTAPPSETEXITFLAG set, as then the application cleans up
instead of just exit(0).

Bug #942086 and #926501 might be related.

Kind regards,
Bernhard
# Unstable amd64 qemu VM 2019-11-21

apt update
apt dist-upgrade


apt install dpkg-dev devscripts quilt systemd-coredump xserver-xorg lightdm openbox xterm htop mc gdb valgrind heaptrack heaptrack-gui pari-doc xpdf xpdf-dbgsym libfreetype6-dbgsym libpoppler82-dbgsym
apt build-dep xpdf



mkdir /home/benutzer/source/xpdf/orig -p
cd    /home/benutzer/source/xpdf/orig
apt source xpdf
cd

mkdir /home/benutzer/source/libpoppler82/orig -p
cd    /home/benutzer/source/libpoppler82/orig
apt source libpoppler82
cd




export LANG=C
export DISPLAY=:0

/usr/bin/xpdf.real /usr/share/pari/doc/users.pdf

# ~10 times next page and previous page - memory usage doubles.





##########


# wget https://github.com/WuBingzheng/memleax/releases/download/v1.1.1/memleax_1.1.1-1_amd64.deb
# dpkg -i memleax_1.1.1-1_amd64.deb
# memleax $(pidof xpdf.real)
# gdb -q --args xpdf.real /usr/share/pari/doc/users.pdf
#   Reading symbols from /usr/lib/debug/.build-id/ab/a6d385be8071a6a44247a89331bee9f0494091.debug...
# memleax -d /usr/lib/debug/.build-id/ab/a6d385be8071a6a44247a89331bee9f0494091.debug $(pidof xpdf.real)
# Had no output at all.


##########


script -a valgrind-xpdf.real_$(date +%Y-%m-%d_%H-%M-%S).txt -c 'valgrind /usr/bin/xpdf.real /usr/share/pari/doc/users.pdf'

script -a valgrind-xpdf.real_$(date +%Y-%m-%d_%H-%M-%S).txt -c 'valgrind --leak-check=full --show-reachable=yes --leak-resolution=high --num-callers=100 --trace-children=yes /usr/bin/xpdf.real /usr/share/pari/doc/users.pdf'


==35071== 34,438,272 bytes in 11 blocks are possibly lost in loss record 1,608 of 1,608
==35071==    at 0x483577F: malloc (vg_replace_malloc.c:309)
==35071==    by 0x11F82C: gmalloc (gmem.h:41)
==35071==    by 0x11F82C: gmallocn (gmem.h:115)
==35071==    by 0x11F82C: XPDFCore::updateTileData(PDFCoreTile*, int, int, int, int, bool) (XPDFCore.cc:1276)
==35071==    by 0x119C5C: PDFCore::clippedRedrawRect(PDFCoreTile*, int, int, int, int, int, int, int, int, int, int, bool, bool) (PDFCore.cc:2171)
==35071==    by 0x119D5F: PDFCore::redrawCbk(void*, int, int, int, int, bool) (PDFCore.cc:2068)
==35071==    by 0x1166F5: dump (CoreOutputDev.cc:53)
==35071==    by 0x1166F5: CoreOutputDev::dump() (CoreOutputDev.cc:46)
==35071==    by 0x4E6016F: Gfx::go(bool) (Gfx.cc:827)
==35071==    by 0x4E6049D: Gfx::display(Object*, bool) (Gfx.cc:714)
==35071==    by 0x4EB6940: Page::displaySlice(OutputDev*, double, double, int, bool, bool, int, int, int, int, bool, bool (*)(void*), void*, bool (*)(Annot*, void*), void*, bool) (Page.cc:548)
==35071==    by 0x11AD82: PDFCore::needTile(PDFCorePage*, int, int) (PDFCore.cc:924)
==35071==    by 0x11BBB0: PDFCore::update(int, int, int, double, int, bool, bool, bool) (PDFCore.cc:724)
==35071==    by 0x122380: XPDFCore::update(int, int, int, double, int, bool, bool, bool) (XPDFCore.cc:297)
==35071==    by 0x11734E: gotoNextPage (PDFCore.cc:963)
==35071==    by 0x11734E: PDFCore::gotoNextPage(int, bool) (PDFCore.cc:947)
==35071==    by 0x1223E1: XPDFCore::gotoNextPage(int, bool) (XPDFCore.cc:325)
==35071==    by 0x127937: XPDFViewer::nextPageCbk(_WidgetRec*, void*, void*) (XPDFViewer.cc:2451)
==35071==    by 0x49361BA: ??? (in /usr/lib/x86_64-linux-gnu/libXm.so.4.0.4)
==35071==    by 0x505F4DE: ??? (in /usr/lib/x86_64-linux-gnu/libXt.so.6.0.0)
==35071==    by 0x5060552: _XtTranslateEvent (in /usr/lib/x86_64-linux-gnu/libXt.so.6.0.0)
==35071==    by 0x5038479: XtDispatchEventToWidget (in /usr/lib/x86_64-linux-gnu/libXt.so.6.0.0)
==35071==    by 0x5038ED1: ??? (in /usr/lib/x86_64-linux-gnu/libXt.so.6.0.0)
==35071==    by 0x5039030: XtDispatchEvent (in /usr/lib/x86_64-linux-gnu/libXt.so.6.0.0)
==35071==    by 0x5044CFF: XtAppProcessEvent (in /usr/lib/x86_64-linux-gnu/libXt.so.6.0.0)
==35071==    by 0x503944C: XtAppMainLoop (in /usr/lib/x86_64-linux-gnu/libXt.so.6.0.0)
==35071==    by 0x11626C: main (xpdf.cc:310)



gdb -q --args /usr/bin/xpdf.real /usr/share/pari/doc/users.pdf

set width 0
set pagination off
directory /home/benutzer/source/xpdf/orig/xpdf-3.04/xpdf
directory /home/benutzer/source/libpoppler82/orig/poppler-0.71.0
b CoreOutputDev::CoreOutputDev
y
run


###############


try1:

debian/rules
HAVE_XTAPPSETEXITFLAG 
--> XPDFApp::~XPDFApp get now reached

xpdf/XPDFApp.cc
void XPDFApp::quit() {
  if (remoteAtom != None) {
    XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
  }
  for (auto ptr : *viewers) {
    delete static_cast<XPDFViewer*>(ptr);
  }
  viewers->clear();
-> clear of a std::vector of pointer to type does not call the destructor on the type pointed to




b XPDFViewer::~XPDFViewer
b XPDFApp::~XPDFApp
b XPDFApp::quit

gdb -q --args /usr/bin/xpdf.real /usr/share/pari/doc/users.pdf

set width 0
set pagination off
directory /home/benutzer/source/xpdf/try1/xpdf-3.04/xpdf
directory /home/benutzer/source/libpoppler82/orig/poppler-0.71.0
b XPDFCore::updateTileData
run


##########


benutzer@debian:~$ heaptrack /usr/bin/xpdf.real /usr/share/pari/doc/users.pdf
heaptrack output will be written to "/home/benutzer/heaptrack.xpdf.real.1182.gz"
starting application, this might take some time...
free(): invalid pointer
Aborted (core dumped)
heaptrack stats:
        allocations:            2445627
        leaked allocations:     496282
        temporary allocations:  231256
Heaptrack finished! Now run the following to investigate the data:

  heaptrack --analyze "/home/benutzer/heaptrack.xpdf.real.1182.gz"

benutzer@debian:~$ script -a heaptrack-xpdf.real.1182.txt -c 'heaptrack --analyze "/home/benutzer/heaptrack.xpdf.real.1182.gz"'


gdb -q --args /usr/bin/xpdf.real /usr/share/pari/doc/users.pdf

set width 0
set pagination off
b FT_Load_Glyph
y
run
Description: Update poppler-0.71.patch
 Change some accesses to containers to avoid memory leaks.

Author: Bernhard Ã?belacker <bernhardu@mailbox.org>

Bug-Debian: https://bugs.debian.org/945188
Forwarded: no
Last-Update: 2019-11-21

--- xpdf-3.04.orig/xpdf/GlobalParams.cc
+++ xpdf-3.04/xpdf/GlobalParams.cc
@@ -1671,6 +1671,7 @@ void GlobalParams::parseBind(GList *toke
     if (binding->code == code &&
 	binding->mods == mods &&
 	binding->context == context) {
+      delete static_cast<KeyBinding*>(*it);
       keyBindings->erase(it);
       break;
     }
@@ -1701,6 +1702,7 @@ void GlobalParams::parseUnbind(GList *to
     if (binding->code == code &&
 	binding->mods == mods &&
 	binding->context == context) {
+      delete static_cast<KeyBinding*>(*it);
       keyBindings->erase(it);
       break;
     }
--- xpdf-3.04.orig/xpdf/PDFCore.cc
+++ xpdf-3.04/xpdf/PDFCore.cc
@@ -208,6 +208,7 @@ int PDFCore::loadFile2(PDFDoc *newDoc) {
   // nothing displayed yet
   topPage = -99;
   midPage = -99;
+  for (auto ptr : *pages) { delete static_cast<PDFCorePage*>(ptr); }
   pages->clear();
 
   // compute the max unscaled page size
@@ -242,6 +243,7 @@ void PDFCore::clear() {
   // no page displayed
   topPage = -99;
   midPage = -99;
+  for (auto ptr : *pages) { delete static_cast<PDFCorePage*>(ptr); }
   pages->clear();
 
   // redraw
@@ -265,6 +267,7 @@ PDFDoc *PDFCore::takeDoc(GBool redraw) {
   // no page displayed
   topPage = -99;
   midPage = -99;
+  for (auto ptr : *pages) { delete static_cast<PDFCorePage*>(ptr); }
   pages->clear();
 
   // redraw
@@ -485,6 +488,7 @@ void PDFCore::update(int topPageA, int s
       rotateA != rotate) {
     needUpdate = gTrue;
     setSelection(0, 0, 0, 0, 0);
+    for (auto ptr : *pages) { delete static_cast<PDFCorePage*>(ptr); }
     pages->clear();
     zoom = zoomA;
     rotate = rotateA;
@@ -607,17 +611,12 @@ void PDFCore::update(int topPageA, int s
     // objects that are needed
     for (auto it = pages->begin(); it != pages->end();) {
       auto page = static_cast<PDFCorePage *> (*it);
-      if (page->page >= pg0)
-        break;
-      it = pages->erase(it);
-    }
-
-    for (auto it = pages->rbegin(); it != pages->rend();) {
-      auto page = static_cast<PDFCorePage *> (*it);
-      if (page->page <= pg1)
-        break;
-
-      it = decltype(it){ pages->erase(std::next(it).base()) };
+      if (page->page >= pg0 && page->page <=pg1) {
+        it++;
+      } else {
+        delete static_cast<PDFCorePage*>(*it);
+        it = pages->erase(it);
+      }
     }
 
     j = pages->getLength() > 0 ? ((PDFCorePage *)pages->get(0))->page - 1
@@ -663,6 +662,7 @@ void PDFCore::update(int topPageA, int s
 	  tile->xMin > scrollX + drawAreaWidth + drawAreaWidth / 2 ||
 	  y1 < scrollY - drawAreaHeight / 2 ||
 	  y0 > scrollY + drawAreaHeight + drawAreaHeight / 2) {
+        delete static_cast<PDFCoreTile*>(*itt);
         itt = page->tiles->erase(itt);
       } else {
         itt++;
@@ -839,7 +839,7 @@ void PDFCore::addPage(int pg, int rot) {
     }
   }
 
-  pages->insert(pages->begin(), page);
+  pages->push_back(page);
 }
 
 void PDFCore::needTile(PDFCorePage *page, int x, int y) {
--- xpdf-3.04.orig/xpdf/XPDFApp.cc
+++ xpdf-3.04/xpdf/XPDFApp.cc
@@ -265,9 +265,9 @@ XPDFViewer *XPDFApp::openAtDest(GString
 
 XPDFViewer *XPDFApp::reopen(XPDFViewer *viewer, PDFDoc *doc, int page,
 			    GBool fullScreenA) {
-  int i;
 
-  viewers->erase(std::remove(viewers->begin(), viewers->end(), viewer), viewers->end());
+  std::remove(viewers->begin(), viewers->end(), viewer);
+  delete viewer;
 
   viewer = new XPDFViewer(this, doc, page, NULL, fullScreenA);
   if (!viewer->isOk()) {
@@ -295,12 +295,15 @@ void XPDFApp::close(XPDFViewer *viewer,
     if (closeLast) {
       quit();
     } else {
+      for (auto ptr : *viewers) { delete static_cast<XPDFViewer*>(ptr); }
       viewer->clear();
     }
   } else {
     for (i = 0; i < viewers->getLength(); ++i) {
       if (((XPDFViewer *)viewers->get(i)) == viewer) {
-        viewers->erase(viewers->begin() + i);
+        auto it = viewers->begin() + i;
+        delete static_cast<XPDFViewer*>(*it);
+        viewers->erase(it);
 	if (remoteAtom != None && remoteViewer == viewer) {
 	  remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1);
 	  remoteWin = remoteViewer->getWindow();
@@ -318,6 +321,7 @@ void XPDFApp::quit() {
   if (remoteAtom != None) {
     XSetSelectionOwner(display, remoteAtom, None, CurrentTime);
   }
+  for (auto ptr : *viewers) { delete static_cast<XPDFViewer*>(ptr); }
   viewers->clear();
 #if HAVE_XTAPPSETEXITFLAG
   XtAppSetExitFlag(appContext);

Reply to: