[clang] d646157 - [analyzer] Fix assertion failure on code with transparent unions

Valeriy Savchenko via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 25 13:10:31 PDT 2021


Author: Valeriy Savchenko
Date: 2021-06-25T23:09:16+03:00
New Revision: d646157146ccda93cd72dcbaff4a554c61ed9586

URL: https://github.com/llvm/llvm-project/commit/d646157146ccda93cd72dcbaff4a554c61ed9586
DIFF: https://github.com/llvm/llvm-project/commit/d646157146ccda93cd72dcbaff4a554c61ed9586.diff

LOG: [analyzer] Fix assertion failure on code with transparent unions

rdar://76948312

Differential Revision: https://reviews.llvm.org/D104716

Added: 
    clang/test/Analysis/transparent_union_bug.c

Modified: 
    clang/lib/StaticAnalyzer/Core/CallEvent.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index ecf1d1b5f0688..3785f498414f9 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -47,6 +47,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
@@ -466,6 +467,42 @@ bool CallEvent::isVariadic(const Decl *D) {
   llvm_unreachable("unknown callable kind");
 }
 
+static bool isTransparentUnion(QualType T) {
+  const RecordType *UT = T->getAsUnionType();
+  return UT && UT->getDecl()->hasAttr<TransparentUnionAttr>();
+}
+
+// In some cases, symbolic cases should be transformed before we associate
+// them with parameters.  This function incapsulates such cases.
+static SVal processArgument(SVal Value, const Expr *ArgumentExpr,
+                            const ParmVarDecl *Parameter, SValBuilder &SVB) {
+  QualType ParamType = Parameter->getType();
+  QualType ArgumentType = ArgumentExpr->getType();
+
+  // Transparent unions allow users to easily convert values of union field
+  // types into union-typed objects.
+  //
+  // Also, more importantly, they allow users to define functions with 
diff erent
+  // 
diff erent parameter types, substituting types matching transparent union
+  // field types with the union type itself.
+  //
+  // Here, we check specifically for latter cases and prevent binding
+  // field-typed values to union-typed regions.
+  if (isTransparentUnion(ParamType) &&
+      // Let's check that we indeed trying to bind 
diff erent types.
+      !isTransparentUnion(ArgumentType)) {
+    BasicValueFactory &BVF = SVB.getBasicValueFactory();
+
+    llvm::ImmutableList<SVal> CompoundSVals = BVF.getEmptySValList();
+    CompoundSVals = BVF.prependSVal(Value, CompoundSVals);
+
+    // Wrap it with compound value.
+    return SVB.makeCompoundVal(ParamType, CompoundSVals);
+  }
+
+  return Value;
+}
+
 static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
                                          CallEvent::BindingsTy &Bindings,
                                          SValBuilder &SVB,
@@ -490,10 +527,12 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
     // determined in compile-time but not represented as arg-expressions,
     // which makes getArgSVal() fail and return UnknownVal.
     SVal ArgVal = Call.getArgSVal(Idx);
+    const Expr *ArgExpr = Call.getArgExpr(Idx);
     if (!ArgVal.isUnknown()) {
       Loc ParamLoc = SVB.makeLoc(
           MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx));
-      Bindings.push_back(std::make_pair(ParamLoc, ArgVal));
+      Bindings.push_back(
+          std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB)));
     }
   }
 

diff  --git a/clang/test/Analysis/transparent_union_bug.c b/clang/test/Analysis/transparent_union_bug.c
new file mode 100644
index 0000000000000..b6069c6a59b19
--- /dev/null
+++ b/clang/test/Analysis/transparent_union_bug.c
@@ -0,0 +1,40 @@
+// RUN: %clang_analyze_cc1 -analyze -triple x86_64-apple-darwin10 \
+// RUN:  -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_warnIfReached();
+
+typedef struct {
+  int value;
+} Struct;
+
+typedef union {
+  Struct *ptr;
+  long num;
+} __attribute__((transparent_union)) Alias;
+
+void foo(Struct *x);
+void foo(Alias y) {
+  if (y.ptr == 0) {
+    // no-crash
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void foobar(long z);
+void foobar(Alias z) {
+  if (z.num != 42) {
+    // no-crash
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void foobaz(Alias x) {
+  if (x.ptr == 0) {
+    // no-crash
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void bar(Struct arg) {
+  foo(&arg);
+  foobar(42);
+  foobaz(&arg);
+}


        


More information about the cfe-commits mailing list