Skip to content

Commit a69c247

Browse files
authored
[-Wcompletion-handler] Fix a non-termination issue (llvm#78380) (#8082)
The Called-Once dataflow analysis could never terminate as a consequence of non-monotonic update on states. States of kind Escape can override states leading to non-monotonic update. This fix disallows the `Escape` state to override the `Reported` state. rdar://119671856 (cherry picked from commit 2a06850)
1 parent 792b01b commit a69c247

File tree

2 files changed

+13
-2
lines changed

2 files changed

+13
-2
lines changed

clang/lib/Analysis/CalledOnceCheck.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ class ParameterStatus {
163163
NotVisited = 0x8, /* 1000 */
164164
// We already reported a violation and stopped tracking calls for this
165165
// parameter.
166-
Reported = 0x15, /* 1111 */
166+
Reported = 0xF, /* 1111 */
167167
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Reported)
168168
};
169169

@@ -932,7 +932,8 @@ class CalledOnceChecker : public ConstStmtVisitor<CalledOnceChecker> {
932932
ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index);
933933

934934
// Escape overrides whatever error we think happened.
935-
if (CurrentParamStatus.isErrorStatus()) {
935+
if (CurrentParamStatus.isErrorStatus() &&
936+
CurrentParamStatus.getKind() != ParameterStatus::Kind::Reported) {
936937
CurrentParamStatus = ParameterStatus::Escaped;
937938
}
938939
}

clang/test/SemaObjC/warn-called-once.m

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,16 @@ - (void)test_escape_after_branch:(int)cond
11951195
}
11961196

11971197
// rdar://74441906
1198+
- (void)test_termination:(int)cond
1199+
withCompletion:(void (^)(void))handler {
1200+
// The code below was able to cause non-termination but should be
1201+
// fixed now:
1202+
do {
1203+
escape(handler);
1204+
handler(); // expected-warning{{completion handler is called twice}} expected-note{{previous call is here; set to nil to indicate it cannot be called afterwards}}
1205+
} while (cond);
1206+
}
1207+
11981208
typedef void (^DeferredBlock)(void);
11991209
static inline void DefferedCallback(DeferredBlock *inBlock) { (*inBlock)(); }
12001210
#define _DEFERCONCAT(a, b) a##b

0 commit comments

Comments
 (0)