Bug 18519

Summary: memory leak in putenv
Product: Base System Reporter: Abdul Khan <khana>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 1.0-RELEASE   
Hardware: Any   
OS: Any   

Description Abdul Khan 2000-05-12 21:10:01 UTC
 sorry about the last one.. i was a little too quick on the draw :)
 
 this one should work:
 
 #include <iostream.h>
 #include <stdlib.h>
 
 extern char** environ;
 
 class Exception
 {
 	public:
 		virtual char* getErrorMessage() = 0;
 };
 
 class NullPointerException : public Exception
 {
 	public:
 		virtual char* getErrorMessage() 
 		{
 			return "Null Pointer Exception";
 		};	
 };
 
 class EnvironmentVariable 
 {
 	public:
 
 		EnvironmentVariable(char* variable_name) 
 		{ 
 			if (!variable_name) throw NullPointerException();
 			else name = strdup(variable_name); 
 			setEnvironmentVariableOneTime=false;
 		};
 
 		void setEnv(char* value)
 		{
 			int i = 0, j = 0;
 			while (environ[i])
 			{
 				while (name[j] && environ[i][j] &&
 							name[j] == environ[i][j]) j++;
 				if (environ[i][j] == '=' && !name[j]) 
 				{
 					if (setEnvironmentVariableOneTime)
 					{
 						environ[i] = (char*) realloc (environ[i],
 												sizeof(char)*
 												(strlen (value) + strlen (name) + 1 + 1));
 						sprintf(environ[i], "%s=%s", name, value);
 					}
 					else
 					{
 					int k = i;
 					while (environ[k]) k++;
 					char** new_environ = (char**) malloc(sizeof(char*)*(k+1));
 					for(int n=0;n<k;n++)
 					{
 						new_environ[n] = (char*)
 									malloc(sizeof(char)*(strlen(environ[n])+1));
 						strcpy(new_environ[n], environ[n]);
 					}
 					new_environ[n]=NULL;					
 					new_environ[i] = (char*) realloc (new_environ[i],
 								sizeof(char)*
 								(strlen (value) + strlen (name) + 1 + 1));
 					sprintf(new_environ[i], "%s=%s", name, value);
 					clearenv();
 					environ=new_environ;
 					}
 					break;
 				}
 				i++;
 			}
 			if (!environ[i]) 
 			{
 				char* new_env = 
 						(char*) malloc(sizeof(char)*
 								(strlen (value) + strlen (name) + 1 + 1));
 				sprintf(new_env, "%s=%s", name, value);
 				putenv(new_env);
 			}
 			else
 			{
 				setEnvironmentVariableOneTime = true;
 			}				
 		}
 
 		void setEnvWithLeak(char* value)
 		{
 			char* env = (char *) malloc (sizeof(char)*
 								(strlen (value) + strlen (name) + 1 + 1));
 			sprintf(env, "%s=%s", name, value);
 			putenv(env);
 		}
 		char* getEnv() {return getenv(name);};
 		virtual ~EnvironmentVariable() { free(name);};
 	private:
 		char* name;
 		static bool setEnvironmentVariableOneTime;
 	};
 
 
 int main(int argc, char** argv)
 {
 char * str = 0;
 try 
 {
 	if (argc < 4) 
 	{
 		cout << "Usage: env_mem_leak <environment variable name> ";
 		cout << "<iterations> <bifurcations>" << endl;
 		cout << "Where iterations is the number of times to set the variable ";
 		cout << "and bifrucations is the number of changes in the length of "; 
 		cout << "the string that is put into the environment variable" << endl;
 	}
 	
 	EnvironmentVariable myenv(argv[1]);
 	int iterations = atoi(argv[2]);
 	int bifurcations = atoi(argv[3]);
 	str = (char*) malloc(sizeof(char)*(bifurcations+1));
 
 	for (int i=0; i < iterations; i++)
 	{
 		memset(str, 'A', i % bifurcations);
 		str[(i % bifurcations) + 1]='\0';
 		myenv.setEnv(str);
 			////switch these to see the memory leak problem in purify!!!!!!!!!!
 		//myenv.setEnvWithLeak(str);
 		cout << myenv.getEnv() << endl;
 
 	}
 
 } 
 catch(Exception& e) 
 {
 	cout << endl << e.getErrorMessage() << endl;
 };
 if (str) free(str);
 return 0;
 }
Comment 1 Jeroen Ruigrok van der Werven freebsd_committer freebsd_triage 2000-05-13 11:59:13 UTC
Responsible Changed
From-To: gnats-admin->freebsd-bugs

Misfiled. 

Futhermore, see PR 18515 
Comment 2 Poul-Henning Kamp freebsd_committer freebsd_triage 2001-06-02 10:00:28 UTC
State Changed
From-To: open->closed

Due to bad API design, putenv(3) is a memory leaker. 
It's even documented in the man-page.