From 51560e5609c1153a72bcd384a34a2e1cafdefc7a Mon Sep 17 00:00:00 2001 From: einvbri Date: Sat, 8 Feb 2025 17:00:43 +0100 Subject: [PATCH 1/3] Add option for pthread modeling, default false. Update LITs Add option for pthread modeling set to a default of false. Uses must opt-in. Update LITs so all pass. --- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def | 5 +++++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 3 ++- clang/test/Analysis/SD-tests/thread-modeling-inline.c | 2 +- clang/test/Analysis/SD-tests/thread-modeling-inline2.c | 2 +- clang/test/Analysis/SD-tests/thread-modeling-leak.c | 2 +- clang/test/Analysis/SD-tests/thread-modeling-leak2.c | 2 +- clang/test/Analysis/SD-tests/thread-modeling-null-deref.c | 2 +- clang/test/Analysis/SD-tests/thread-modeling-null-deref2.c | 2 +- .../Analysis/SD-tests/thread-modeling-path-dependent-leak.c | 2 +- clang/test/Analysis/analyzer-config.c | 2 ++ clang/test/Analysis/analyzer-enabled-checkers.c | 1 + .../Analysis/std-c-library-functions-arg-enabled-checkers.c | 1 + 12 files changed, 18 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def index a9ef9aced67e3..50286f2fd32a8 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -127,6 +127,11 @@ ANALYZER_OPTION(bool, MayInlineCXXStandardLibrary, "c++-stdlib-inlining", "considered for inlining.", true) +ANALYZER_OPTION(bool, ModelPthreads, "model-pthreads", + "Model Pthreads if enabled - default is disabled ", + false + ) + ANALYZER_OPTION(bool, MayInlineCXXAllocator, "c++-allocator-inlining", "Whether or not allocator and deallocator calls may be " "considered for inlining.", diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 25e28adaee1ad..66f94ff4905a9 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -1296,6 +1296,7 @@ static bool isTrivialObjectAssignment(const CallEvent &Call) { void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &CallTemplate, const EvalCallOptions &CallOpts) { + AnalyzerOptions &Opts = AMgr.getAnalyzerOptions(); // Make sure we have the most recent state attached to the call. ProgramStateRef State = Pred->getState(); CallEventRef<> Call = CallTemplate.cloneWithState(State); @@ -1322,7 +1323,7 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, // TODO: make this a proper mode // Special case thread creation - if (isThread(*Call)) { + if (isThread(*Call) && Opts.ModelPthreads) { llvm::errs() << "Hijacking pthread_create(3)\n"; threadBifurcate(*Call, D, Bldr, Pred, State); return; diff --git a/clang/test/Analysis/SD-tests/thread-modeling-inline.c b/clang/test/Analysis/SD-tests/thread-modeling-inline.c index 566f5f1781d00..a4432ec47f04c 100644 --- a/clang/test/Analysis/SD-tests/thread-modeling-inline.c +++ b/clang/test/Analysis/SD-tests/thread-modeling-inline.c @@ -1,5 +1,5 @@ // RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ -// RUN: -analyzer-checker=debug.ExprInspection +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true #define NULL ((void*) 0) enum bool { diff --git a/clang/test/Analysis/SD-tests/thread-modeling-inline2.c b/clang/test/Analysis/SD-tests/thread-modeling-inline2.c index 1241d77ad9bf8..af052b285a854 100644 --- a/clang/test/Analysis/SD-tests/thread-modeling-inline2.c +++ b/clang/test/Analysis/SD-tests/thread-modeling-inline2.c @@ -1,5 +1,5 @@ // RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ -// RUN: -analyzer-checker=debug.ExprInspection +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true #define NULL ((void*) 0) enum bool { diff --git a/clang/test/Analysis/SD-tests/thread-modeling-leak.c b/clang/test/Analysis/SD-tests/thread-modeling-leak.c index 5794612c08e7b..f669c85f057d3 100644 --- a/clang/test/Analysis/SD-tests/thread-modeling-leak.c +++ b/clang/test/Analysis/SD-tests/thread-modeling-leak.c @@ -1,7 +1,7 @@ // RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ // RUN: -analyzer-checker=core \ // RUN: -analyzer-checker=unix \ -// RUN: -analyzer-checker=debug.ExprInspection +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true #define NULL ((void*) 0) diff --git a/clang/test/Analysis/SD-tests/thread-modeling-leak2.c b/clang/test/Analysis/SD-tests/thread-modeling-leak2.c index b903437950cc8..bb89b29414fdc 100644 --- a/clang/test/Analysis/SD-tests/thread-modeling-leak2.c +++ b/clang/test/Analysis/SD-tests/thread-modeling-leak2.c @@ -1,7 +1,7 @@ // RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ // RUN: -analyzer-checker=core \ // RUN: -analyzer-checker=unix \ -// RUN: -analyzer-checker=debug.ExprInspection +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true #define NULL ((void*) 0) diff --git a/clang/test/Analysis/SD-tests/thread-modeling-null-deref.c b/clang/test/Analysis/SD-tests/thread-modeling-null-deref.c index b04a1816ce571..0e2c9581cc2ca 100644 --- a/clang/test/Analysis/SD-tests/thread-modeling-null-deref.c +++ b/clang/test/Analysis/SD-tests/thread-modeling-null-deref.c @@ -1,6 +1,6 @@ // RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ // RUN: -analyzer-checker=core \ -// RUN: -analyzer-checker=debug.ExprInspection +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true #define NULL ((void*) 0) enum bool { diff --git a/clang/test/Analysis/SD-tests/thread-modeling-null-deref2.c b/clang/test/Analysis/SD-tests/thread-modeling-null-deref2.c index a8a945684b19b..2e5269dc6b07d 100644 --- a/clang/test/Analysis/SD-tests/thread-modeling-null-deref2.c +++ b/clang/test/Analysis/SD-tests/thread-modeling-null-deref2.c @@ -1,6 +1,6 @@ // RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ // RUN: -analyzer-checker=core \ -// RUN: -analyzer-checker=debug.ExprInspection +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true #define NULL ((void*) 0) enum bool { diff --git a/clang/test/Analysis/SD-tests/thread-modeling-path-dependent-leak.c b/clang/test/Analysis/SD-tests/thread-modeling-path-dependent-leak.c index 03c0dc9079df4..8485e2d454252 100644 --- a/clang/test/Analysis/SD-tests/thread-modeling-path-dependent-leak.c +++ b/clang/test/Analysis/SD-tests/thread-modeling-path-dependent-leak.c @@ -1,7 +1,7 @@ // RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ // RUN: -analyzer-checker=core \ // RUN: -analyzer-checker=unix \ -// RUN: -analyzer-checker=debug.ExprInspection +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true #define NULL ((void*) 0) diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index d5eb790b82f23..24c66e58c59fd 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -99,6 +99,7 @@ // CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14 // CHECK-NEXT: mode = deep // CHECK-NEXT: model-path = "" +// CHECK-NEXT: model-pthreads = false // CHECK-NEXT: notes-as-events = false // CHECK-NEXT: nullability:NoDiagnoseCallsToSystemHeaders = false // CHECK-NEXT: objc-inlining = true @@ -126,6 +127,7 @@ // CHECK-NEXT: suppress-c++-stdlib = true // CHECK-NEXT: suppress-inlined-defensive-checks = true // CHECK-NEXT: suppress-null-return-paths = true +// CHECK-NEXT: thread-aware = true // CHECK-NEXT: track-conditions = true // CHECK-NEXT: track-conditions-debug = false // CHECK-NEXT: unix.DynamicMemoryModeling:AddNoOwnershipChangeNotes = true diff --git a/clang/test/Analysis/analyzer-enabled-checkers.c b/clang/test/Analysis/analyzer-enabled-checkers.c index c70aeb21ab045..0d82b06a4ddae 100644 --- a/clang/test/Analysis/analyzer-enabled-checkers.c +++ b/clang/test/Analysis/analyzer-enabled-checkers.c @@ -7,6 +7,7 @@ // CHECK: OVERVIEW: Clang Static Analyzer Enabled Checkers List // CHECK-EMPTY: // CHECK-NEXT: apiModeling.Errno +// CHECK-NEXT: apiModeling.Thread // CHECK-NEXT: apiModeling.TrustNonnull // CHECK-NEXT: apiModeling.TrustReturnsNonnull // CHECK-NEXT: apiModeling.llvm.CastValue diff --git a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c index faf0a8f19d919..2029cf3672df2 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c +++ b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c @@ -15,6 +15,7 @@ // CHECK: OVERVIEW: Clang Static Analyzer Enabled Checkers List // CHECK-EMPTY: // CHECK-NEXT: apiModeling.Errno +// CHECK-NEXT: apiModeling.Thread // CHECK-NEXT: apiModeling.TrustNonnull // CHECK-NEXT: apiModeling.TrustReturnsNonnull // CHECK-NEXT: apiModeling.llvm.CastValue From e987893cee919cbc4112d2c47226965debf00b79 Mon Sep 17 00:00:00 2001 From: einvbri Date: Sat, 8 Feb 2025 19:35:49 +0100 Subject: [PATCH 2/3] Add example taint analyis improvement demo test Also, add additional LIT test for pointer deref. --- clang/test/Analysis/SD-tests/taint-thread.c | 37 ++++++++++++++++ .../SD-tests/thread-modeling-ptr-deref.c | 42 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 clang/test/Analysis/SD-tests/taint-thread.c create mode 100644 clang/test/Analysis/SD-tests/thread-modeling-ptr-deref.c diff --git a/clang/test/Analysis/SD-tests/taint-thread.c b/clang/test/Analysis/SD-tests/taint-thread.c new file mode 100644 index 0000000000000..9ff29fa95cd9d --- /dev/null +++ b/clang/test/Analysis/SD-tests/taint-thread.c @@ -0,0 +1,37 @@ +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core,optin.taint.GenericTaint -DPTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true + +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core,optin.taint.GenericTaint -DNO_PTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=false + +#define NULL ((void*) 0) +typedef unsigned long int pthread_t; +typedef struct __pthread_attr pthread_attr_t; +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); + +char *strcat( char *dest, const char *src ); +int scanf(const char*, ...); +int system(const char *command); + +void *thread_func(void *arg) { +#ifdef PTHREAD_MODEL + system( (char *) arg); // expected-warning {{Untrusted data is passed to a system call (CERT/STR02-C. Sanitize data passed to complex subsystems)}} +#endif +#ifdef NO_PTHREAD_MODEL + system( (char *) arg); // expected-no-diagnostics +#endif + return NULL; +} + +// Command Injection Vulnerability Example +void test(void) { + char cmd[2048] = "/bin/cat "; + char filename[1024]; + scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here + strcat(cmd, filename); + pthread_t p1; + pthread_create(&p1, NULL, &thread_func, &cmd); +} + diff --git a/clang/test/Analysis/SD-tests/thread-modeling-ptr-deref.c b/clang/test/Analysis/SD-tests/thread-modeling-ptr-deref.c new file mode 100644 index 0000000000000..68bf750410879 --- /dev/null +++ b/clang/test/Analysis/SD-tests/thread-modeling-ptr-deref.c @@ -0,0 +1,42 @@ +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core -DPTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true +// +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core -DNO_PTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=false + +#define NULL ((void*) 0) + +typedef unsigned long int pthread_t; +typedef struct __pthread_attr pthread_attr_t; + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); + +void clang_analyzer_checkInlined(int); +void clang_analyzer_dump(int); + +void* thread_function(void* arg) +{ + // should expect to fail the test at this line if you set the checkInlined to true +#ifdef PTHREAD_MODEL + clang_analyzer_checkInlined(1); // expected-warning{{TRUE}} +#endif + int *ptr = (int *)arg; +#ifdef PTHREAD_MODEL + clang_analyzer_dump(*ptr); // expected-warning{{1 S32b}} +#endif +#ifdef NO_PTHREAD_MODEL + clang_analyzer_dump(*ptr); // expected-warning-re{{reg_${{[[:digit:]]+}}},0 S64b,int}}} +#endif + return NULL; +} + +int test() +{ + int i = 1; + pthread_t p1; + pthread_create(&p1, NULL, &thread_function, &i); + return 0; +} + From ce187ad43ac023aa1a227a56a9ecb37b755d0ccc Mon Sep 17 00:00:00 2001 From: einvbri Date: Mon, 10 Feb 2025 23:26:31 +0100 Subject: [PATCH 3/3] Fix 2 crashes seen when analyzing memcached Current changes were causing analysis of memcached to crash. This update addresses 2 of 3 crashes found so far, adds a covering LIT test and improves LIT test coverage. All clang/test/Analysis LITs now pass. --- .../Checkers/ThreadModeling.cpp | 6 +- .../Core/ExprEngineCallAndReturn.cpp | 6 ++ .../SD-tests/thread-modeling-funcptr.c | 64 +++++++++++++++++++ .../SD-tests/thread-modeling-malloc.c | 59 +++++++++++++++++ .../SD-tests/thread-modeling-struct.c | 56 ++++++++++++++++ 5 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 clang/test/Analysis/SD-tests/thread-modeling-funcptr.c create mode 100644 clang/test/Analysis/SD-tests/thread-modeling-malloc.c create mode 100644 clang/test/Analysis/SD-tests/thread-modeling-struct.c diff --git a/clang/lib/StaticAnalyzer/Checkers/ThreadModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ThreadModeling.cpp index 396d5467d2c24..c6d4ad1edb735 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ThreadModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ThreadModeling.cpp @@ -32,6 +32,8 @@ class ThreadModeling : public Checker { void ThreadModeling::checkPreCall(const CallEvent &Call, CheckerContext &C) const { + return; +#if 0 if (!ThreadCreateCalls.contains(Call)) { return; } @@ -67,7 +69,7 @@ void ThreadModeling::checkPreCall(const CallEvent &Call, CheckerContext &C) cons // 6. Resolve AST to Call // 7. Inline Call - +#endif } const FunctionDecl *ThreadModeling::GetFunctionDecl(SVal V, CheckerContext &C) const { @@ -82,4 +84,4 @@ void clang::ento::registerThreadModeling(CheckerManager &Mgr) { bool clang::ento::shouldRegisterThreadModeling(const CheckerManager &) { return true; -} \ No newline at end of file +} diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 66f94ff4905a9..87993bafe782a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -561,6 +561,12 @@ void ExprEngine::threadBifurcate(CallEvent const &Call, Decl const *D, if (auto const *FR = dyn_cast(SRR)) StartRoutine = dyn_cast(FR->getDecl()); + // There may not be an actual function bound to the 3rd + // argument of pthread_create because of analyzer limitations, + // so detect that case and return at this point since it cannot be modeled + if (!StartRoutine) + return; + assert(StartRoutine && "start_routine should be a valid function pointer"); assert(StartRoutine->hasBody() && "start_routine must be well defined"); diff --git a/clang/test/Analysis/SD-tests/thread-modeling-funcptr.c b/clang/test/Analysis/SD-tests/thread-modeling-funcptr.c new file mode 100644 index 0000000000000..fdf264462cbe8 --- /dev/null +++ b/clang/test/Analysis/SD-tests/thread-modeling-funcptr.c @@ -0,0 +1,64 @@ +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core,unix -DPTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true +// +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core,unix -DNO_PTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=false + +#define NULL ((void*) 0) +typedef __typeof(sizeof(int)) size_t; +typedef unsigned long int pthread_t; +typedef struct __pthread_attr pthread_attr_t; + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); + +void clang_analyzer_checkInlined(int); +void clang_analyzer_dump(int); + +typedef struct _mystruct { + int a; + int b; +} mystruct, *pmystruct; + +void *malloc(size_t sz); +void free (void* ptr); + +static void* thread_function(void* arg) +{ + pmystruct ps = (pmystruct) arg; + // should expect to fail the test at this line if you set the checkInlined to true + int *ptr = (int *)arg; + clang_analyzer_dump(*ptr); // expected-warning-re{{reg_${{[[:digit:]]+}}},0 S64b,int}}} + free(arg); + return NULL; +} + +void create_worker( void *(*func)(void *), void * arg) { + pthread_t p1; + pthread_create(&p1, NULL, func, arg); +} + +int mem[256]; + +int test() +{ + pmystruct ps = (pmystruct) malloc(sizeof(mystruct)); + ps->a = 1; + ps->b = 2; + + // The static analyzer gives up on analyzing a code path for + // iterations that exceed a limit. + // See https://discourse.llvm.org/t/loop-handling-improvement-plans/80417 + // + // To prove this to yourself, change 256 to 1 and rerun. Change + // to a few different numbers and explore where the LIT test + // starts to produce unexpected values. + for (int i=0; i<256; i++) { + mem[i] = 0; + } + create_worker(thread_function, ps); + + return 0; +} + diff --git a/clang/test/Analysis/SD-tests/thread-modeling-malloc.c b/clang/test/Analysis/SD-tests/thread-modeling-malloc.c new file mode 100644 index 0000000000000..612baa1e2e8e2 --- /dev/null +++ b/clang/test/Analysis/SD-tests/thread-modeling-malloc.c @@ -0,0 +1,59 @@ +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core,unix -DPTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true +// +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core,unix -DNO_PTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=false + +#define NULL ((void*) 0) +typedef __typeof(sizeof(int)) size_t; +typedef unsigned long int pthread_t; +typedef struct __pthread_attr pthread_attr_t; + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); + +void clang_analyzer_checkInlined(int); +void clang_analyzer_dump(int); + +typedef struct _mystruct { + int a; + int b; +} mystruct, *pmystruct; + +void *malloc(size_t sz); +void free (void* ptr); + +void* thread_function(void* arg) +{ + pmystruct ps = (pmystruct) arg; + // should expect to fail the test at this line if you set the checkInlined to true +#ifdef PTHREAD_MODEL + clang_analyzer_checkInlined(1); // expected-warning{{TRUE}} +#endif + int *ptr = (int *)arg; +#ifdef PTHREAD_MODEL + clang_analyzer_dump(ps->a); // expected-warning{{1 S32b}} + clang_analyzer_dump(ps->b); // expected-warning{{2 S32b}} +#endif +#ifdef NO_PTHREAD_MODEL + clang_analyzer_dump(*ptr); // expected-warning-re{{reg_${{[[:digit:]]+}}},0 S64b,int}}} +#endif + return NULL; +} + +int test() +{ + pmystruct ps = (pmystruct) malloc(sizeof(mystruct)); + ps->a = 1; + ps->b = 2; + pthread_t p1; + pthread_create(&p1, NULL, &thread_function, ps); + +#ifdef PTHREAD_MODEL + return 0; // expected-warning{{Potential leak of memory pointed to by 'ps'}} +#endif +#ifdef NO_PTHREAD_MODEL + return 0; +#endif +} diff --git a/clang/test/Analysis/SD-tests/thread-modeling-struct.c b/clang/test/Analysis/SD-tests/thread-modeling-struct.c new file mode 100644 index 0000000000000..6b9262f1b82b4 --- /dev/null +++ b/clang/test/Analysis/SD-tests/thread-modeling-struct.c @@ -0,0 +1,56 @@ +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core,unix -DPTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=true +// +// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \ +// RUN: -analyzer-checker=core,unix -DNO_PTHREAD_MODEL=1 \ +// RUN: -analyzer-checker=debug.ExprInspection -analyzer-config model-pthreads=false + +#define NULL ((void*) 0) +typedef __typeof(sizeof(int)) size_t; +typedef unsigned long int pthread_t; +typedef struct __pthread_attr pthread_attr_t; + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); + +void clang_analyzer_checkInlined(int); +void clang_analyzer_dump(int); + +typedef struct _mystruct { + int a; + int b; +} mystruct, *pmystruct; + +void *malloc(size_t sz); +void free (void* ptr); + +void* thread_function(void* arg) +{ + pmystruct ps = (pmystruct) arg; + // should expect to fail the test at this line if you set the checkInlined to true +#ifdef PTHREAD_MODEL + clang_analyzer_checkInlined(1); // expected-warning{{TRUE}} +#endif + int *ptr = (int *)arg; +#ifdef PTHREAD_MODEL + clang_analyzer_dump(ps->a); // expected-warning{{1 S32b}} + clang_analyzer_dump(ps->b); // expected-warning{{2 S32b}} +#endif +#ifdef NO_PTHREAD_MODEL + clang_analyzer_dump(*ptr); // expected-warning-re{{reg_${{[[:digit:]]+}}},0 S64b,int}}} +#endif + free(arg); + return NULL; +} + +int test() +{ + pmystruct ps = (pmystruct) malloc(sizeof(mystruct)); + ps->a = 1; + ps->b = 2; + pthread_t p1; + pthread_create(&p1, NULL, &thread_function, ps); + + return 0; +} +