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: