xref: /llvm-project/clang/test/Analysis/putenv-stack-array.c (revision bc3baa93ce5142fcdc2dc5a7d27e26a32999116d)
13c230474SBalázs Kéri // RUN: %clang_analyze_cc1 \
2*bc3baa93SBalázs Kéri // RUN:  -analyzer-checker=security.PutenvStackArray \
33c230474SBalázs Kéri // RUN:  -verify %s
43c230474SBalázs Kéri 
53c230474SBalázs Kéri #include "Inputs/system-header-simulator.h"
63c230474SBalázs Kéri void free(void *);
73c230474SBalázs Kéri void *malloc(size_t);
83c230474SBalázs Kéri int putenv(char *);
93c230474SBalázs Kéri int snprintf(char *, size_t, const char *, ...);
103c230474SBalázs Kéri 
test_auto_var(const char * var)113c230474SBalázs Kéri int test_auto_var(const char *var) {
123c230474SBalázs Kéri   char env[1024];
133c230474SBalázs Kéri   (void)snprintf(env, sizeof(env), "TEST=%s", var);
143c230474SBalázs Kéri   return putenv(env); // expected-warning{{The 'putenv' function should not be called with arrays that have automatic storage}}
153c230474SBalázs Kéri }
163c230474SBalázs Kéri 
test_static_var(const char * var)173c230474SBalázs Kéri int test_static_var(const char *var) {
183c230474SBalázs Kéri   static char env[1024];
193c230474SBalázs Kéri   (void)snprintf(env, sizeof(env), "TEST=%s", var);
203c230474SBalázs Kéri   return putenv(env); // no-warning: static array is used
213c230474SBalázs Kéri }
223c230474SBalázs Kéri 
test_heap_memory(const char * var)233c230474SBalázs Kéri void test_heap_memory(const char *var) {
243c230474SBalázs Kéri   const char *env_format = "TEST=%s";
253c230474SBalázs Kéri   const size_t len = strlen(var) + strlen(env_format);
263c230474SBalázs Kéri   char *env = (char *)malloc(len);
273c230474SBalázs Kéri   if (env == NULL)
283c230474SBalázs Kéri     return;
293c230474SBalázs Kéri   if (putenv(env) != 0) // no-warning: env was dynamically allocated.
303c230474SBalázs Kéri     free(env);
313c230474SBalázs Kéri }
323c230474SBalázs Kéri 
333c230474SBalázs Kéri typedef struct {
343c230474SBalázs Kéri   int A;
353c230474SBalázs Kéri   char Env[1024];
363c230474SBalázs Kéri } Mem;
373c230474SBalázs Kéri 
test_auto_var_struct()383c230474SBalázs Kéri int test_auto_var_struct() {
393c230474SBalázs Kéri   Mem mem;
403c230474SBalázs Kéri   return putenv(mem.Env); // expected-warning{{The 'putenv' function should not be called with}}
413c230474SBalázs Kéri }
423c230474SBalázs Kéri 
test_auto_var_subarray()433c230474SBalázs Kéri int test_auto_var_subarray() {
443c230474SBalázs Kéri   char env[1024];
453c230474SBalázs Kéri   return putenv(env + 100); // expected-warning{{The 'putenv' function should not be called with}}
463c230474SBalázs Kéri }
473c230474SBalázs Kéri 
f_test_auto_var_call(char * env)4876b9d389SBalázs Kéri int f_test_auto_var_call(char *env) {
4976b9d389SBalázs Kéri   return putenv(env); // expected-warning{{The 'putenv' function should not be called with}}
5076b9d389SBalázs Kéri }
5176b9d389SBalázs Kéri 
test_auto_var_call()5276b9d389SBalázs Kéri int test_auto_var_call() {
5376b9d389SBalázs Kéri   char env[1024];
5476b9d389SBalázs Kéri   return f_test_auto_var_call(env);
5576b9d389SBalázs Kéri }
5676b9d389SBalázs Kéri 
test_constant()573c230474SBalázs Kéri int test_constant() {
583c230474SBalázs Kéri   char *env = "TEST";
593c230474SBalázs Kéri   return putenv(env); // no-warning: data is not on the stack
603c230474SBalázs Kéri }
613c230474SBalázs Kéri 
623c230474SBalázs Kéri extern char *ext_env;
test_extern()633c230474SBalázs Kéri int test_extern() {
643c230474SBalázs Kéri   return putenv(ext_env); // no-warning: extern storage class.
653c230474SBalázs Kéri }
663c230474SBalázs Kéri 
test_auto_var_reset()673c230474SBalázs Kéri void test_auto_var_reset() {
683c230474SBalázs Kéri   char env[] = "NAME=value";
693c230474SBalázs Kéri   putenv(env); // expected-warning{{The 'putenv' function should not be called with}}
703c230474SBalázs Kéri   // ... (do something)
713c230474SBalázs Kéri   // Even cases like this are likely a bug:
723c230474SBalázs Kéri   // It looks like that if one string was passed to putenv,
733c230474SBalázs Kéri   // it should not be deallocated at all, because when reading the
743c230474SBalázs Kéri   // environment variable a pointer into this string is returned.
753c230474SBalázs Kéri   // In this case, if another (or the same) thread reads variable "NAME"
763c230474SBalázs Kéri   // at this point and does not copy the returned string, the data may
773c230474SBalázs Kéri   // become invalid.
783c230474SBalázs Kéri   putenv((char *)"NAME=anothervalue");
793c230474SBalázs Kéri }
8076b9d389SBalázs Kéri 
f_main(char * env)8176b9d389SBalázs Kéri void f_main(char *env) {
8276b9d389SBalázs Kéri   putenv(env); // no warning: string allocated in stack of 'main'
8376b9d389SBalázs Kéri }
8476b9d389SBalázs Kéri 
main(int argc,char ** argv)8576b9d389SBalázs Kéri int main(int argc, char **argv) {
8676b9d389SBalázs Kéri   char env[] = "NAME=value";
8776b9d389SBalázs Kéri   putenv(env); // no warning: string allocated in stack of 'main'
8876b9d389SBalázs Kéri   f_main(env);
8976b9d389SBalázs Kéri   return 0;
9076b9d389SBalázs Kéri }
91