Skip to content

Commit 2a06850

Browse files
authored
[-Wcompletion-handler] Fix a non-termination issue (#78380)
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
1 parent 6c74d80 commit 2a06850

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
@@ -1194,6 +1194,16 @@ - (void)test_escape_after_branch:(int)cond
11941194
escape(handler);
11951195
}
11961196

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

0 commit comments

Comments
 (0)