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