'In C, why is the pointer returned by getenv automatically reclaimed?
I use the following code to test the pointer returned by getenv, if not free, testing will cause a memory leak.
#include <stdio.h>
#include <stdlib.h>
void demo() {
const char *home = getenv("HOME");
printf("%s\n", home);
}
int main() {
demo();
return 0;
}
I use Valgrind to detect memory leaks:
$ gcc main.c -o main
$ valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./main
The result is as follows:
==134679== Memcheck, a memory error detector
==134679== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==134679== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==134679== Command: ./demo
==134679==
/home/aszswaz
==134679==
==134679== HEAP SUMMARY:
==134679== in use at exit: 0 bytes in 0 blocks
==134679== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==134679==
==134679== All heap blocks were freed -- no leaks are possible
==134679==
==134679== For lists of detected and suppressed errors, rerun with: -s
==134679== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
It shows that a piece of memory has been applied for and a piece of memory has been reclaimed. Why can the pointer obtained with getenv be automatically recycled?
If I add free((void *)home) to the code, will it affect the global environment variable?
Solution 1:[1]
The environment is initialized on the initial process stack, just above the parameters argc and argv to main().
Normally, as the environment life and parameters themselves is the whole program life, the common implementation consist in pushing the environment strings, the environment array, the main function parameter strings and the command line array in the stack, just before pushing the three variables (historically main() had a third parameter environ, that was passed also to main) For legacy code reasons, this environment pointer is still passed to main.
Just try the following program:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv, char **environ)
{
printf("argc = %d\n", argc);
printf("args:");
for (int i = 0; i < argc; i++) {
printf(" [%s]", argv[i]);
}
printf("\n\nEnvironment:\n");
for (char **p = environ; *p; p++) {
printf(" %s\n", *p);
}
return 0;
}
what getenv() returns is not statically allocated data, nor dynamically allocated data in the heap. It is stored in the stack (almost all POSIX-like operating systems solve this problem in the same way) just above main() parameters (you can check it with a debugger, to see where are exactly located the strings, I have already done too)
So your problem is not related to getenv(), which doesn't use malloc() to return dynamically allocated strings to you.
You'll need to look elsewhere for that memory Valgrind identifies as dynamic (It doesn't show any problem with it)
Think that valgrind identifies the memory you have allocated with malloc() (or any of its friends) and not free()d, and the report says at exit() there's no memory allocated. So getenv() doesn't allocate memory to give you the environment contents.
If you read on how the kernel initializes a process memory's initial stack, you will find very interesting things (listed from most deep in the stack to the top of it):
- There's some fixed machine code to properly return from kernel mode when there's a pending interrupt (interrupts are executed only when the kernel switches from kernel mode to user mode because they have to execute the handler code in user mode, and never in kernel mode, for obvious reasons)
- There's a legacy structure to save command line parameters and to allow the kernel to access command parameters for ps(1) command to work. This is no longer true, as it represents a security hole to put kernel info in user space, but the structure is still there, for legacy code to use. The parameters for a command are now in kernel space, and can only be modified by a special system call.
- There are all the strings associated to the received environment of the process.
- The array of pointer to the environment strings is also stored in the stack. This includes a final
NULLpointer to be able to identify the end of the array. - All the strings of the command line parameters are also stored there.
- The array of pointers (including the last
NULLpointer, which is not counted inargc) of the command line parameters. - The parameter
environwith a pointer to the array of environment strings. - The parameter
argvwith a pointer to the array of command line parameters. - The parameter
argcwith the number of command line parameters (this includes the program name, but excludes the lastNULLpointer)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
