Bug 119782

Summary: memory leak in popt with int args
Product: Red Hat Enterprise Linux 4 Reporter: Peter Snelling <snelling>
Component: rpmAssignee: Panu Matilainen <pmatilai>
Status: CLOSED WONTFIX QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: 4.0CC: notting, redhat-bugzilla
Target Milestone: ---   
Target Release: ---   
Hardware: i386   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2012-06-20 13:19:07 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Peter Snelling 2004-04-02 05:19:41 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6)
Gecko/20040113

Description of problem:
Programs which use popt leak memory in "expandNextArg" when parsing
int options, after "poptFreeContext" is invoked.  Given the following
short program:

#include <popt.h>           // For Parsing command line options

int main(int argc, char *argv[] )
{
   int value = 0;
   int intOptions = (POPT_ARG_INT | POPT_ARGFLAG_ONEDASH);
   poptContext optCon; // Context for parsing command-line options

   struct poptOption optionsTable[] = {
      POPT_AUTOHELP
      { "value", 'v', intOptions, &value, 0, "Enter an int", 0 },
      { NULL, 0, 0, NULL, 0 }
   };

   optCon = poptGetContext(NULL, argc, (const char**) argv, 
      optionsTable, 0);
   poptSetOtherOptionHelp(optCon, "Shop Help\n");

   if (argc < 2) {
      poptPrintUsage(optCon, stderr, 0);
      return 1;
   }

   int c;
   while ((c = poptGetNextOpt(optCon))>=0) {
   }

   poptFreeContext(optCon);
   return 0;
}

Then use valgrind (http://valgrind.kde.org/) to check for memory leaks
in the above (named test):
>valgrind --leak-check=yes test -v=1
...
==7192== 2 bytes in 1 blocks are definitely lost in loss record 1 of 5
==7192==    at 0x40026C8C: realloc (vg_replace_malloc.c:310)
==7192==    by 0x403D3465: expandNextArg (in /usr/lib/libpopt.so.0.0.0)
==7192==    by 0x403D3A04: poptGetNextOpt (in /usr/lib/libpopt.so.0.0.0)
==7192==    by 0x804DAA0: main (test.cc:25)
...

If I rerun it with a longer int:
>valgrind --leak-check=yes test -v=12
It reports 3 bytes lost.  Similarly:
>valgrind --leak-check=yes test -v=123
reports 4 bytes lost.

Probably not too serious for normal users using popt once to parse
command line arguments.  Only possibly serious if someone was using
popt in a strange way, parsing things repeatedly...


Version-Release number of selected component (if applicable):
popt-1.7-1.06

How reproducible:
Always

Steps to Reproduce:
1.Take any popt program with int arguments which exits cleanly (see
simple example above)
2.Run it with valgrind to check for leaks
3.valgrind will report leaks the length of the argument supplied (+1)
    

Actual Results:  >valgrind --leak-check=yes test -v=1
...
==7192== 2 bytes in 1 blocks are definitely lost in loss record 1 of 5
==7192==    at 0x40026C8C: realloc (vg_replace_malloc.c:310)
==7192==    by 0x403D3465: expandNextArg (in /usr/lib/libpopt.so.0.0.0)
==7192==    by 0x403D3A04: poptGetNextOpt (in /usr/lib/libpopt.so.0.0.0)
==7192==    by 0x804DAA0: main (test.cc:25)
...

Expected Results:  No memory leaks expected

Additional info:

Standard RH8 on Dell i686 desktop.

Comment 1 Jeff Johnson 2004-04-02 12:50:35 UTC
All arguments returned to the caller are malloc'd.

It's up to the caller, not popt, to free.

Comment 2 Peter Snelling 2004-04-02 16:54:02 UTC
From the man page, it sounded like the application needs to call free
for poptParseArgvString and poptDupArgv, but I don't see how that's
the case for poptGetNextOpt.  It's doesn't return any char pointers,
and there are no extra parameters in this example to free.

Any chance you could point out where I'm supposed to free something in
the above example?  Or, for that matter in the example in the man page
which has the exact same memory leak if you use the option "--bps=1"?

Comment 3 Peter Snelling 2004-04-02 20:22:50 UTC
I grabbed the source for popt (1.7), and I'm now pretty confident that
this is a real bug.  It affects both string and int parms.  Even if
you free the string return, there is an additional string that isn't
deallocated.

Valgrind identified the realloc right at the end of "expandNextArg" as
the source of the leak, and that line is clearly commented:
   t = realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */

I'm not sure I understand this code well enough to be sure of how to
fix this, but playing around with it a bit, the pointer to it gets
null'd without being released in "poptResetContext", in this loop:
    while (con->os > con->optionStack) {
	cleanOSE(con->os--);
    }

Notice that this look does a "cleanOSE" on every "con-os", except for
the last one (where con->os == con->optionStack).  The change that
fixes this for me is adding a call to _free right after the loop:
    while (con->os > con->optionStack) {
	cleanOSE(con->os--);
    }
    _free(con->os->nextArg);


Comment 4 Bill Nottingham 2006-08-07 17:17:31 UTC
Red Hat Linux is no longer supported by Red Hat, Inc. If you are still
running Red Hat Linux, you are strongly advised to upgrade to a
current Fedora Core release or Red Hat Enterprise Linux or comparable.
Some information on which option may be right for you is available at
http://www.redhat.com/rhel/migrate/redhatlinux/.

Red Hat apologizes that these issues have not been resolved yet. We do
want to make sure that no important bugs slip through the cracks.
Please check if this issue is still present in a current Fedora Core
release. If so, please change the product and version to match, and
check the box indicating that the requested information has been
provided. Note that any bug still open against Red Hat Linux on will be
closed as 'CANTFIX' on September 30, 2006. Thanks again for your help.


Comment 5 Peter Snelling 2006-08-21 14:34:57 UTC
Yes, this bug still exists in current Fedora Core and RHEL releases.  I've
modified the "product" to be RHEL 4.1, which is what I'm currently running.  The
simplest way to verify this bug is to just use "rpm", which also has this bug,
because it uses popt to parse it's parameters.  So even a command as simple as
"rpm --help" has a small memory leak, which can be seen using valgrind:

$ valgrind --tool=memcheck --leak-check=yes rpm --help
...
==5326== LEAK SUMMARY:
==5326==    definitely lost: 47 bytes in 1 blocks.
==5326==    possibly lost:   0 bytes in 0 blocks.
==5326==    still reachable: 9924 bytes in 141 blocks.
==5326==         suppressed: 200 bytes in 1 blocks.

Comment 6 Jeff Johnson 2007-01-17 21:30:51 UTC
The 1 block leak in popthelp.c has been fixed in rpm/popt cvs, will be in popt-1.10.8-0.11 when built.

Meanwhile, there are other 1 time malloc's of data that cannot be free'd without changing popt's ABI.

UPSTREAM or WONTFIX, your call.

Comment 7 Robert Scheck 2007-08-23 23:10:28 UTC
This problem is IMHO solved in Rawhide by popt-1.12-3. If not, please open a 
separate bug for Fedora to get this split of from RHEL.

Comment 8 Jiri Pallich 2012-06-20 13:19:07 UTC
Thank you for submitting this issue for consideration in Red Hat Enterprise Linux. The release for which you requested us to review is now End of Life. 
Please See https://access.redhat.com/support/policy/updates/errata/

If you would like Red Hat to re-consider your feature request for an active release, please re-open the request via appropriate support channels and provide additional supporting details about the importance of this issue.