forked from OSchip/llvm-project
[analyzer] Fix yet-another-crash in body-farming std::call_once
Crash occurs when parameters to the callback and to std::call_once mismatch, and C++ is supposed to auto-construct an argument. Filed by Alexander Kornienko in https://bugs.llvm.org/show_bug.cgi?id=36149 rdar://37034403 Differential Revision: https://reviews.llvm.org/D42777 llvm-svn: 324046
This commit is contained in:
parent
844ccca577
commit
59202324a5
|
@ -406,6 +406,16 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
|
|||
// reference.
|
||||
for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
|
||||
const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
|
||||
if (PDecl &&
|
||||
CallbackFunctionType->getParamType(ParamIdx - 2)
|
||||
.getNonReferenceType()
|
||||
.getCanonicalType() !=
|
||||
PDecl->getType().getNonReferenceType().getCanonicalType()) {
|
||||
DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
|
||||
<< "params passed to std::call_once, "
|
||||
<< "ignoring the call\n");
|
||||
return nullptr;
|
||||
}
|
||||
Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
|
||||
if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {
|
||||
QualType PTy = PDecl->getType().getNonReferenceType();
|
||||
|
@ -816,4 +826,3 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
|
|||
|
||||
return Val.getValue();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,26 @@
|
|||
|
||||
void clang_analyzer_eval(bool);
|
||||
|
||||
// Faking std::std::call_once implementation.
|
||||
// Faking std::call_once implementation.
|
||||
namespace std {
|
||||
|
||||
// Fake std::function implementation.
|
||||
template <typename>
|
||||
class function;
|
||||
class function_base {
|
||||
public:
|
||||
long field;
|
||||
};
|
||||
template <typename R, typename... P>
|
||||
class function<R(P...)> : function_base {
|
||||
public:
|
||||
R operator()(P...) const {
|
||||
|
||||
// Read from a super-class necessary to reproduce a crash.
|
||||
bool a = field;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef EMULATE_LIBSTDCPP
|
||||
typedef struct once_flag_s {
|
||||
unsigned long __state_ = 0;
|
||||
|
@ -360,3 +377,29 @@ void test_implicit_funcptr() {
|
|||
clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
|
||||
#endif
|
||||
}
|
||||
|
||||
int param_passed(int *x) {
|
||||
return *x; // no-warning, as std::function is not working yet.
|
||||
}
|
||||
|
||||
void callback_taking_func_ok(std::function<void(int*)> &innerCallback) {
|
||||
innerCallback(nullptr);
|
||||
}
|
||||
|
||||
// The provided callback expects an std::function, but instead a pointer
|
||||
// to a C++ function is provided.
|
||||
void callback_with_implicit_cast_ok() {
|
||||
std::once_flag flag;
|
||||
call_once(flag, callback_taking_func_ok, ¶m_passed);
|
||||
}
|
||||
|
||||
void callback_taking_func(std::function<void()> &innerCallback) {
|
||||
innerCallback();
|
||||
}
|
||||
|
||||
// The provided callback expects an std::function, but instead a C function
|
||||
// name is provided, and C++ implicitly auto-constructs a pointer from it.
|
||||
void callback_with_implicit_cast() {
|
||||
std::once_flag flag;
|
||||
call_once(flag, callback_taking_func, callback_with_implicit_cast);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue