diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -92,10 +92,8 @@ return false; // Get it's symbol and find the declaration region it's pointing to. - const auto *Sm = dyn_cast(SymReg->getSymbol()); - if (!Sm) - return false; - const auto *DeclReg = dyn_cast(Sm->getRegion()); + const auto *DeclReg = + dyn_cast_or_null(SymReg->getSymbol()->getOriginRegion()); if (!DeclReg) return false; diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -973,26 +973,16 @@ const MemRegion *sReg = nullptr; if (D->hasGlobalStorage() && !D->isStaticLocal()) { - - // First handle the globals defined in system headers. - if (Ctx.getSourceManager().isInSystemHeader(D->getLocation())) { - // Allow the system globals which often DO GET modified, assume the - // rest are immutable. - if (D->getName().contains("errno")) - sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); - else - sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); - - // Treat other globals as GlobalInternal unless they are constants. - } else { - QualType GQT = D->getType(); - const Type *GT = GQT.getTypePtrOrNull(); + QualType Ty = D->getType(); + assert(!Ty.isNull()); + if (Ty.isConstQualified() && Ty->isArithmeticType()) { // TODO: We could walk the complex types here and see if everything is // constified. - if (GT && GQT.isConstQualified() && GT->isArithmeticType()) - sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); - else - sReg = getGlobalsRegion(); + sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); + } else if (Ctx.getSourceManager().isInSystemHeader(D->getLocation())) { + sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); + } else { + sReg = getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind); } // Finally handle static locals. diff --git a/clang/test/Analysis/Inputs/some_system_globals.h b/clang/test/Analysis/Inputs/some_system_globals.h new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/Inputs/some_system_globals.h @@ -0,0 +1,4 @@ +#pragma clang system_header + +extern const int my_const_system_global; +extern int my_mutable_system_global; diff --git a/clang/test/Analysis/Inputs/some_user_globals.h b/clang/test/Analysis/Inputs/some_user_globals.h new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/Inputs/some_user_globals.h @@ -0,0 +1,2 @@ +extern const int my_const_user_global; +extern int my_mutable_user_global; diff --git a/clang/test/Analysis/globals-are-not-always-immutable.c b/clang/test/Analysis/globals-are-not-always-immutable.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/globals-are-not-always-immutable.c @@ -0,0 +1,71 @@ +// RUN: %clang_analyze_cc1 -verify %s \ +// RUN: -analyzer-config eagerly-assume=false \ +// RUN: -analyzer-checker=core,debug.ExprInspection + +#include "Inputs/errno_var.h" +#include "Inputs/some_system_globals.h" +#include "Inputs/some_user_globals.h" + +extern void abort() __attribute__((__noreturn__)); +#define assert(expr) ((expr) ? (void)(0) : abort()) + +void invalidate_globals(void); +void clang_analyzer_eval(int x); + +/// Test the special system 'errno' +void test_errno_constraint() { + assert(errno > 2); + clang_analyzer_eval(errno > 2); // expected-warning {{TRUE}} + invalidate_globals(); + clang_analyzer_eval(errno > 2); // expected-warning {{UNKNOWN}} +} +void test_errno_assign(int x) { + errno = x; + clang_analyzer_eval(errno == x); // expected-warning {{TRUE}} + invalidate_globals(); + clang_analyzer_eval(errno == x); // expected-warning {{UNKNOWN}} +} + +/// Test user global variables +void test_my_const_user_global_constraint() { + assert(my_const_user_global > 2); + clang_analyzer_eval(my_const_user_global > 2); // expected-warning {{TRUE}} + invalidate_globals(); + clang_analyzer_eval(my_const_user_global > 2); // expected-warning {{TRUE}} +} +void test_my_const_user_global_assign(int); // One cannot assign value to a const lvalue. + +void test_my_mutable_user_global_constraint() { + assert(my_mutable_user_global > 2); + clang_analyzer_eval(my_mutable_user_global > 2); // expected-warning {{TRUE}} + invalidate_globals(); + clang_analyzer_eval(my_mutable_user_global > 2); // expected-warning {{UNKNOWN}} +} +void test_my_mutable_user_global_assign(int x) { + my_mutable_user_global = x; + clang_analyzer_eval(my_mutable_user_global == x); // expected-warning {{TRUE}} + invalidate_globals(); + clang_analyzer_eval(my_mutable_user_global == x); // expected-warning {{UNKNOWN}} +} + +/// Test system global variables +void test_my_const_system_global_constraint() { + assert(my_const_system_global > 2); + clang_analyzer_eval(my_const_system_global > 2); // expected-warning {{TRUE}} + invalidate_globals(); + clang_analyzer_eval(my_const_system_global > 2); // expected-warning {{TRUE}} +} +void test_my_const_system_global_assign(int);// One cannot assign value to a const lvalue. + +void test_my_mutable_system_global_constraint() { + assert(my_mutable_system_global > 2); + clang_analyzer_eval(my_mutable_system_global > 2); // expected-warning {{TRUE}} + invalidate_globals(); + clang_analyzer_eval(my_mutable_system_global > 2); // expected-warning {{UNKNOWN}} +} +void test_my_mutable_system_global_assign(int x) { + my_mutable_system_global = x; + clang_analyzer_eval(my_mutable_system_global == x); // expected-warning {{TRUE}} + invalidate_globals(); + clang_analyzer_eval(my_mutable_system_global == x); // expected-warning {{UNKNOWN}} +}