// RUN: %clang_analyze_cc1 \ // RUN: -analyzer-checker=security.PutenvStackArray \ // RUN: -verify %s #include "Inputs/system-header-simulator.h" void free(void *); void *malloc(size_t); int putenv(char *); int snprintf(char *, size_t, const char *, ...); int test_auto_var(const char *var) { char env[1024]; (void)snprintf(env, sizeof(env), "TEST=%s", var); return putenv(env); // expected-warning{{The 'putenv' function should not be called with arrays that have automatic storage}} } int test_static_var(const char *var) { static char env[1024]; (void)snprintf(env, sizeof(env), "TEST=%s", var); return putenv(env); // no-warning: static array is used } void test_heap_memory(const char *var) { const char *env_format = "TEST=%s"; const size_t len = strlen(var) + strlen(env_format); char *env = (char *)malloc(len); if (env == NULL) return; if (putenv(env) != 0) // no-warning: env was dynamically allocated. free(env); } typedef struct { int A; char Env[1024]; } Mem; int test_auto_var_struct() { Mem mem; return putenv(mem.Env); // expected-warning{{The 'putenv' function should not be called with}} } int test_auto_var_subarray() { char env[1024]; return putenv(env + 100); // expected-warning{{The 'putenv' function should not be called with}} } int f_test_auto_var_call(char *env) { return putenv(env); // expected-warning{{The 'putenv' function should not be called with}} } int test_auto_var_call() { char env[1024]; return f_test_auto_var_call(env); } int test_constant() { char *env = "TEST"; return putenv(env); // no-warning: data is not on the stack } extern char *ext_env; int test_extern() { return putenv(ext_env); // no-warning: extern storage class. } void test_auto_var_reset() { char env[] = "NAME=value"; putenv(env); // expected-warning{{The 'putenv' function should not be called with}} // ... (do something) // Even cases like this are likely a bug: // It looks like that if one string was passed to putenv, // it should not be deallocated at all, because when reading the // environment variable a pointer into this string is returned. // In this case, if another (or the same) thread reads variable "NAME" // at this point and does not copy the returned string, the data may // become invalid. putenv((char *)"NAME=anothervalue"); } void f_main(char *env) { putenv(env); // no warning: string allocated in stack of 'main' } int main(int argc, char **argv) { char env[] = "NAME=value"; putenv(env); // no warning: string allocated in stack of 'main' f_main(env); return 0; }