xref: /llvm-project/clang/test/Analysis/putenv-stack-array.c (revision bc3baa93ce5142fcdc2dc5a7d27e26a32999116d)
1 // RUN: %clang_analyze_cc1 \
2 // RUN:  -analyzer-checker=security.PutenvStackArray \
3 // RUN:  -verify %s
4 
5 #include "Inputs/system-header-simulator.h"
6 void free(void *);
7 void *malloc(size_t);
8 int putenv(char *);
9 int snprintf(char *, size_t, const char *, ...);
10 
test_auto_var(const char * var)11 int test_auto_var(const char *var) {
12   char env[1024];
13   (void)snprintf(env, sizeof(env), "TEST=%s", var);
14   return putenv(env); // expected-warning{{The 'putenv' function should not be called with arrays that have automatic storage}}
15 }
16 
test_static_var(const char * var)17 int test_static_var(const char *var) {
18   static char env[1024];
19   (void)snprintf(env, sizeof(env), "TEST=%s", var);
20   return putenv(env); // no-warning: static array is used
21 }
22 
test_heap_memory(const char * var)23 void test_heap_memory(const char *var) {
24   const char *env_format = "TEST=%s";
25   const size_t len = strlen(var) + strlen(env_format);
26   char *env = (char *)malloc(len);
27   if (env == NULL)
28     return;
29   if (putenv(env) != 0) // no-warning: env was dynamically allocated.
30     free(env);
31 }
32 
33 typedef struct {
34   int A;
35   char Env[1024];
36 } Mem;
37 
test_auto_var_struct()38 int test_auto_var_struct() {
39   Mem mem;
40   return putenv(mem.Env); // expected-warning{{The 'putenv' function should not be called with}}
41 }
42 
test_auto_var_subarray()43 int test_auto_var_subarray() {
44   char env[1024];
45   return putenv(env + 100); // expected-warning{{The 'putenv' function should not be called with}}
46 }
47 
f_test_auto_var_call(char * env)48 int f_test_auto_var_call(char *env) {
49   return putenv(env); // expected-warning{{The 'putenv' function should not be called with}}
50 }
51 
test_auto_var_call()52 int test_auto_var_call() {
53   char env[1024];
54   return f_test_auto_var_call(env);
55 }
56 
test_constant()57 int test_constant() {
58   char *env = "TEST";
59   return putenv(env); // no-warning: data is not on the stack
60 }
61 
62 extern char *ext_env;
test_extern()63 int test_extern() {
64   return putenv(ext_env); // no-warning: extern storage class.
65 }
66 
test_auto_var_reset()67 void test_auto_var_reset() {
68   char env[] = "NAME=value";
69   putenv(env); // expected-warning{{The 'putenv' function should not be called with}}
70   // ... (do something)
71   // Even cases like this are likely a bug:
72   // It looks like that if one string was passed to putenv,
73   // it should not be deallocated at all, because when reading the
74   // environment variable a pointer into this string is returned.
75   // In this case, if another (or the same) thread reads variable "NAME"
76   // at this point and does not copy the returned string, the data may
77   // become invalid.
78   putenv((char *)"NAME=anothervalue");
79 }
80 
f_main(char * env)81 void f_main(char *env) {
82   putenv(env); // no warning: string allocated in stack of 'main'
83 }
84 
main(int argc,char ** argv)85 int main(int argc, char **argv) {
86   char env[] = "NAME=value";
87   putenv(env); // no warning: string allocated in stack of 'main'
88   f_main(env);
89   return 0;
90 }
91