The POSIX system call putenv
states that the allocated memory string cannot be freed by the caller after the call to putenv
. Therefore, you cannot call putenv
with an automatic variable.
Example:
#include <cstdlib>
#include <cstring>
#include <unistd.h>
int main()
{
char envVar[] = "MYVAR=Value";
// putenv(envVar); //ERROR!
char *memory = static_cast<char*>(std::malloc(sizeof(envVar)));
std::strcpy(memory, envVar);
putenv(memory); //OK!
}
My question at this point is ... how is the environment variable memory free
'd? Does one need to maintain their on separate storage and constantly remove things from the environment? I.e.
#include <cstdlib>
#include <cstring>
#include <string>
#include <map>
static std::map<std::string, char*> environmentBlock;
static struct EnvironmentBlockFreer
{
~EnvironmentBlockFreer()
{
for(std::map<std::string, char*>::iterator it = environmentBlock.begin()
it != environmentBlock.end(); ++it)
{
putenv(it->first.c_str()); //Remove entry from the environment
std::free(static_cast<void *>(it->second)); //Nuke the memory
}
}
} EnvironmentBlockFreer_ENTRY;
int main()
{
char envVar[] = "MYVAR=Value";
char *memory = static_cast<char*>(std::malloc(sizeof(envVar)));
std::strcpy(memory, envVar);
putenv(memory); //OK!
environmentBlock.insert(std::pair<std::string, char*>(
"MYVAR", memory)); //Remember the values for later!
}
EDIT: It does look like I need to track this myself, at least according to Valgrind:
/* This program: */
#include <stdlib.h>
#include <string.h>
int main()
{
char str[] = "MYVAR=Example";
char *mem = malloc(sizeof(str));
strcpy(mem, str);
putenv(mem);
}
/* Produced output:
==4219== Memcheck, a memory error detector
==4219== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==4219== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==4219== Command: ./a.out
==4219==
==4219==
==4219== HEAP SUMMARY:
==4219== in use at exit: 14 bytes in 1 blocks
==4219== total heap usage: 2 allocs, 1 frees, 194 bytes allocated
==4219==
==4219== LEAK SUMMARY:
==4219== definitely lost: 14 bytes in 1 blocks
==4219== indirectly lost: 0 bytes in 0 blocks
==4219== possibly lost: 0 bytes in 0 blocks
==4219== still reachable: 0 bytes in 0 blocks
==4219== suppressed: 0 bytes in 0 blocks
==4219== Rerun with --leak-check=full to see details of leaked memory
==4219==
==4219== For counts of detected and suppressed errors, rerun with: -v
==4219== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 8)
*/
Don't use putenv()
if you are worried about the memory leaking.
That's why POSIX provides setenv()
and unsetenv()
as well - those take control of the memory and manage it.
Quoting the putenv()
manual page (URL above):
The
putenv()
function shall use the string argument to set environment variable values. The string argument should point to a string of the form "name= value
". Theputenv()
function shall make the value of the environment variable name equal to value by altering an existing variable or creating a new one. In either case, the string pointed to by string shall become part of the environment, so altering the string shall change the environment. The space used by string is no longer used once a new string which defines name is passed toputenv()
.
No, you don't need to do that manually. Memory for your environment is freed by the OS (as part of your process memory) when your process exits.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With