From b30521c28a4dc1b94d793385e4144ede5822b2c1 Mon Sep 17 00:00:00 2001 From: Denys Petrov Date: Mon, 26 Apr 2021 19:17:56 +0300 Subject: [PATCH] [analyzer] Wrong type cast occurs during pointer dereferencing after type punning Summary: During pointer dereferencing CastRetrievedVal uses wrong type from the Store after type punning. Namely, the pointer casts to another type and then assigns with a value of one more another type. It produces NonLoc value when Loc is expected. Differential Revision: https://reviews.llvm.org/D89055 Fixes: https://bugs.llvm.org/show_bug.cgi?id=37503 https://bugs.llvm.org/show_bug.cgi?id=49007 --- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 9 ++++++++- clang/test/Analysis/casts.c | 5 +++++ clang/test/Analysis/string.c | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index a490993..f376922 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -748,8 +748,8 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, QualType CastTy, // pointers as well. // FIXME: We really need a single good function to perform casts for us // correctly every time we need it. + const MemRegion *R = V.getRegion(); if (CastTy->isPointerType() && !CastTy->isVoidPointerType()) { - const MemRegion *R = V.getRegion(); if (const auto *SR = dyn_cast(R)) { QualType SRTy = SR->getSymbol()->getType(); if (!hasSameUnqualifiedPointeeType(SRTy, CastTy)) { @@ -758,6 +758,13 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, QualType CastTy, } } } + // Next fixes pointer dereference using type different from its initial + // one. See PR37503 and PR49007 for details. + if (const auto *ER = dyn_cast(R)) { + R = StateMgr.getStoreManager().castRegion(ER, CastTy); + return loc::MemRegionVal(R); + } + return V; } diff --git a/clang/test/Analysis/casts.c b/clang/test/Analysis/casts.c index ae7b846..702e53a 100644 --- a/clang/test/Analysis/casts.c +++ b/clang/test/Analysis/casts.c @@ -245,3 +245,8 @@ double no_crash_reinterpret_double_as_sym_ptr(double a, void * b) { return a * a; } +void no_crash_reinterpret_char_as_uchar(char ***a, int *b) { + *(unsigned char **)a = (unsigned char *)b; + if (**a == 0) // no-crash + ; +} diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c index debcea48..2bf34ca 100644 --- a/clang/test/Analysis/string.c +++ b/clang/test/Analysis/string.c @@ -363,6 +363,20 @@ void strcpy_no_overflow(char *y) { strcpy(x, y); // no-warning } +// PR37503 +void *get_void_ptr(); +char ***type_punned_ptr; +void strcpy_no_assertion(char c) { + *(unsigned char **)type_punned_ptr = (unsigned char *)(get_void_ptr()); + strcpy(**type_punned_ptr, &c); // no-crash +} + +// PR49007 +char f(char ***c, int *i) { + *(void **)c = i + 1; + return (**c)[0]; // no-crash +} + //===----------------------------------------------------------------------=== // stpcpy() //===----------------------------------------------------------------------=== -- 2.7.4