Skip to content

Commit b932fb6

Browse files
committed
[StaticAnalyzer] Add reproducers for a bug in VisitObjCForCollectionStmt
The bug (see llvm#124477) in VisitObjCForCollectionStmt seems have been there for a long time and can be very rarely triggered. Now adding tests that reproduce it. The integrated test is reduced from a crash observed downstream that reproduces the bug. The unit test is contributed by Balazs Benics (@steakhal) for helping reproducing the bug. Much thanks to their help. Commit this test on behalf of them. (rdar://143280254)
1 parent 95d993a commit b932fb6

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=core,apiModeling,nullability.NullableDereferenced,nullability.NullabilityBase -x objective-c %s
2+
/*
3+
This test is reduced from a static analyzer crash. The bug causing
4+
the crash is explained in #124477. It can only be triggered in some
5+
rare cases so please do not modify this reproducer.
6+
*/
7+
8+
#pragma clang assume_nonnull begin
9+
# 15 "some-sys-header.h" 1 3
10+
@class NSArray, NSObject;
11+
12+
@interface Base
13+
@property (readonly, copy) NSArray *array;
14+
@end
15+
16+
#pragma clang assume_nonnull end
17+
# 8 "this-file.m" 2
18+
19+
20+
@interface Test : Base
21+
22+
@property (readwrite, copy, nullable) NSObject *label;
23+
@property (readwrite, strong, nullable) Test * field;
24+
25+
- (void)f;
26+
27+
@end
28+
29+
@implementation Test
30+
- (void)f
31+
{
32+
NSObject * X;
33+
34+
for (NSObject *ele in self.field.array) {}
35+
self.label = X;
36+
}
37+
@end
38+
39+

clang/unittests/StaticAnalyzer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_clang_unittest(StaticAnalysisTests
1515
IsCLibraryFunctionTest.cpp
1616
MemRegionDescriptiveNameTest.cpp
1717
NoStateChangeFuncVisitorTest.cpp
18+
ObjcBug-124477.cpp
1819
ParamRegionTest.cpp
1920
RangeSetTest.cpp
2021
RegisterCustomCheckersTest.cpp
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// This test is contributed by @steakhal to help reproducing the bug reported in
10+
// #124477.
11+
12+
#include "CheckerRegistration.h"
13+
#include "clang/StaticAnalyzer/Core/Checker.h"
14+
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
15+
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
16+
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
17+
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
18+
#include "gtest/gtest.h"
19+
20+
using namespace clang;
21+
using namespace ento;
22+
23+
// Some dummy trait that we can mutate back and forth to force a new State.
24+
REGISTER_TRAIT_WITH_PROGRAMSTATE(Flag, bool)
25+
26+
namespace {
27+
class FlipFlagOnCheckLocation : public Checker<check::Location> {
28+
public:
29+
// We make sure we alter the State every time we model a checkLocation event.
30+
void checkLocation(SVal l, bool isLoad, const Stmt *S,
31+
CheckerContext &C) const {
32+
ProgramStateRef State = C.getState();
33+
State = State->set<Flag>(!State->get<Flag>());
34+
C.addTransition(State);
35+
}
36+
};
37+
38+
void addFlagFlipperChecker(AnalysisASTConsumer &AnalysisConsumer,
39+
AnalyzerOptions &AnOpts) {
40+
AnOpts.CheckersAndPackages = {{"test.FlipFlagOnCheckLocation", true}};
41+
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
42+
Registry.addChecker<FlipFlagOnCheckLocation>("test.FlipFlagOnCheckLocation",
43+
"Description", "");
44+
});
45+
}
46+
47+
TEST(ObjCTest, CheckLocationEventsShouldMaterializeInObjCForCollectionStmts) {
48+
// Previously, the `ExprEngine::hasMoreIteration` may fired an assertion
49+
// because we forgot to handle correctly the resulting nodes of the
50+
// check::Location callback for the ObjCForCollectionStmts.
51+
// This caused inconsistencies in the graph and triggering the assertion.
52+
// See #124477 for more details.
53+
std::string Diags;
54+
EXPECT_TRUE(runCheckerOnCodeWithArgs<addFlagFlipperChecker>(
55+
R"(
56+
@class NSArray, NSDictionary, NSString;
57+
extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
58+
void entrypoint(NSArray *bowl) {
59+
for (NSString *fruit in bowl) { // no-crash
60+
NSLog(@"Fruit: %@", fruit);
61+
}
62+
})",
63+
{"-x", "objective-c"}, Diags));
64+
}
65+
66+
} // namespace

0 commit comments

Comments
 (0)