summaryrefslogtreecommitdiffstats
path: root/Source/kwsys/testSystemTools.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2012-04-26 14:36:53 (GMT)
committerBrad King <brad.king@kitware.com>2012-04-27 12:13:52 (GMT)
commite48796b26b5b2b75401b48d21927b1d2912d4dca (patch)
tree6b088ca80eedcd8459ce8b36114956d85995563d /Source/kwsys/testSystemTools.cxx
parentb10c5cbb878af541f4ffa35a9e287c31743c6e97 (diff)
downloadCMake-e48796b26b5b2b75401b48d21927b1d2912d4dca.zip
CMake-e48796b26b5b2b75401b48d21927b1d2912d4dca.tar.gz
CMake-e48796b26b5b2b75401b48d21927b1d2912d4dca.tar.bz2
KWSys: Fix SystemTools environment memory handling (#13156)
The SystemTools::PutEnv function tries to provide the "putenv" API without leaking memory. However, the kwsysDeletingCharVector singleton frees memory that may still be referenced by the environment table, having been placed there by putenv. If any static destruction or processing by an external tool happens after the singleton is destroyed and accesses the environment it will read invalid memory. Replace use of putenv with setenv/unsetenv when available. The latter manage internal copies of the values passed instead of referencing the original memory. When setenv/unsetenv are not available use putenv with a singleton that removes its values from the environment before freeing their memory. This requires an "unputenv" implementation. On at least some platforms it must be written in terms of "putenv" because other APIs are not available and direct modification of the "environ" global is not safe (e.g. on Windows there is interaction with "wenviron"). Fortunately either putenv("A=") or putenv("A") will remove "A" from the environment on these platforms. On other platforms fall back to direct manipulation of "environ". Also add UnPutEnv to the API and add a test for the behavior of both.
Diffstat (limited to 'Source/kwsys/testSystemTools.cxx')
-rw-r--r--Source/kwsys/testSystemTools.cxx54
1 files changed, 54 insertions, 0 deletions
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index c0e74af..3ac0cb3 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -328,6 +328,58 @@ bool CheckStringOperations()
}
//----------------------------------------------------------------------------
+
+bool CheckPutEnv(const char* env, const char* name, const char* value)
+{
+ if(!kwsys::SystemTools::PutEnv(env))
+ {
+ kwsys_ios::cerr << "PutEnv(\"" << env
+ << "\") failed!" << kwsys_ios::endl;
+ return false;
+ }
+ const char* v = kwsys::SystemTools::GetEnv(name);
+ v = v? v : "(null)";
+ if(strcmp(v, value) != 0)
+ {
+ kwsys_ios::cerr << "GetEnv(\"" << name << "\") returned \""
+ << v << "\", not \"" << value << "\"!" << kwsys_ios::endl;
+ return false;
+ }
+ return true;
+}
+
+bool CheckUnPutEnv(const char* env, const char* name)
+{
+ if(!kwsys::SystemTools::UnPutEnv(env))
+ {
+ kwsys_ios::cerr << "UnPutEnv(\"" << env << "\") failed!"
+ << kwsys_ios::endl;
+ return false;
+ }
+ if(const char* v = kwsys::SystemTools::GetEnv(name))
+ {
+ kwsys_ios::cerr << "GetEnv(\"" << name << "\") returned \""
+ << v << "\", not (null)!" << kwsys_ios::endl;
+ return false;
+ }
+ return true;
+}
+
+bool CheckEnvironmentOperations()
+{
+ bool res = true;
+ res &= CheckPutEnv("A=B", "A", "B");
+ res &= CheckPutEnv("B=C", "B", "C");
+ res &= CheckPutEnv("C=D", "C", "D");
+ res &= CheckPutEnv("D=E", "D", "E");
+ res &= CheckUnPutEnv("A", "A");
+ res &= CheckUnPutEnv("B=", "B");
+ res &= CheckUnPutEnv("C=D", "C");
+ /* Leave "D=E" in environment so a memory checker can test for leaks. */
+ return res;
+}
+
+//----------------------------------------------------------------------------
int testSystemTools(int, char*[])
{
bool res = true;
@@ -356,5 +408,7 @@ int testSystemTools(int, char*[])
res &= CheckStringOperations();
+ res &= CheckEnvironmentOperations();
+
return res ? 0 : 1;
}