[-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
This commit is contained in:
parent
6c74d8083b
commit
2a06850701
@ -163,7 +163,7 @@ public:
|
|||||||
NotVisited = 0x8, /* 1000 */
|
NotVisited = 0x8, /* 1000 */
|
||||||
// We already reported a violation and stopped tracking calls for this
|
// We already reported a violation and stopped tracking calls for this
|
||||||
// parameter.
|
// parameter.
|
||||||
Reported = 0x15, /* 1111 */
|
Reported = 0xF, /* 1111 */
|
||||||
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Reported)
|
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Reported)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -932,7 +932,8 @@ private:
|
|||||||
ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index);
|
ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index);
|
||||||
|
|
||||||
// Escape overrides whatever error we think happened.
|
// Escape overrides whatever error we think happened.
|
||||||
if (CurrentParamStatus.isErrorStatus()) {
|
if (CurrentParamStatus.isErrorStatus() &&
|
||||||
|
CurrentParamStatus.getKind() != ParameterStatus::Kind::Reported) {
|
||||||
CurrentParamStatus = ParameterStatus::Escaped;
|
CurrentParamStatus = ParameterStatus::Escaped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1194,6 +1194,16 @@ void suppression_3(int cond, void (^callback)(void) CALLED_ONCE) {
|
|||||||
escape(handler);
|
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);
|
typedef void (^DeferredBlock)(void);
|
||||||
static inline void DefferedCallback(DeferredBlock *inBlock) { (*inBlock)(); }
|
static inline void DefferedCallback(DeferredBlock *inBlock) { (*inBlock)(); }
|
||||||
#define _DEFERCONCAT(a, b) a##b
|
#define _DEFERCONCAT(a, b) a##b
|
||||||
|
Loading…
x
Reference in New Issue
Block a user