| // RUN: %clang_analyze_cc1 \ |
| // RUN: -analyzer-checker=alpha.security.cert.env.InvalidPtr\ |
| // RUN: -analyzer-output=text -verify -Wno-unused %s |
| |
| #include "../Inputs/system-header-simulator.h" |
| char *getenv(const char *name); |
| char *setlocale(int category, const char *locale); |
| char *strerror(int errnum); |
| |
| typedef struct { |
| char * field; |
| } lconv; |
| lconv *localeconv(void); |
| |
| typedef struct { |
| } tm; |
| char *asctime(const tm *timeptr); |
| |
| int strcmp(const char*, const char*); |
| extern void foo(char *e); |
| extern char* bar(void); |
| |
| |
| void getenv_test1(void) { |
| char *p; |
| |
| p = getenv("VAR"); |
| *p; // no-warning |
| |
| p = getenv("VAR2"); |
| *p; // no-warning, getenv result was assigned to the same pointer |
| } |
| |
| void getenv_test2(void) { |
| char *p, *p2; |
| |
| p = getenv("VAR"); |
| // expected-note@-1{{previous function call was here}} |
| *p; // no-warning |
| |
| p2 = getenv("VAR2"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void getenv_test3(void) { |
| char *p, *p2, *p3; |
| |
| p = getenv("VAR"); |
| *p; // no-warning |
| |
| p = getenv("VAR2"); |
| // expected-note@-1{{previous function call was here}} |
| p2 = getenv("VAR2"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| |
| p3 = getenv("VAR3"); |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void getenv_test4(void) { |
| char *p, *p2, *p3; |
| |
| p = getenv("VAR"); |
| // expected-note@-1{{previous function call was here}} |
| p2 = getenv("VAR2"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| p3 = getenv("VAR3"); |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void getenv_test5(void) { |
| char *p, *p2, *p3; |
| |
| p = getenv("VAR"); |
| p2 = getenv("VAR2"); |
| // expected-note@-1{{previous function call was here}} |
| p3 = getenv("VAR3"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| |
| *p2; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void getenv_test6(void) { |
| char *p, *p2; |
| p = getenv("VAR"); |
| *p; // no-warning |
| |
| p = getenv("VAR2"); |
| // expected-note@-1{{previous function call was here}} |
| *p; // no-warning |
| |
| p2 = getenv("VAR3"); |
| // expected-note@-1{{previous function call was here}} |
| // expected-note@-2{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| |
| *p2; // no-warning |
| |
| p = getenv("VAR4"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| |
| *p; // no-warning |
| *p2; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void getenv_test7(void) { |
| char *p, *p2; |
| p = getenv("VAR"); |
| // expected-note@-1{{previous function call was here}} |
| *p; // no-warning |
| |
| p2 = getenv("VAR2"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| |
| foo(p); |
| // expected-warning@-1{{use of invalidated pointer 'p' in a function call}} |
| // expected-note@-2{{use of invalidated pointer 'p' in a function call}} |
| } |
| |
| void getenv_test8(void) { |
| static const char *array[] = { |
| 0, |
| 0, |
| "/var/tmp", |
| "/usr/tmp", |
| "/tmp", |
| "." |
| }; |
| |
| if( !array[0] ) |
| // expected-note@-1{{Taking true branch}} |
| array[0] = getenv("TEMPDIR"); |
| // expected-note@-1{{previous function call was here}} |
| |
| if( !array[1] ) |
| // expected-note@-1{{Taking true branch}} |
| array[1] = getenv("TMPDIR"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| |
| *array[0]; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void getenv_test9(void) { |
| char *p, *p2; |
| p = getenv("something"); |
| p = bar(); |
| p2 = getenv("something"); |
| *p; // no-warning: p does not point to getenv anymore |
| } |
| |
| void getenv_test10(void) { |
| strcmp(getenv("VAR1"), getenv("VAR2")); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| // expected-note@-2{{previous function call was here}} |
| // expected-warning@-3{{use of invalidated pointer 'getenv("VAR1")' in a function call}} |
| // expected-note@-4{{use of invalidated pointer 'getenv("VAR1")' in a function call}} |
| } |
| |
| void dereference_pointer(char* a) { |
| *a; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void getenv_test11(void) { |
| char *p = getenv("VAR"); |
| // expected-note@-1{{previous function call was here}} |
| |
| char *pp = getenv("VAR2"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| |
| dereference_pointer(p); |
| // expected-note@-1{{Calling 'dereference_pointer'}} |
| } |
| |
| void getenv_test12(int flag1, int flag2) { |
| char *p = getenv("VAR"); |
| // expected-note@-1{{previous function call was here}} |
| |
| if (flag1) { |
| // expected-note@-1{{Assuming 'flag1' is not equal to 0}} |
| // expected-note@-2{{Taking true branch}} |
| char *pp = getenv("VAR2"); |
| // expected-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}} |
| } |
| |
| if (flag2) { |
| // expected-note@-1{{Assuming 'flag2' is not equal to 0}} |
| // expected-note@-2{{Taking true branch}} |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| } |
| |
| void setlocale_test1(void) { |
| char *p, *p2; |
| p = setlocale(0, "VAR"); |
| *p; // no-warning |
| |
| p = setlocale(0, "VAR2"); |
| // expected-note@-1{{previous function call was here}} |
| *p; // no-warning |
| |
| p2 = setlocale(0, "VAR3"); |
| // expected-note@-1{{'setlocale' call may invalidate the result of the previous 'setlocale'}} |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void setlocale_test2(int flag) { |
| char *p, *p2; |
| p = setlocale(0, "VAR"); |
| *p; // no-warning |
| |
| p = setlocale(0, "VAR2"); |
| // expected-note@-1{{previous function call was here}} |
| *p; // no-warning |
| |
| if (flag) { |
| // expected-note@-1{{Assuming 'flag' is not equal to 0}} |
| // expected-note@-2{{Taking true branch}} |
| p2 = setlocale(0, "VAR3"); |
| // expected-note@-1{{'setlocale' call may invalidate the result of the previous 'setlocale'}} |
| } |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void strerror_test1(void) { |
| char *p, *p2; |
| |
| p = strerror(0); |
| *p; // no-warning |
| |
| p = strerror(1); |
| // expected-note@-1{{previous function call was here}} |
| *p; // no-warning |
| |
| p2 = strerror(2); |
| // expected-note@-1{{'strerror' call may invalidate the result of the previous 'strerror'}} |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void strerror_test2(int errno) { |
| char *p, *p2; |
| |
| p = strerror(0); |
| *p; // no-warning |
| |
| p = strerror(1); |
| // expected-note@-1{{previous function call was here}} |
| *p; // no-warning |
| |
| if (0 == 1) { |
| // expected-note@-1{{0 is not equal to 1}} |
| // expected-note@-2{{Taking false branch}} |
| p2 = strerror(2); |
| } |
| |
| *p; // no-warning |
| |
| if (errno) { |
| // expected-note@-1{{Assuming 'errno' is not equal to 0}} |
| // expected-note@-2{{Taking true branch}} |
| p2 = strerror(errno); |
| // expected-note@-1{{'strerror' call may invalidate the result of the previous 'strerror'}} |
| } |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void asctime_test(void) { |
| const tm *t; |
| const tm *tt; |
| |
| char* p = asctime(t); |
| // expected-note@-1{{previous function call was here}} |
| char* pp = asctime(tt); |
| // expected-note@-1{{'asctime' call may invalidate the result of the previous 'asctime'}} |
| |
| *p; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void localeconv_test1(void) { |
| lconv *lc1 = localeconv(); |
| // expected-note@-1{{previous function call was here}} |
| lconv *lc2 = localeconv(); |
| // expected-note@-1{{'localeconv' call may invalidate the result of the previous 'localeconv'}} |
| |
| *lc1; |
| // expected-warning@-1{{dereferencing an invalid pointer}} |
| // expected-note@-2{{dereferencing an invalid pointer}} |
| } |
| |
| void localeconv_test2(void) { |
| // TODO: false negative |
| lconv *lc1 = localeconv(); |
| lconv *lc2 = localeconv(); |
| lc1->field; |
| } |