Author: Ziqing Luo Date: 2024-01-26T11:23:15-08:00 New Revision: 2a068507016e476893b6b1b9c55b255dbae5829e
URL: https://github.com/llvm/llvm-project/commit/2a068507016e476893b6b1b9c55b255dbae5829e DIFF: https://github.com/llvm/llvm-project/commit/2a068507016e476893b6b1b9c55b255dbae5829e.diff LOG: [-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 Added: Modified: clang/lib/Analysis/CalledOnceCheck.cpp clang/test/SemaObjC/warn-called-once.m Removed: ################################################################################ diff --git a/clang/lib/Analysis/CalledOnceCheck.cpp b/clang/lib/Analysis/CalledOnceCheck.cpp index 04c5f6aa9c7450..30cbd257b65e8f 100644 --- a/clang/lib/Analysis/CalledOnceCheck.cpp +++ b/clang/lib/Analysis/CalledOnceCheck.cpp @@ -163,7 +163,7 @@ class ParameterStatus { NotVisited = 0x8, /* 1000 */ // We already reported a violation and stopped tracking calls for this // parameter. - Reported = 0x15, /* 1111 */ + Reported = 0xF, /* 1111 */ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Reported) }; @@ -932,7 +932,8 @@ class CalledOnceChecker : public ConstStmtVisitor<CalledOnceChecker> { ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index); // Escape overrides whatever error we think happened. - if (CurrentParamStatus.isErrorStatus()) { + if (CurrentParamStatus.isErrorStatus() && + CurrentParamStatus.getKind() != ParameterStatus::Kind::Reported) { CurrentParamStatus = ParameterStatus::Escaped; } } diff --git a/clang/test/SemaObjC/warn-called-once.m b/clang/test/SemaObjC/warn-called-once.m index dbe8dc1cf1ae17..f23e41e00ee298 100644 --- a/clang/test/SemaObjC/warn-called-once.m +++ b/clang/test/SemaObjC/warn-called-once.m @@ -1194,6 +1194,16 @@ - (void)test_escape_after_branch:(int)cond escape(handler); } +- (void)test_termination:(int)cond + withCompletion:(void (^)(void))handler { + // The code below was able to cause non-termination but should be + // fixed now: + do { + escape(handler); + handler(); // expected-warning{{completion handler is called twice}} expected-note{{previous call is here; set to nil to indicate it cannot be called afterwards}} + } while (cond); +} + typedef void (^DeferredBlock)(void); static inline void DefferedCallback(DeferredBlock *inBlock) { (*inBlock)(); } #define _DEFERCONCAT(a, b) a##b _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits