August 26, 2011

Win32 Env variable Pitfall of mismatching SetEnvironmentVariable and getEnv

Problem Description

Below article will give a brief introduction on environment variables and one strange (for a Unix programmer) behavior in WIN32. 

i.e getEnv() does not retrieve some environment variable but retrieve some in WIN32. But in Unix, all environment variables are retrieved.

Background

As quoted in wiki -

Environment variables are a set of dynamically named values that can affect the way running processes will behave. (http://en.wikipedia.org/wiki/Environment_variable )

In Unix environment, it is usual to set environment variables in 2 ways -

  • Type 1 setting : Use setenv command (generally collect these command into a environment sourcing file) and call it to set all the environment variables.
A point of note : The first option is executed from the shell command and all these environment variables are inherited by the process - it is more of a statically set environment variable. The second option is a more dynamic option which can be set during the process execution.

These variables, thus set can be accessed with getEnv (
http://pubs.opengroup.org/onlinepubs/009695399/functions/getenv.html) again available from stdlib.

Now, let us come to the crux of the problem.

In Unix, both the environment variables set by "Type 1" and "Type 2" can be accessed by getEnv function. When this code is ported in WIN32, it is strangely seen that statically set environment variables only will be accessible for getEnv function.

Any environment variable set using "Type2" setting (i.e dynamically set variable) using setEnvironmentVariable API (http://msdn.microsoft.com/en-us/library/ms686206%28v=vs.85%29.aspx) cannot be accessed by getEnv() function.

Example
Let us take a look at below code
Example 1
(In command line, setenv LIB="c:\\mylib;c:\\yourlib" is already done)-


1:  #include <stdlib.h>  
2:  #include <stdio.h>  
3:  int main( void )  
4:  {  
5:  char *libvar;  
6:  /* Get new value. */  
7:  libvar = getenv( "LIB" );  
8:  if( libvar != NULL )  
9:  printf( "New LIB variable is: %s\n", libvar );  
10:  return 0;  
11:  }  
In the above case, we will be able to get the output with detailed environment variable set from command line.

However, the below example has a start change in behavior 
Example 2
(In command line, LIB="c:\\mylib;c:\\yourlib" is not set from command line, but set in program)-


1:    #include <stdlib.h>  
2:    #include <stdio.h>  
3:    int main( void )  
4:    {  
5:      char *libvar;  
6:      SetEnvironmentVariable("LIB", "C:\WIN32");  
7:      /* Get new value. */  
8:      libvar = getenv( "LIB" );  
9:      if( libvar != NULL )  
10:       printf( "New LIB variable is: %s\n", libvar );  
11:     return 0;  
12:    } 
Here, the output would not be printed, owing to the fact that Type 2 setting env variables are not obtained by the getenv() API.

Root cause
The getEnv() function provides the output only from the internal cache (data structures) populated during the process start-up i.e the environment variable set in the shell. This is mentioned in the MSDN manual -
getenv operates only on the data structures accessible to the run-time library and not on the environment "segment" created for the process by the operating system
Thus in WIN32, getEnv() will not reflect the environment variable set during the execution of the program. Instead users need to use GetEnvironmentVariableA() API provided by MSDN.

Take Away's
  • Developers needs to be very discreet in using API's and also checking for differing "meanings" across different OS.
  • The manual should be read in detail and "in the corner" mentioning of the difference in behavior must be checked with a magnifying lens.
Regards,
Tech Unravel.
Supreme Debugging

No comments:

Post a Comment