Bug 1007614

Summary: memory leak in infpy_read_memory()
Product: Red Hat Enterprise Linux 6 Reporter: Laszlo Ersek <lersek>
Component: gdbAssignee: Sergio Durigan Junior <sergiodj>
Status: CLOSED ERRATA QA Contact: qe-baseos-tools-bugs
Severity: high Docs Contact:
Priority: medium    
Version: 6.4CC: jan.kratochvil, ltroan, mcermak, mfranc, patrickm
Target Milestone: rc   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: gdb-7.2-67.el6 Doc Type: Bug Fix
Doc Text:
Cause: A specific function in the Python support on GDB leaked the reference to a buffer that was read from the program being debugged. Consequence: In a memory-intensive scenario, GDB would leak a big amount of memory. Fix: GDB now correctly frees the memory acquired. Result: GDB does not overconsume memory when using Python scriptting on memory-intensive scenarios.
Story Points: ---
Clone Of: Environment:
Last Closed: 2014-10-14 07:28:03 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 826266, 1020419, 1056252, 1092931    

Description Laszlo Ersek 2013-09-13 00:00:08 UTC
*** Description of problem:

The infpy_read_memory() function [gdb/python/py-inferior.c] leaks memory: it leaks a reference to the buffer that is read from the debuggee and is passed to the Python script. When the value goes out of scope or becomes otherwise unreferenced in the Python script, it should be freed, but due to the leaked reference, it is never released.

This is a problem for memory-intensive python scripts. For a real example, see blocked blug 826266; my Python script there wants to read several gigabytes from a coredump. I'll paste a simple reproducer below.

*** Version-Release number of selected component (if applicable):
gdb-7.2-60.el6_4.1.x86_64 (RHEL-6.4.z)

*** How reproducible:
100%

*** Steps to Reproduce:

1. Save the following python code in the file "testprog.py":
--------[snip]--------
class HelloWorld (gdb.Command):
    """Greet the whole world."""

    def __init__ (self):
        super (HelloWorld, self).__init__ ("hello-world",
                                           gdb.COMMAND_OBSCURE)

    def invoke (self, arg, from_tty):
        px = gdb.parse_and_eval("px")
        core = gdb.inferiors()[0]
        for i in range(256 * 1024):
            chunk = core.read_memory(px, 4096)
        print "Hello, World!"

HelloWorld ()
--------[snip]--------

2. Save the following C test program in the file "testprog.c":
--------[snip]--------
#include <unistd.h>

static struct x {
  char unsigned u[4096];
} x, *px = &x;

int
main(void)
{
  pause();
  return 0;
}
--------[snip]--------

3. build it:
    gcc -g3 -o testprog testprog.c

4. Enable coredumps:
    ulimit -c unlimited

5. Disable abrt or at least reconfigure /proc/sys/kernel/core_pattern so that the coredump is written to a local file and not piped to abrt.

6. start the program:
    ./testprog

7. Send SIGQUIT to the program, pressing Ctrl-\, eliciting a coredump.

8. Open the core with gdb:
    gdb ./testprog core.PID

9. Load the python script:
    (gdb) source testprog.py

10. From another terminal, check the initial memory usage of gdb:
    ps -o pid,rsz,vsz,cmd -C gdb

11. Run the python script:
    (gdb) hello-world

12. From another terminal, verify the memory usage of gdb after the 1st run:
    ps -o pid,rsz,vsz,cmd -C gdb

13. Run the python script again:
    (gdb) hello-world

14. From another terminal, verify the memory usage of gdb after the 2nd run:
    ps -o pid,rsz,vsz,cmd -C gdb

*** Actual results:
From step 10 to step 12, 1 GB virtual memory is leaked.
From step 12 to step 14, another GB of virtual memory is leaked.

*** Expected results:
Memory footprint stays reasonably stable.

*** Additional info:
Apparently, this bug has been fixed by upstream gdb git commit

commit 655e820cf9a039ee55325d9e1f8423796d592b4b
Author: Tom Tromey <tromey>
Date:   Wed Mar 28 17:38:07 2012 +0000

        * python/py-inferior.c (infpy_read_memory): Remove cleanups and
        explicitly free 'buffer' on exit paths.  Decref 'membuf_object'
        before returning.

The second part looks relevant here (ie. the Py_DECREF (membuf_obj) call before returning.)

The bug seems to be present in gdb-7.2-64.el6 too (ie. the current RHEL-6.5 development version).

Comment 1 Laszlo Ersek 2013-09-13 00:10:59 UTC
Inheriting Severity from blocked bug 826266.

Comment 3 Sergio Durigan Junior 2014-04-09 22:58:05 UTC
FYI, the commit has changed to:

commit cc0265cdda9dc7e8665e8bfcf5b4477489daf27c

Because GDB+Binutils have recently migrated to git and rewritten all of the repository's history.  I am working on this bug now.

Comment 7 errata-xmlrpc 2014-10-14 07:28:03 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

http://rhn.redhat.com/errata/RHBA-2014-1534.html