baloghadamsoftware updated this revision to Diff 266296.
baloghadamsoftware added a comment.
Herald added subscribers: llvm-commits, MaskRay, hiraditya, arichardson,
nemanjai, emaste.
Herald added a reviewer: espindola.
Herald added a reviewer: MaskRay.
Herald added a project: LLVM.
Updated according to the comments.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D80522/new/
https://reviews.llvm.org/D80522
Files:
clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
clang/lib/StaticAnalyzer/Core/CallEvent.cpp
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
clang/lib/StaticAnalyzer/Core/MemRegion.cpp
clang/lib/StaticAnalyzer/Core/Store.cpp
clang/test/Analysis/explain-svals.c
clang/test/Analysis/explain-svals.cpp
clang/test/Analysis/explain-svals.m
clang/unittests/StaticAnalyzer/CMakeLists.txt
clang/unittests/StaticAnalyzer/ParamRegionTest.cpp
compiler-rt/lib/fuzzer/afl/afl_driver.cpp
lld/ELF/InputFiles.cpp
lld/test/ELF/invalid/verneed-shared.test
lld/test/ELF/invalid/verneed-shared.yaml
lldb/include/lldb/Utility/Args.h
lldb/test/API/python_api/hello_world/TestHelloWorld.py
lldb/test/API/python_api/sbdata/TestSBData.py
llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h
llvm/include/llvm/CodeGen/ResourcePriorityQueue.h
llvm/include/llvm/Support/YAMLTraits.h
llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp
llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp
llvm/lib/Support/YAMLTraits.cpp
llvm/test/CodeGen/PowerPC/pr45709.ll
llvm/unittests/Support/YAMLIOTest.cpp
llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn
Index: llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn
===================================================================
--- llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn
+++ llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn
@@ -55,6 +55,7 @@
"SimpleConstraintManager.cpp",
"SimpleSValBuilder.cpp",
"Store.cpp",
+ "SubEngine.cpp",
"SymbolManager.cpp",
"TextDiagnostics.cpp",
"WorkList.cpp",
Index: llvm/unittests/Support/YAMLIOTest.cpp
===================================================================
--- llvm/unittests/Support/YAMLIOTest.cpp
+++ llvm/unittests/Support/YAMLIOTest.cpp
@@ -333,6 +333,7 @@
uint16_t u16;
uint8_t u8;
bool b;
+ char c;
int64_t s64;
int32_t s32;
int16_t s16;
@@ -357,6 +358,7 @@
io.mapRequired("u16", bt.u16);
io.mapRequired("u8", bt.u8);
io.mapRequired("b", bt.b);
+ io.mapRequired("c", bt.c);
io.mapRequired("s64", bt.s64);
io.mapRequired("s32", bt.s32);
io.mapRequired("s16", bt.s16);
@@ -386,6 +388,7 @@
"u16: 65000\n"
"u8: 255\n"
"b: false\n"
+ "c: 'c'\n"
"s64: -5000000000\n"
"s32: -2000000000\n"
"s16: -32000\n"
@@ -396,7 +399,7 @@
"h16: 0x8765\n"
"h32: 0xFEDCBA98\n"
"h64: 0xFEDCBA9876543210\n"
- "...\n");
+ "...\n");
yin >> map;
EXPECT_FALSE(yin.error());
@@ -407,6 +410,7 @@
EXPECT_EQ(map.u16, 65000);
EXPECT_EQ(map.u8, 255);
EXPECT_EQ(map.b, false);
+ EXPECT_EQ(map.c, 'c');
EXPECT_EQ(map.s64, -5000000000LL);
EXPECT_EQ(map.s32, -2000000000L);
EXPECT_EQ(map.s16, -32000);
@@ -434,6 +438,7 @@
map.u16 = 50000;
map.u8 = 254;
map.b = true;
+ map.c = 'd';
map.s64 = -6000000000LL;
map.s32 = -2000000000;
map.s16 = -32000;
@@ -463,6 +468,7 @@
EXPECT_EQ(map.u16, 50000);
EXPECT_EQ(map.u8, 254);
EXPECT_EQ(map.b, true);
+ EXPECT_EQ(map.c, 'd');
EXPECT_EQ(map.s64, -6000000000LL);
EXPECT_EQ(map.s32, -2000000000L);
EXPECT_EQ(map.s16, -32000);
Index: llvm/test/CodeGen/PowerPC/pr45709.ll
===================================================================
--- llvm/test/CodeGen/PowerPC/pr45709.ll
+++ llvm/test/CodeGen/PowerPC/pr45709.ll
@@ -10,37 +10,30 @@
define dso_local void @_ZN1a1bEv(<4 x float> %in) local_unnamed_addr #0 align 2 {
; CHECK-LABEL: _ZN1a1bEv:
; CHECK: # %bb.0:
-; CHECK-NEXT: bc 12, 4*cr5+lt, .LBB0_6
-; CHECK-NEXT: b .LBB0_1
-; CHECK-NEXT: .LBB0_1: # %.preheader
-; CHECK-NEXT: b .LBB0_2
-; CHECK-NEXT: .LBB0_2:
-; CHECK-NEXT: b .LBB0_3
-; CHECK-NEXT: .LBB0_3:
+; CHECK-NEXT: bclr 12, 4*cr5+lt, 0
+; CHECK-NEXT: # %bb.1: # %.preheader
; CHECK-NEXT: addis r3, r2, .LCPI0_0@toc@ha
-; CHECK-NEXT: addi r3, r3, .LCPI0_0@toc@l
-; CHECK-NEXT: lvx v3, 0, r3
-; CHECK-NEXT: vperm v2, v2, v2, v3
; CHECK-NEXT: vxor v3, v3, v3
+; CHECK-NEXT: addi r3, r3, .LCPI0_0@toc@l
+; CHECK-NEXT: lvx v4, 0, r3
; CHECK-NEXT: addi r3, r1, -48
; CHECK-NEXT: stvx v3, 0, r3
; CHECK-NEXT: addi r3, r1, -32
+; CHECK-NEXT: vperm v2, v2, v2, v4
; CHECK-NEXT: stvx v2, 0, r3
; CHECK-NEXT: lwz r3, -48(r1)
; CHECK-NEXT: lwz r4, -32(r1)
; CHECK-NEXT: cmpw r4, r3
-; CHECK-NEXT: bc 12, gt, .LBB0_4
-; CHECK-NEXT: b .LBB0_5
-; CHECK-NEXT: .LBB0_4:
+; CHECK-NEXT: bc 12, gt, .LBB0_2
+; CHECK-NEXT: b .LBB0_3
+; CHECK-NEXT: .LBB0_2: # %.preheader
; CHECK-NEXT: addi r3, r4, 0
-; CHECK-NEXT: .LBB0_5:
-; CHECK-NEXT: cmpw r3, r3
+; CHECK-NEXT: .LBB0_3: # %.preheader
; CHECK-NEXT: stw r3, -64(r1)
; CHECK-NEXT: addi r3, r1, -64
; CHECK-NEXT: lvx v2, 0, r3
; CHECK-NEXT: addi r3, r1, -16
; CHECK-NEXT: stvx v2, 0, r3
-; CHECK-NEXT: .LBB0_6:
; CHECK-NEXT: blr
br i1 undef, label %7, label %1
@@ -62,4 +55,4 @@
declare <4 x float> @llvm.maxnum.v4f32(<4 x float>, <4 x float>) #0
-attributes #0 = { nounwind optnone noinline }
+attributes #0 = { nounwind }
Index: llvm/lib/Support/YAMLTraits.cpp
===================================================================
--- llvm/lib/Support/YAMLTraits.cpp
+++ llvm/lib/Support/YAMLTraits.cpp
@@ -864,6 +864,17 @@
return "invalid boolean";
}
+void ScalarTraits<char>::output(const char &Val, void *, raw_ostream &Out) {
+ Out << Val;
+}
+
+StringRef ScalarTraits<char>::input(StringRef Scalar, void *, char &Val) {
+ if (Scalar.size() != 1)
+ return "invalid character";
+ Val = Scalar[0];
+ return StringRef();
+}
+
void ScalarTraits<StringRef>::output(const StringRef &Val, void *,
raw_ostream &Out) {
Out << Val;
Index: llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp
+++ llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp
@@ -19,13 +19,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/ResourcePriorityQueue.h"
-#include "llvm/CodeGen/DFAPacketizer.h"
#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
-#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
-#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
Index: llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp
===================================================================
--- llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp
+++ llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp
@@ -24,7 +24,6 @@
#include "llvm/Analysis/ObjCARCAliasAnalysis.h"
#include "llvm/Analysis/ObjCARCAnalysisUtils.h"
-#include "llvm/Analysis/Passes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Value.h"
Index: llvm/include/llvm/Support/YAMLTraits.h
===================================================================
--- llvm/include/llvm/Support/YAMLTraits.h
+++ llvm/include/llvm/Support/YAMLTraits.h
@@ -1159,6 +1159,12 @@
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
+template <> struct ScalarTraits<char> {
+ static void output(const char &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, char &);
+ static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
+};
+
template<>
struct ScalarTraits<StringRef> {
static void output(const StringRef &, void *, raw_ostream &);
Index: llvm/include/llvm/CodeGen/ResourcePriorityQueue.h
===================================================================
--- llvm/include/llvm/CodeGen/ResourcePriorityQueue.h
+++ llvm/include/llvm/CodeGen/ResourcePriorityQueue.h
@@ -16,15 +16,15 @@
#ifndef LLVM_CODEGEN_RESOURCEPRIORITYQUEUE_H
#define LLVM_CODEGEN_RESOURCEPRIORITYQUEUE_H
+#include "llvm/CodeGen/DFAPacketizer.h"
#include "llvm/CodeGen/ScheduleDAG.h"
+#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/MC/MCInstrItineraries.h"
namespace llvm {
- class DFAPacketizer;
- class InstrItineraryData;
class ResourcePriorityQueue;
- class SelectionDAGISel;
- class TargetInstrInfo;
- class TargetRegisterInfo;
/// Sorting functions for the Available queue.
struct resource_sort {
Index: llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h
===================================================================
--- llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h
+++ llvm/include/llvm/Analysis/ObjCARCAnalysisUtils.h
@@ -23,13 +23,17 @@
#define LLVM_LIB_ANALYSIS_OBJCARCANALYSISUTILS_H
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/ObjCARCInstKind.h"
+#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ValueHandle.h"
+#include "llvm/Pass.h"
namespace llvm {
namespace objcarc {
Index: lldb/test/API/python_api/sbdata/TestSBData.py
===================================================================
--- lldb/test/API/python_api/sbdata/TestSBData.py
+++ lldb/test/API/python_api/sbdata/TestSBData.py
@@ -21,7 +21,6 @@
self.line = line_number('main.cpp', '// set breakpoint here')
@add_test_categories(['pyapi'])
- @skipIfReproducer # SBData::SetData is not instrumented.
def test_byte_order_and_address_byte_size(self):
"""Test the SBData::SetData() to ensure the byte order and address
byte size are obeyed"""
@@ -42,7 +41,6 @@
self.assertTrue(addr == 0x8877665544332211);
@add_test_categories(['pyapi'])
- @skipIfReproducer # SBData::SetData is not instrumented.
def test_with_run_command(self):
"""Test the SBData APIs."""
self.build()
Index: lldb/test/API/python_api/hello_world/TestHelloWorld.py
===================================================================
--- lldb/test/API/python_api/hello_world/TestHelloWorld.py
+++ lldb/test/API/python_api/hello_world/TestHelloWorld.py
@@ -75,7 +75,6 @@
@add_test_categories(['pyapi'])
@skipIfiOSSimulator
@expectedFailureNetBSD
- @skipIfReproducer # File synchronization is not supported during replay.
def test_with_attach_to_process_with_id_api(self):
"""Create target, spawn a process, and attach to it with process id."""
exe = '%s_%d'%(self.testMethodName, os.getpid())
Index: lldb/include/lldb/Utility/Args.h
===================================================================
--- lldb/include/lldb/Utility/Args.h
+++ lldb/include/lldb/Utility/Args.h
@@ -391,7 +391,7 @@
return lldb_private::Args::ArgEntry(value, quote);
}
StringRef value;
- uint8_t quote;
+ char quote;
};
static void mapping(IO &io, lldb_private::Args::ArgEntry &v);
};
Index: lld/test/ELF/invalid/verneed-shared.yaml
===================================================================
--- lld/test/ELF/invalid/verneed-shared.yaml
+++ lld/test/ELF/invalid/verneed-shared.yaml
@@ -6,7 +6,7 @@
## sh_offset(SHT_GNU_verneed) is out of bounds.
# RUN: yaml2obj --docnum=1 %s -o %t1.so
# RUN: not ld.lld %t.o %t1.so -o /dev/null 2>&1 | FileCheck --check-prefix=SHOFFSET %s
-# SHOFFSET: error: {{.*}}.so: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x0) that is greater than the file size (0x168)
+# SHOFFSET: error: {{.*}}.so: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x0) that is greater than the file size (0x228)
--- !ELF
FileHeader:
Class: ELFCLASS64
@@ -17,14 +17,12 @@
- Name: .gnu.version_r
Type: SHT_GNU_verneed
Flags: [ SHF_ALLOC ]
- Info: 1
ShOffset: 0xFFFFFFFF
-## A Verneed entry is misaligned (not a multiple of 4). This may happen
-## some interface shared objects. We use memcpy to read the fields, so
-## misalignment isn't a problem and there is no need to diagnose.
+## A Verneed entry is misaligned (not a multiple of 4).
# RUN: yaml2obj --docnum=2 %s -o %t2.so
-# RUN: ld.lld %t.o %t2.so -o /dev/null
+# RUN: not ld.lld %t.o %t2.so -o /dev/null 2>&1 | FileCheck --check-prefix=VN-MISALIGNED %s
+# VN-MISALIGNED: {{.*}}.so has an invalid Verneed
--- !ELF
FileHeader:
Class: ELFCLASS64
Index: lld/ELF/InputFiles.cpp
===================================================================
--- lld/ELF/InputFiles.cpp
+++ lld/ELF/InputFiles.cpp
@@ -1224,12 +1224,14 @@
ArrayRef<uint8_t> data = CHECK(obj.getSectionContents(sec), this);
const uint8_t *verneedBuf = data.begin();
for (unsigned i = 0; i != sec->sh_info; ++i) {
- if (verneedBuf + sizeof(typename ELFT::Verneed) > data.end())
+ if (verneedBuf + sizeof(typename ELFT::Verneed) > data.end() ||
+ uintptr_t(verneedBuf) % sizeof(uint32_t) != 0)
fatal(toString(this) + " has an invalid Verneed");
auto *vn = reinterpret_cast<const typename ELFT::Verneed *>(verneedBuf);
const uint8_t *vernauxBuf = verneedBuf + vn->vn_aux;
for (unsigned j = 0; j != vn->vn_cnt; ++j) {
- if (vernauxBuf + sizeof(typename ELFT::Vernaux) > data.end())
+ if (vernauxBuf + sizeof(typename ELFT::Vernaux) > data.end() ||
+ uintptr_t(vernauxBuf) % sizeof(uint32_t) != 0)
fatal(toString(this) + " has an invalid Vernaux");
auto *aux = reinterpret_cast<const typename ELFT::Vernaux *>(vernauxBuf);
if (aux->vna_name >= this->stringTable.size())
Index: compiler-rt/lib/fuzzer/afl/afl_driver.cpp
===================================================================
--- compiler-rt/lib/fuzzer/afl/afl_driver.cpp
+++ compiler-rt/lib/fuzzer/afl/afl_driver.cpp
@@ -111,7 +111,7 @@
// Use this optionally defined function to output sanitizer messages even if
// user asks to close stderr.
-extern "C" __attribute__((weak)) void __sanitizer_set_report_fd(void *);
+__attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *);
// Keep track of where stderr content is being written to, so that
// dup_and_close_stderr can use the correct one.
Index: clang/unittests/StaticAnalyzer/ParamRegionTest.cpp
===================================================================
--- /dev/null
+++ clang/unittests/StaticAnalyzer/ParamRegionTest.cpp
@@ -0,0 +1,109 @@
+//===- unittests/StaticAnalyzer/ParamRegionTest.cpp -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Reusables.h"
+
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+class ParamRegionTestConsumer : public ExprEngineConsumer {
+ void performTest(const Decl *D) {
+ StoreManager &StMgr = Eng.getStoreManager();
+ MemRegionManager &MRMgr = StMgr.getRegionManager();
+ const StackFrameContext *SFC =
+ Eng.getAnalysisDeclContextManager().getStackFrame(D);
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ for (const auto *P : FD->parameters()) {
+ const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC);
+ if (SFC->inTopFrame())
+ assert(isa<NonParamVarRegion>(Reg));
+ else
+ assert(isa<ParamVarRegion>(Reg));
+ }
+ } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
+ for (const auto *P : CD->parameters()) {
+ const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC);
+ if (SFC->inTopFrame())
+ assert(isa<NonParamVarRegion>(Reg));
+ else
+ assert(isa<ParamVarRegion>(Reg));
+ }
+ } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ for (const auto *P : MD->parameters()) {
+ const TypedValueRegion *Reg = MRMgr.getVarRegion(P, SFC);
+ if (SFC->inTopFrame())
+ assert(isa<NonParamVarRegion>(Reg));
+ else
+ assert(isa<ParamVarRegion>(Reg));
+ }
+ }
+ }
+
+public:
+ ParamRegionTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ for (const auto *D : DG) {
+ performTest(D);
+ }
+ return true;
+ }
+};
+
+class ParamRegionTestAction : public ASTFrontendAction {
+public:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ return std::make_unique<ParamRegionTestConsumer>(Compiler);
+ }
+};
+
+TEST(ParamRegion, ParamRegionTest) {
+ EXPECT_TRUE(
+ tooling::runToolOnCode(std::make_unique<ParamRegionTestAction>(),
+ R"(void foo(int n) {
+ auto lambda = [n](int m) {
+ return n + m;
+ };
+
+ int k = lambda(2);
+ }
+
+ void bar(int l) {
+ foo(l);
+ }
+
+ struct S {
+ int n;
+ S(int nn): n(nn) {}
+ };
+
+ void baz(int p) {
+ S s(p);
+ })"));
+ EXPECT_TRUE(
+ tooling::runToolOnCode(std::make_unique<ParamRegionTestAction>(),
+ R"(@interface O
+ + alloc;
+ - initWithInt:(int)q;
+ @end
+
+ void qix(int r) {
+ O *o = [[O alloc] initWithInt:r];
+ })",
+ "input.m"));
+}
+
+} // namespace
+} // namespace ento
+} // namespace clang
Index: clang/unittests/StaticAnalyzer/CMakeLists.txt
===================================================================
--- clang/unittests/StaticAnalyzer/CMakeLists.txt
+++ clang/unittests/StaticAnalyzer/CMakeLists.txt
@@ -8,6 +8,7 @@
CallDescriptionTest.cpp
CallEventTest.cpp
StoreTest.cpp
+ ParamRegionTest.cpp
RegisterCustomCheckersTest.cpp
SymbolReaperTest.cpp
RangeSetTest.cpp
Index: clang/test/Analysis/explain-svals.m
===================================================================
--- clang/test/Analysis/explain-svals.m
+++ clang/test/Analysis/explain-svals.m
@@ -28,3 +28,44 @@
};
clang_analyzer_explain(&x); // expected-warning-re{{{{^pointer to block variable 'x'$}}}}
}
+
+@interface O
++ (instancetype)top_level_class_method:(int)param;
++ (instancetype)non_top_level_class_method:(int)param;
+- top_level_instance_method:(int)param;
+- non_top_level_instance_method:(int)param;
+@end
+
+@implementation O
++ (instancetype)top_level_class_method:(int)param {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
++ (instancetype)non_top_level_class_method:(int)param {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
+- top_level_instance_method:(int)param {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
+- non_top_level_instance_method:(int)param {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+@end
+
+void test_3(int n, int m) {
+ O *o = [O non_top_level_class_method:n];
+ [o non_top_level_instance_method:m];
+
+ void (^block_top_level)(int) = ^(int param) {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+ clang_analyzer_explain(&n); // expected-warning-re{{{{^pointer to parameter 'n'$}}}}
+ };
+ void (^block_non_top_level)(int) = ^(int param) {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+ clang_analyzer_explain(&n); // expected-warning-re{{{{^pointer to parameter 'n'$}}}}
+ };
+
+ block_non_top_level(n);
+}
Index: clang/test/Analysis/explain-svals.cpp
===================================================================
--- clang/test/Analysis/explain-svals.cpp
+++ clang/test/Analysis/explain-svals.cpp
@@ -19,6 +19,7 @@
void clang_analyzer_explain(int);
void clang_analyzer_explain(void *);
+void clang_analyzer_explain(const int *);
void clang_analyzer_explain(S);
size_t clang_analyzer_getExtent(void *);
@@ -100,3 +101,30 @@
clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of temporary object constructed at statement 'conjure_S\(\)'$}}}}
clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
}
+
+class C_top_level {
+public:
+ C_top_level(int param) {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+ }
+};
+
+class C_non_top_level {
+public:
+ C_non_top_level(int param) {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+ }
+};
+
+void test_7(int n) {
+ C_non_top_level c(n);
+
+ auto lambda_top_level = [n](int param) {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+ };
+ auto lambda_non_top_level = [n](int param) {
+ clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+ };
+
+ lambda_non_top_level(n);
+}
Index: clang/test/Analysis/explain-svals.c
===================================================================
--- clang/test/Analysis/explain-svals.c
+++ clang/test/Analysis/explain-svals.c
@@ -27,3 +27,15 @@
clang_analyzer_explain_voidp(&s); // expected-warning-re{{{{^pointer to parameter 's'$}}}}
clang_analyzer_explain_int(s.z); // expected-warning-re{{{{^initial value of field 'z' of parameter 's'$}}}}
}
+
+void test_3(int param) {
+ clang_analyzer_explain_voidp(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
+void test_non_top_level(int param) {
+ clang_analyzer_explain_voidp(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
+}
+
+void test_4(int n) {
+ test_non_top_level(n);
+}
Index: clang/lib/StaticAnalyzer/Core/Store.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/Store.cpp
+++ clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -134,7 +134,8 @@
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
case MemRegion::ObjCStringRegionKind:
- case MemRegion::VarRegionKind:
+ case MemRegion::NonParamVarRegionKind:
+ case MemRegion::ParamVarRegionKind:
case MemRegion::CXXTempObjectRegionKind:
case MemRegion::CXXBaseObjectRegionKind:
case MemRegion::CXXDerivedObjectRegionKind:
Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -160,11 +160,9 @@
}
ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
- : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
+ : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {}
-const ObjCIvarDecl *ObjCIvarRegion::getDecl() const {
- return cast<ObjCIvarDecl>(D);
-}
+const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { return IVD; }
QualType ObjCIvarRegion::getValueType() const {
return getDecl()->getType();
@@ -178,6 +176,33 @@
return QualType(getDecl()->getTypeForDecl(), 0);
}
+QualType ParamVarRegion::getValueType() const {
+ assert(getDecl() &&
+ "`ParamVarRegion` support functions without `Decl` not implemented"
+ " yet.");
+ return getDecl()->getType();
+}
+
+const ParmVarDecl *ParamVarRegion::getDecl() const {
+ const Decl *D = getStackFrame()->getDecl();
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ assert(Index < FD->param_size());
+ return FD->parameters()[Index];
+ } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+ assert(Index < BD->param_size());
+ return BD->parameters()[Index];
+ } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ assert(Index < MD->param_size());
+ return MD->parameters()[Index];
+ } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
+ assert(Index < CD->param_size());
+ return CD->parameters()[Index];
+ } else {
+ llvm_unreachable("Unexpected Decl kind!");
+ }
+}
+
//===----------------------------------------------------------------------===//
// FoldingSet profiling.
//===----------------------------------------------------------------------===//
@@ -249,25 +274,44 @@
CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
}
+void FieldRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getDecl(), superRegion);
+}
+
void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const ObjCIvarDecl *ivd,
const MemRegion* superRegion) {
- DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
+ ID.AddInteger(static_cast<unsigned>(ObjCIvarRegionKind));
+ ID.AddPointer(ivd);
+ ID.AddPointer(superRegion);
+}
+
+void ObjCIvarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getDecl(), superRegion);
}
-void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
- const MemRegion* superRegion, Kind k) {
- ID.AddInteger(static_cast<unsigned>(k));
- ID.AddPointer(D);
+void NonParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const VarDecl *VD,
+ const MemRegion *superRegion) {
+ ID.AddInteger(static_cast<unsigned>(NonParamVarRegionKind));
+ ID.AddPointer(VD);
ID.AddPointer(superRegion);
}
-void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- DeclRegion::ProfileRegion(ID, D, superRegion, getKind());
+void NonParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getDecl(), superRegion);
}
-void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- VarRegion::ProfileRegion(ID, getDecl(), superRegion);
+void ParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE,
+ unsigned Idx, const MemRegion *SReg) {
+ ID.AddInteger(static_cast<unsigned>(ParamVarRegionKind));
+ ID.AddPointer(OE);
+ ID.AddInteger(Idx);
+ ID.AddPointer(SReg);
+}
+
+void ParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getOriginExpr(), getIndex(), superRegion);
}
void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
@@ -479,12 +523,11 @@
os << "SymRegion{" << sym << '}';
}
-void VarRegion::dumpToStream(raw_ostream &os) const {
- const auto *VD = cast<VarDecl>(D);
+void NonParamVarRegion::dumpToStream(raw_ostream &os) const {
if (const IdentifierInfo *ID = VD->getIdentifier())
os << ID->getName();
else
- os << "VarRegion{D" << VD->getID() << '}';
+ os << "NonParamVarRegion{D" << VD->getID() << '}';
}
LLVM_DUMP_METHOD void RegionRawOffset::dump() const {
@@ -531,6 +574,18 @@
os << "StackLocalsSpaceRegion";
}
+void ParamVarRegion::dumpToStream(raw_ostream &os) const {
+ const ParmVarDecl *PVD = getDecl();
+ assert(PVD &&
+ "`ParamVarRegion` support functions without `Decl` not implemented"
+ " yet.");
+ if (const IdentifierInfo *ID = PVD->getIdentifier()) {
+ os << ID->getName();
+ } else {
+ os << "ParamVarRegion{P" << PVD->getID() << '}';
+ }
+}
+
bool MemRegion::canPrintPretty() const {
return canPrintPrettyAsExpr();
}
@@ -550,11 +605,18 @@
llvm_unreachable("This region cannot be printed pretty.");
}
-bool VarRegion::canPrintPrettyAsExpr() const {
- return true;
+bool NonParamVarRegion::canPrintPrettyAsExpr() const { return true; }
+
+void NonParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+ os << getDecl()->getName();
}
-void VarRegion::printPrettyAsExpr(raw_ostream &os) const {
+bool ParamVarRegion::canPrintPrettyAsExpr() const { return true; }
+
+void ParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+ assert(getDecl() &&
+ "`ParamVarRegion` support functions without `Decl` not implemented"
+ " yet.");
os << getDecl()->getName();
}
@@ -693,7 +755,8 @@
case MemRegion::CXXTempObjectRegionKind:
case MemRegion::CXXThisRegionKind:
case MemRegion::ObjCIvarRegionKind:
- case MemRegion::VarRegionKind:
+ case MemRegion::NonParamVarRegionKind:
+ case MemRegion::ParamVarRegionKind:
case MemRegion::ElementRegionKind:
case MemRegion::ObjCStringRegionKind: {
QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
@@ -847,9 +910,11 @@
for (BlockDataRegion::referenced_vars_iterator
I = BR->referenced_vars_begin(),
E = BR->referenced_vars_end(); I != E; ++I) {
- const VarRegion *VR = I.getOriginalRegion();
- if (VR->getDecl() == VD)
- return cast<VarRegion>(I.getCapturedRegion());
+ const TypedValueRegion *OrigR = I.getOriginalRegion();
+ if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {
+ if (VR->getDecl() == VD)
+ return cast<VarRegion>(I.getCapturedRegion());
+ }
}
}
@@ -858,8 +923,30 @@
return (const StackFrameContext *)nullptr;
}
-const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
+const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
const LocationContext *LC) {
+ const auto *PVD = dyn_cast<ParmVarDecl>(D);
+ if (PVD) {
+ unsigned Index = PVD->getFunctionScopeIndex();
+ const StackFrameContext *SFC = LC->getStackFrame();
+ const Stmt *CallSite = SFC->getCallSite();
+ if (CallSite) {
+ const Decl *D = SFC->getDecl();
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (Index < FD->param_size() && FD->parameters()[Index] == PVD)
+ return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+ getStackArgumentsRegion(SFC));
+ } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+ if (Index < BD->param_size() && BD->parameters()[Index] == PVD)
+ return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+ getStackArgumentsRegion(SFC));
+ } else {
+ return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+ getStackArgumentsRegion(SFC));
+ }
+ }
+ }
+
D = D->getCanonicalDecl();
const MemRegion *sReg = nullptr;
@@ -942,13 +1029,23 @@
}
}
- return getSubRegion<VarRegion>(D, sReg);
+ return getSubRegion<NonParamVarRegion>(D, sReg);
}
-const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
- const MemRegion *superR) {
+const NonParamVarRegion *
+MemRegionManager::getNonParamVarRegion(const VarDecl *D,
+ const MemRegion *superR) {
D = D->getCanonicalDecl();
- return getSubRegion<VarRegion>(D, superR);
+ return getSubRegion<NonParamVarRegion>(D, superR);
+}
+
+const ParamVarRegion *
+MemRegionManager::getParamVarRegion(const Expr *OriginExpr, unsigned Index,
+ const LocationContext *LC) {
+ const StackFrameContext *SFC = LC->getStackFrame();
+ assert(SFC);
+ return getSubRegion<ParamVarRegion>(OriginExpr, Index,
+ getStackArgumentsRegion(SFC));
}
const BlockDataRegion *
@@ -1341,7 +1438,8 @@
case MemRegion::CXXThisRegionKind:
case MemRegion::StringRegionKind:
case MemRegion::ObjCStringRegionKind:
- case MemRegion::VarRegionKind:
+ case MemRegion::NonParamVarRegionKind:
+ case MemRegion::ParamVarRegionKind:
case MemRegion::CXXTempObjectRegionKind:
// Usual base regions.
goto Finish;
@@ -1497,7 +1595,7 @@
const VarRegion *OriginalVR = nullptr;
if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) {
- VR = MemMgr.getVarRegion(VD, this);
+ VR = MemMgr.getNonParamVarRegion(VD, this);
OriginalVR = MemMgr.getVarRegion(VD, LC);
}
else {
@@ -1506,7 +1604,7 @@
OriginalVR = VR;
}
else {
- VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+ VR = MemMgr.getNonParamVarRegion(VD, MemMgr.getUnknownRegion());
OriginalVR = MemMgr.getVarRegion(VD, LC);
}
}
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -342,12 +342,12 @@
// Operator arguments do not correspond to operator parameters
// because this-argument is implemented as a normal argument in
// operator call expressions but not in operator declarations.
- const VarRegion *VR = Caller->getParameterLocation(
+ const TypedValueRegion *TVR = Caller->getParameterLocation(
*Caller->getAdjustedParameterIndex(Idx), currBldrCtx->blockCount());
- if (!VR)
+ if (!TVR)
return None;
- return loc::MemRegionVal(VR);
+ return loc::MemRegionVal(TVR);
};
if (const auto *CE = dyn_cast<CallExpr>(E)) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -218,7 +218,7 @@
auto CE = BD->capture_end();
for (; I != E; ++I) {
const VarRegion *capturedR = I.getCapturedRegion();
- const VarRegion *originalR = I.getOriginalRegion();
+ const TypedValueRegion *originalR = I.getOriginalRegion();
// If the capture had a copy expression, use the result of evaluating
// that expression, otherwise use the original value.
Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -222,39 +222,17 @@
return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, BlockCount, Idx);
}
-const VarRegion *CallEvent::getParameterLocation(unsigned Index,
- unsigned BlockCount) const {
+const ParamVarRegion
+*CallEvent::getParameterLocation(unsigned Index, unsigned BlockCount) const {
const StackFrameContext *SFC = getCalleeStackFrame(BlockCount);
// We cannot construct a VarRegion without a stack frame.
if (!SFC)
return nullptr;
- // Retrieve parameters of the definition, which are different from
- // CallEvent's parameters() because getDecl() isn't necessarily
- // the definition. SFC contains the definition that would be used
- // during analysis.
- const Decl *D = SFC->getDecl();
-
- // TODO: Refactor into a virtual method of CallEvent, like parameters().
- const ParmVarDecl *PVD = nullptr;
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- PVD = FD->parameters()[Index];
- else if (const auto *BD = dyn_cast<BlockDecl>(D))
- PVD = BD->parameters()[Index];
- else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
- PVD = MD->parameters()[Index];
- else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D))
- PVD = CD->parameters()[Index];
- assert(PVD && "Unexpected Decl kind!");
-
- const VarRegion *VR =
- State->getStateManager().getRegionManager().getVarRegion(PVD, SFC);
-
- // This sanity check would fail if our parameter declaration doesn't
- // correspond to the stack frame's function declaration.
- assert(VR->getStackFrame() == SFC);
-
- return VR;
+ const ParamVarRegion *PVR =
+ State->getStateManager().getRegionManager().getParamVarRegion(
+ getOriginExpr(), Index, SFC);
+ return PVR;
}
/// Returns true if a type is a pointer-to-const or reference-to-const
@@ -325,8 +303,9 @@
if (getKind() != CE_CXXAllocator)
if (isArgumentConstructedDirectly(Idx))
if (auto AdjIdx = getAdjustedParameterIndex(Idx))
- if (const VarRegion *VR = getParameterLocation(*AdjIdx, BlockCount))
- ValuesToInvalidate.push_back(loc::MemRegionVal(VR));
+ if (const TypedValueRegion *TVR =
+ getParameterLocation(*AdjIdx, BlockCount))
+ ValuesToInvalidate.push_back(loc::MemRegionVal(TVR));
}
// Invalidate designated regions using the batch invalidation API.
@@ -527,7 +506,8 @@
// which makes getArgSVal() fail and return UnknownVal.
SVal ArgVal = Call.getArgSVal(Idx);
if (!ArgVal.isUnknown()) {
- Loc ParamLoc = SVB.makeLoc(MRMgr.getVarRegion(ParamDecl, CalleeCtx));
+ Loc ParamLoc = SVB.makeLoc(
+ MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx));
Bindings.push_back(std::make_pair(ParamLoc, ArgVal));
}
}
Index: clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -709,7 +709,8 @@
case MemRegion::SymbolicRegionKind:
case MemRegion::AllocaRegionKind:
- case MemRegion::VarRegionKind:
+ case MemRegion::NonParamVarRegionKind:
+ case MemRegion::ParamVarRegionKind:
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
// These are the types we can currently track string lengths for.
@@ -814,7 +815,8 @@
}
case MemRegion::SymbolicRegionKind:
case MemRegion::AllocaRegionKind:
- case MemRegion::VarRegionKind:
+ case MemRegion::NonParamVarRegionKind:
+ case MemRegion::ParamVarRegionKind:
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
return getCStringLengthForRegion(C, state, Ex, MR, hypothetical);
@@ -1009,10 +1011,14 @@
os << "a C++ temp object of type "
<< cast<TypedValueRegion>(MR)->getValueType().getAsString();
return true;
- case MemRegion::VarRegionKind:
+ case MemRegion::NonParamVarRegionKind:
os << "a variable of type"
<< cast<TypedValueRegion>(MR)->getValueType().getAsString();
return true;
+ case MemRegion::ParamVarRegionKind:
+ os << "a parameter of type"
+ << cast<TypedValueRegion>(MR)->getValueType().getAsString();
+ return true;
case MemRegion::FieldRegionKind:
os << "a field of type "
<< cast<TypedValueRegion>(MR)->getValueType().getAsString();
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
@@ -73,9 +73,13 @@
ABSTRACT_REGION(DeclRegion, TypedValueRegion)
REGION(FieldRegion, DeclRegion)
REGION(ObjCIvarRegion, DeclRegion)
- REGION(VarRegion, DeclRegion)
- REGION_RANGE(DECL_REGIONS, FieldRegionKind,
- VarRegionKind)
+ ABSTRACT_REGION(VarRegion, DeclRegion)
+ REGION(NonParamVarRegion, VarRegion)
+ REGION(ParamVarRegion, VarRegion)
+ REGION_RANGE(VAR_REGIONS, NonParamVarRegionKind,
+ ParamVarRegionKind)
+ REGION_RANGE(DECL_REGIONS, FieldRegionKind,
+ ParamVarRegionKind)
REGION(ElementRegion, TypedValueRegion)
REGION(ObjCStringRegion, TypedValueRegion)
REGION(StringRegion, TypedValueRegion)
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -308,6 +308,10 @@
Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
bool IsVirtual) const;
+ /// Get the lvalue for a parameter.
+ Loc getLValue(const Expr *Call, unsigned Index,
+ const LocationContext *LC) const;
+
/// Get the lvalue for a variable reference.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -890,20 +890,12 @@
class DeclRegion : public TypedValueRegion {
protected:
- const ValueDecl *D;
-
- DeclRegion(const ValueDecl *d, const MemRegion *sReg, Kind k)
- : TypedValueRegion(sReg, k), D(d) {
+ DeclRegion(const MemRegion *sReg, Kind k) : TypedValueRegion(sReg, k) {
assert(classof(this));
- assert(d && d->isCanonicalDecl());
}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
- const MemRegion* superRegion, Kind k);
-
public:
- const ValueDecl *getDecl() const { return D; }
- void Profile(llvm::FoldingSetNodeID& ID) const override;
+ virtual const ValueDecl *getDecl() const = 0;
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
@@ -914,9 +906,9 @@
class VarRegion : public DeclRegion {
friend class MemRegionManager;
- // Constructors and private methods.
- VarRegion(const VarDecl *vd, const MemRegion *sReg)
- : DeclRegion(vd, sReg, VarRegionKind) {
+protected:
+ // Constructors and protected methods.
+ VarRegion(const MemRegion *sReg, Kind k) : DeclRegion(sReg, k) {
// VarRegion appears in unknown space when it's a block variable as seen
// from a block using it, when this block is analyzed at top-level.
// Other block variables appear within block data regions,
@@ -925,17 +917,45 @@
isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
- const MemRegion *superRegion) {
- DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
+public:
+ const VarDecl *getDecl() const override = 0;
+
+ const StackFrameContext *getStackFrame() const;
+
+ QualType getValueType() const override {
+ // FIXME: We can cache this if needed.
+ return getDecl()->getType();
}
-public:
- void Profile(llvm::FoldingSetNodeID& ID) const override;
+ static bool classof(const MemRegion *R) {
+ unsigned k = R->getKind();
+ return k >= BEGIN_VAR_REGIONS && k <= END_VAR_REGIONS;
+ }
+};
+
+class NonParamVarRegion : public VarRegion {
+ friend class MemRegionManager;
- const VarDecl *getDecl() const { return cast<VarDecl>(D); }
+ const VarDecl *VD;
- const StackFrameContext *getStackFrame() const;
+ // Constructors and private methods.
+ NonParamVarRegion(const VarDecl *vd, const MemRegion *sReg)
+ : VarRegion(sReg, NonParamVarRegionKind), VD(vd) {
+ // VarRegion appears in unknown space when it's a block variable as seen
+ // from a block using it, when this block is analyzed at top-level.
+ // Other block variables appear within block data regions,
+ // which, unlike everything else on this list, are not memory spaces.
+ assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) ||
+ isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID, const VarDecl *VD,
+ const MemRegion *superRegion);
+
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ const VarDecl *getDecl() const override { return VD; }
QualType getValueType() const override {
// FIXME: We can cache this if needed.
@@ -949,7 +969,49 @@
void printPrettyAsExpr(raw_ostream &os) const override;
static bool classof(const MemRegion* R) {
- return R->getKind() == VarRegionKind;
+ return R->getKind() == NonParamVarRegionKind;
+ }
+};
+
+/// ParamVarRegion - Represents a region for paremters. Only parameters of the
+/// function in the current stack frame are represented as `ParamVarRegion`s.
+/// Parameters of top-level analyzed functions as well as captured paremeters
+/// by lambdas and blocks are repesented as `VarRegion`s.
+
+// FIXME: `ParamVarRegion` only supports parameters of functions, C++
+// constructors, blocks and Objective-C methods with existing `Decl`. Upon
+// implementing stack frame creations for functions without decl (functions
+// passed by function pointer) methods of `ParamVarRegion` must be updated.
+class ParamVarRegion : public VarRegion {
+ friend class MemRegionManager;
+
+ const Expr *OriginExpr;
+ unsigned Index;
+
+ ParamVarRegion(const Expr *OE, unsigned Idx, const MemRegion *SReg)
+ : VarRegion(SReg, ParamVarRegionKind), OriginExpr(OE), Index(Idx) {
+ assert(!cast<StackSpaceRegion>(SReg)->getStackFrame()->inTopFrame());
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE,
+ unsigned Idx, const MemRegion *SReg);
+
+public:
+ const Expr *getOriginExpr() const { return OriginExpr; }
+ unsigned getIndex() const { return Index; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
+ void dumpToStream(raw_ostream &os) const override;
+
+ QualType getValueType() const override;
+ const ParmVarDecl *getDecl() const override;
+
+ bool canPrintPrettyAsExpr() const override;
+ void printPrettyAsExpr(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == ParamVarRegionKind;
}
};
@@ -991,16 +1053,22 @@
class FieldRegion : public DeclRegion {
friend class MemRegionManager;
- FieldRegion(const FieldDecl *fd, const SubRegion* sReg)
- : DeclRegion(fd, sReg, FieldRegionKind) {}
+ const FieldDecl *FD;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
+ FieldRegion(const FieldDecl *fd, const SubRegion *sReg)
+ : DeclRegion(sReg, FieldRegionKind), FD(fd) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID, const FieldDecl *FD,
const MemRegion* superRegion) {
- DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
+ ID.AddInteger(static_cast<unsigned>(FieldRegionKind));
+ ID.AddPointer(FD);
+ ID.AddPointer(superRegion);
}
public:
- const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
+ const FieldDecl *getDecl() const override { return FD; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
QualType getValueType() const override {
// FIXME: We can cache this if needed.
@@ -1022,6 +1090,8 @@
class ObjCIvarRegion : public DeclRegion {
friend class MemRegionManager;
+ const ObjCIvarDecl *IVD;
+
ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg);
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
@@ -1029,6 +1099,9 @@
public:
const ObjCIvarDecl *getDecl() const;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const override;
+
QualType getValueType() const override;
bool canPrintPrettyAsExpr() const override;
@@ -1312,11 +1385,18 @@
/// getVarRegion - Retrieve or create the memory region associated with
/// a specified VarDecl and LocationContext.
- const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC);
+ const VarRegion *getVarRegion(const VarDecl *VD, const LocationContext *LC);
/// getVarRegion - Retrieve or create the memory region associated with
- /// a specified VarDecl and super region.
- const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR);
+ /// a specified VarDecl and LocationContext.
+ const NonParamVarRegion *getNonParamVarRegion(const VarDecl *VD,
+ const MemRegion *superR);
+
+ /// getParamVarRegion - Retrieve or create the memory region
+ /// associated with a specified CallExpr, Index and LocationContext.
+ const ParamVarRegion *getParamVarRegion(const Expr *OriginExpr,
+ unsigned Index,
+ const LocationContext *LC);
/// getElementRegion - Retrieve the memory region associated with the
/// associated element type, index, and super region.
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -97,7 +97,7 @@
class SwitchNodeBuilder;
class ExprEngine {
- void anchor();
+ virtual void anchor();
public:
/// The modes of inlining, which override the default analysis-wide settings.
enum InliningModes {
@@ -177,7 +177,7 @@
SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS, InliningModes HowToInlineIn);
- virtual ~ExprEngine() = default;
+ ~ExprEngine() = default;
/// Returns true if there is still simulation state on the worklist.
bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -403,8 +403,8 @@
/// Returns memory location for a parameter variable within the callee stack
/// frame. May fail; returns null on failure.
- const VarRegion *getParameterLocation(unsigned Index,
- unsigned BlockCount) const;
+ const ParamVarRegion *getParameterLocation(unsigned Index,
+ unsigned BlockCount) const;
/// Returns true if on the current path, the argument was constructed by
/// calling a C++ constructor over it. This is an internal detail of the
Index: clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -18,6 +18,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
+#include "llvm/ADT/StringExtras.h"
namespace clang {
@@ -179,7 +180,7 @@
return OS.str();
}
- std::string VisitVarRegion(const VarRegion *R) {
+ std::string VisitNonParamVarRegion(const NonParamVarRegion *R) {
const VarDecl *VD = R->getDecl();
std::string Name = VD->getQualifiedNameAsString();
if (isa<ParmVarDecl>(VD))
@@ -216,6 +217,39 @@
"' inside " + Visit(R->getSuperRegion());
}
+ std::string VisitParamVarRegion(const ParamVarRegion *R) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+
+ const ParmVarDecl *PVD = R->getDecl();
+ std::string Name = PVD->getQualifiedNameAsString();
+ if (!Name.empty()) {
+ OS << "parameter '" << Name << "'";
+ return std::string(OS.str());
+ }
+
+ unsigned Index = R->getIndex() + 1;
+ OS << Index << llvm::getOrdinalSuffix(Index) << " of parameter ";
+ const Decl *Parent = R->getStackFrame()->getDecl();
+ if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
+ OS << "function '" << FD->getQualifiedNameAsString() << "()'";
+ else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
+ OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
+ else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
+ if (MD->isClassMethod())
+ OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
+ else
+ OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
+ } else if (isa<BlockDecl>(Parent)) {
+ if (cast<BlockDecl>(Parent)->isConversionFromLambda())
+ OS << "lambda";
+ else
+ OS << "block";
+ }
+
+ return std::string(OS.str());
+ }
+
std::string VisitSVal(SVal V) {
std::string Str;
llvm::raw_string_ostream OS(Str);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits