| // 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; | |
| } |