Question

C standard says that:

The getenv function returns a pointer to a string associated with the matched list member. The string pointed to shall not be modified by the program, but may be overwritten by a subsequent call to the getenv function.

As I understand, getenv implementation in glibc(I used ver. 2.17) returns element from global variable called char **environ. Every subsequent call to the getenv function still returns one of the elements from this array(or null when such env variable doesn't exist) without altering any of previously returned values.

Is any alternation of content of previously returned pointer by getenv function possible by subsequent call to the getenv function when using glibc? If yes, when?

Was it helpful?

Solution

This is really just a bug in the standards. Even C11 keeps language that allows the buffer to be overwritten, but at the same time, it does not permit data races with other calls to getenv, only with (implementation-defined) functions which modify the environment, so permitting this overwriting to take place seems contradictory.

On all real-world implementations, including glibc, getenv returns the pointer to the copy of the string in the internal representation of the environment, and will never be invalidated except possibly if you call functions which modify the environment.

OTHER TIPS

If I correctly understood, getenv can theoretically be implemented by copying the string into it's internal static buffer and returning a pointer to it instead of giving a pointer to environ member. If so, the string will be changed by each getenv call.

Perhaps a demo will help:

char *getenv(const char *var){
    int i=0, len=strlen(var);
    if (!environ||!*var||strchr(var,'='))
        return NULL;
    while ( environ[i] && (environ[i][len] != '=' || strncmp(var,environ[i],len)) )
        i++;
    return (environ[i])? environ[i]+len+1 : NULL;
}

Each call will get an appropriate pointer to the global extern 2d array environ, which is why the program should not modify it, because it would actually modify the environ variable; however a subsequent call to getenv may get the value in a different position (if setenv or putenv has changed it)

Notice that you are getting a pointer to the middle of a string. Think of what would happen if you changed it. Then at any given point the **environ may change so that address is pointing to some other variable (or junk) ... if you need to use that string long term, you should copy it just to be safe (especially in threaded environments)

What it is saying is that you can do mycharptr=getenv("myvar"); as often as you wish, that is safe, but don't do mycharptr=getenv("myvar");mycharptr[0]='\0'; ... mycharptr=getenv("myvar");... or you may get unexpected results.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top