diff --git a/libc/src/env.cpp b/libc/src/env.cpp index 57b8fb34..25812a96 100644 --- a/libc/src/env.cpp +++ b/libc/src/env.cpp @@ -94,12 +94,30 @@ static void _update_env() environ = g_dynamic_env.data(); } +// Check if a user has modified environ, in which case we should reset env_is_dynamic and free our buffers. +static void _check_dynamic_env() +{ + if (!env_is_dynamic) return; + + env_is_dynamic = environ == g_dynamic_env.data(); + + if (!env_is_dynamic) + { + for (auto element : g_dynamic_env) + { + if (element) free(element); + } + } +} + extern "C" { char** environ = nullptr; int clearenv() { + _check_dynamic_env(); + if (env_is_dynamic) { for (auto element : g_dynamic_env) @@ -127,6 +145,8 @@ extern "C" auto index = _findenv(key, nullptr); if (index < 0) return 0; + _check_dynamic_env(); + if (!env_is_dynamic) { if (_move_env() < 0) return -1; @@ -149,6 +169,8 @@ extern "C" auto index = _findenv(key, nullptr); if (index >= 0 && !overwrite) return 0; + _check_dynamic_env(); + if (!env_is_dynamic) { if (_move_env() < 0) return -1; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7749593c..d090faea 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,6 +21,7 @@ luna_test(libluna/TestHashTable.cpp TestHashTable) luna_test(libluna/TestCPath.cpp TestCPath) luna_test(libc/TestScanf.cpp TestScanf) luna_test(libc/TestString.cpp TestString) +luna_test(libc/TestEnv.cpp TestEnv) luna_app(run-tests.cpp run-tests) endif() diff --git a/tests/libc/TestEnv.cpp b/tests/libc/TestEnv.cpp new file mode 100644 index 00000000..b7f076a5 --- /dev/null +++ b/tests/libc/TestEnv.cpp @@ -0,0 +1,85 @@ +#include +#include +#include + +extern char** environ; + +TestResult test_setenv_then_getenv() +{ + clearenv(); + + validate(setenv("sample", "value", 1) == 0); + + char* value = getenv("sample"); + validate(value); + validate(!strcmp(value, "value")); + + test_success; +} + +TestResult test_setenv_dont_overwrite() +{ + clearenv(); + + validate(setenv("sample", "value", 1) == 0); + + char* value = getenv("sample"); + validate(value); + validate(!strcmp(value, "value")); + + validate(setenv("sample", "other_value", 0) == 0); + + value = getenv("sample"); + validate(value); + validate(!strcmp(value, "value")); + + test_success; +} + +TestResult test_unsetenv() +{ + clearenv(); + + validate(setenv("sample", "value", 1) == 0); + + char* value = getenv("sample"); + validate(value); + validate(!strcmp(value, "value")); + + validate(unsetenv("sample") == 0); + + value = getenv("sample"); + validate(!value); + + test_success; +} + +TestResult test_setenv_before_and_after_manual_environ_modification() +{ + clearenv(); + + validate(setenv("sample", "value", 1) == 0); + + char* list[] = { "hello=world", NULL }; + environ = list; + + validate(setenv("other", "value", 1) == 0); + + char* value = getenv("hello"); + validate(value); + validate(!strcmp(value, "world")); + + test_success; +} + +Result test_main() +{ + test_prelude; + + run_test(test_setenv_then_getenv); + run_test(test_setenv_dont_overwrite); + run_test(test_unsetenv); + run_test(test_setenv_before_and_after_manual_environ_modification); + + return {}; +}