What does one do about buggy POSIX APIs which leak memory?
Disclaimer: This is for an assignment, but the assignment doesn't require that we remove memory leaks. I'm just anal retentive on this one.
Consider the following method:
//Prints the current user ID to the console.
void PrintUserId()
{
std::cout << "Current User Id: " << cuserid(0) << std::endl;
}
The docs for cuserid
state:
If string is not a null pointer, it should be an array that c开发者_开发百科an hold at least L_cuserid characters; the string is returned in this array. Otherwise, a pointer to a string in a static area is returned.
But at least on my system, the memory in question doesn't appear to be statically allocated (or at least there are bugs...):
(Valgrind Output) ==4488== 160 (40 direct, 120 indirect) bytes in 1 blocks are definitely lost in loss record 11 of 11 ==4488== at 0x4025BD3: malloc (vg_replace_malloc.c:236) ==4488== by 0x4247A9C: nss_parse_service_list (nsswitch.c:622) ==4488== by 0x4248216: __nss_database_lookup (nsswitch.c:164) ==4488== by 0x402DEAB: ??? ==4488== by 0x402EB6C: ??? ==4488== by 0x41FE41C: getpwuid_r@@GLIBC_2.1.2 (getXXbyYY_r.c:253) ==4488== by 0x41A2785: cuserid (cuserid.c:38) ==4488== by 0x80495A3: PrintUserId() (in /home/bro4/Assignment1.bin) ==4488== by 0x8049A11: ParentProcess() (in /home/bro4/Assignment1.bin) ==4488== by 0x8049B53: main (in /home/bro4/Assignment1.bin)
Am I just stuck on this?
It might be a false positive. cuserid
or its dependencies could allocate a buffer on its first call, then free or reuse it on the next call. Try calling it in a loop; do you end up with multiple leak reports?
In your case, the allocation is done by nss_parse_service_list, part of the nsswitch internal API that handles switching between various authentication providers (unix /etc/passwd, LDAP, etc). This function is called by __nss_database_lookup, which calls it as part of a one-time initialization process. So this isn't really a leak; it's memory that's allocated to hold the results of parsing a config file (or, in this case, a default config). It won't be freed, because it's needed until the program terminates; but neither will it grow.
Since this is a false positive, you may want to suppress these reports in valgrind. It's not uncommon to see valgrind warnings from system libraries - there are one-time allocations like this in various library routines, as well as low-level routines doing things that look to valgrind like a potential problem, when in fact they're very carefully controlled and correct. It's best to suppress them - after, of course, checking that they're not really your fault, of course!
The Single UNIX ® Specification, Version 2 does not guarantee that static data will be used, it says it "may be static".
If s is a null pointer, this representation is generated in an area that may be static (and thus overwritten by subsequent calls to cuserid()), the address of which is returned.
The linux man page for cuserid() has two provocative statements:
The cuserid function was included in the 1988 version of POSIX, but removed from the 1990 version.
and
Nobody knows precisely what cuserid() does - avoid it in portable programs - avoid it altogether - use getpwuid(geteuid()) instead, if that is what you meant. DO NOT USE cuserid().
Assuming the statement that this function was removed from POSIX more than 20 years ago is accurate, I would say "DO NOT USE cuserid()" is pretty good advice. Failing that, pass a pointer to cuserid and manage the memory yourself.
精彩评论