aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/StaticAnalyzer
diff options
context:
space:
mode:
Diffstat (limited to 'clang/unittests/StaticAnalyzer')
-rw-r--r--clang/unittests/StaticAnalyzer/CallEventTest.cpp41
1 files changed, 41 insertions, 0 deletions
diff --git a/clang/unittests/StaticAnalyzer/CallEventTest.cpp b/clang/unittests/StaticAnalyzer/CallEventTest.cpp
index 8b5289e..f426892 100644
--- a/clang/unittests/StaticAnalyzer/CallEventTest.cpp
+++ b/clang/unittests/StaticAnalyzer/CallEventTest.cpp
@@ -84,6 +84,47 @@ TEST(CXXDeallocatorCall, SimpleDestructor) {
#endif
}
+TEST(PrivateMethodCache, NeverReturnDanglingPointersWithMultipleASTs) {
+ // Each iteration will load and unload an AST multiple times. Since the code
+ // is always the same, we increase the chance of hitting a bug in the private
+ // method cache, returning a dangling pointer and crashing the process. If the
+ // cache is properly cleared between runs, the test should pass.
+ for (int I = 0; I < 100; ++I) {
+ auto const *Code = R"(
+ typedef __typeof(sizeof(int)) size_t;
+
+ extern void *malloc(size_t size);
+ extern void *memcpy(void *dest, const void *src, size_t n);
+
+ @interface SomeMoreData {
+ char const* _buffer;
+ int _size;
+ }
+ @property(nonatomic, readonly) const char* buffer;
+ @property(nonatomic) int size;
+
+ - (void)appendData:(SomeMoreData*)other;
+
+ @end
+
+ @implementation SomeMoreData
+ @synthesize size = _size;
+ @synthesize buffer = _buffer;
+
+ - (void)appendData:(SomeMoreData*)other {
+ int const len = (_size + other.size); // implicit self._length
+ char* d = malloc(sizeof(char) * len);
+ memcpy(d + 20, other.buffer, len);
+ }
+
+ @end
+ )";
+ std::string Diags;
+ EXPECT_TRUE(runCheckerOnCodeWithArgs<addCXXDeallocatorChecker>(
+ Code, {"-x", "objective-c", "-Wno-objc-root-class"}, Diags));
+ }
+}
+
} // namespace
} // namespace ento
} // namespace clang