Make atomic non-member functions as nonnull
Summary: As a companion to libc++ patch https://reviews.llvm.org/D47225, mark builtin atomic non-member functions which accept pointers as nonnull. The atomic non-member functions accept pointers to std::atomic / std::atomic_flag as well as to the non-atomic value. These are all dereferenced unconditionally when lowered, and therefore will fault if null. It's a tiny gotcha for new users, especially when they pass in NULL as expected value (instead of passing a pointer to a NULL value). <rdar://problem/18473124> Reviewers: arphaman Subscribers: aheejin, cfe-commits Differential Revision: https://reviews.llvm.org/D47229 llvm-svn: 333246
This commit is contained in:
parent
698b0a674d
commit
7f0a05ada5
@ -3451,9 +3451,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
// atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the
|
||||
// volatile-ness of the pointee-type inject itself into the result or the
|
||||
// other operands. Similarly atomic_load can take a pointer to a const 'A'.
|
||||
// All atomic operations have an overload which takes a pointer to a volatile
|
||||
// 'A'. We shouldn't let the volatile-ness of the pointee-type inject itself
|
||||
// into the result or the other operands. Similarly atomic_load takes a
|
||||
// pointer to a const 'A'.
|
||||
ValType.removeLocalVolatile();
|
||||
ValType.removeLocalConst();
|
||||
QualType ResultType = ValType;
|
||||
@ -3466,16 +3467,27 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
|
||||
// The type of a parameter passed 'by value'. In the GNU atomics, such
|
||||
// arguments are actually passed as pointers.
|
||||
QualType ByValType = ValType; // 'CP'
|
||||
if (!IsC11 && !IsN)
|
||||
bool IsPassedByAddress = false;
|
||||
if (!IsC11 && !IsN) {
|
||||
ByValType = Ptr->getType();
|
||||
IsPassedByAddress = true;
|
||||
}
|
||||
|
||||
// The first argument --- the pointer --- has a fixed type; we
|
||||
// deduce the types of the rest of the arguments accordingly. Walk
|
||||
// the remaining arguments, converting them to the deduced value type.
|
||||
for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) {
|
||||
// The first argument's non-CV pointer type is used to deduce the type of
|
||||
// subsequent arguments, except for:
|
||||
// - weak flag (always converted to bool)
|
||||
// - memory order (always converted to int)
|
||||
// - scope (always converted to int)
|
||||
for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) {
|
||||
QualType Ty;
|
||||
if (i < NumVals[Form] + 1) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
// The first argument is always a pointer. It has a fixed type.
|
||||
// It is always dereferenced, a nullptr is undefined.
|
||||
CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart());
|
||||
// Nothing else to do: we already know all we want about this pointer.
|
||||
continue;
|
||||
case 1:
|
||||
// The second argument is the non-atomic operand. For arithmetic, this
|
||||
// is always passed by value, and for a compare_exchange it is always
|
||||
@ -3484,14 +3496,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
|
||||
assert(Form != Load);
|
||||
if (Form == Init || (Form == Arithmetic && ValType->isIntegerType()))
|
||||
Ty = ValType;
|
||||
else if (Form == Copy || Form == Xchg)
|
||||
else if (Form == Copy || Form == Xchg) {
|
||||
if (IsPassedByAddress)
|
||||
// The value pointer is always dereferenced, a nullptr is undefined.
|
||||
CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart());
|
||||
Ty = ByValType;
|
||||
else if (Form == Arithmetic)
|
||||
} else if (Form == Arithmetic)
|
||||
Ty = Context.getPointerDiffType();
|
||||
else {
|
||||
Expr *ValArg = TheCall->getArg(i);
|
||||
// Treat this argument as _Nonnull as we want to show a warning if
|
||||
// NULL is passed into it.
|
||||
// The value pointer is always dereferenced, a nullptr is undefined.
|
||||
CheckNonNullArgument(*this, ValArg, DRE->getLocStart());
|
||||
LangAS AS = LangAS::Default;
|
||||
// Keep address space of non-atomic pointer type.
|
||||
@ -3504,8 +3518,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// The third argument to compare_exchange / GNU exchange is a
|
||||
// (pointer to a) desired value.
|
||||
// The third argument to compare_exchange / GNU exchange is the desired
|
||||
// value, either by-value (for the *_n variant) or as a pointer.
|
||||
if (!IsN)
|
||||
CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart());
|
||||
Ty = ByValType;
|
||||
break;
|
||||
case 3:
|
||||
@ -3887,7 +3903,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
|
||||
ResultType = Context.BoolTy;
|
||||
break;
|
||||
|
||||
case Builtin::BI__sync_lock_test_and_set:
|
||||
case Builtin::BI__sync_lock_test_and_set:
|
||||
case Builtin::BI__sync_lock_test_and_set_1:
|
||||
case Builtin::BI__sync_lock_test_and_set_2:
|
||||
case Builtin::BI__sync_lock_test_and_set_4:
|
||||
|
||||
@ -531,8 +531,80 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
|
||||
}
|
||||
|
||||
void nullPointerWarning(_Atomic(int) *Ap, int *p, int val) {
|
||||
// The 'expected' pointer shouldn't be NULL.
|
||||
(void)__c11_atomic_compare_exchange_strong(Ap, NULL, val, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)atomic_compare_exchange_weak(Ap, ((void*)0), val); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange_n(p, NULL, val, 0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
volatile _Atomic(int) vai;
|
||||
_Atomic(int) ai;
|
||||
volatile int vi = 42;
|
||||
int i = 42;
|
||||
|
||||
__c11_atomic_init((volatile _Atomic(int)*)0, 42); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__c11_atomic_init((_Atomic(int)*)0, 42); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__c11_atomic_store((volatile _Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__c11_atomic_store((_Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_load((volatile _Atomic(int)*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_load((_Atomic(int)*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_exchange((volatile _Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_exchange((_Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_compare_exchange_weak((volatile _Atomic(int)*)0, &i, 42, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_compare_exchange_weak((_Atomic(int)*)0, &i, 42, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_compare_exchange_weak(&vai, (int*)0, 42, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_compare_exchange_weak(&ai, (int*)0, 42, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_compare_exchange_strong((volatile _Atomic(int)*)0, &i, 42, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_compare_exchange_strong((_Atomic(int)*)0, &i, 42, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_compare_exchange_strong(&vai, (int*)0, 42, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_compare_exchange_strong(&ai, (int*)0, 42, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_add((volatile _Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_add((_Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_sub((volatile _Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_sub((_Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_and((volatile _Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_and((_Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_or((volatile _Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_or((_Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_xor((volatile _Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__c11_atomic_fetch_xor((_Atomic(int)*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
|
||||
__atomic_store_n((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_store_n((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_store((volatile int*)0, &i, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_store((int*)0, &i, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_store(&vi, (int*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_store(&i, (int*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_load_n((volatile int*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_load_n((int*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_load((volatile int*)0, &i, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_load((int*)0, &i, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_load(&vi, (int*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_load(&i, (int*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_exchange_n((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_exchange_n((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_exchange((volatile int*)0, &i, &i, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_exchange((int*)0, &i, &i, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_exchange(&vi, (int*)0, &i, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_exchange(&i, (int*)0, &i, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_exchange(&vi, &i, (int*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
__atomic_exchange(&i, &i, (int*)0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange_n((volatile int*)0, &i, 42, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange_n((int*)0, &i, 42, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange_n(&vi, (int*)0, 42, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange_n(&i, (int*)0, 42, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange((volatile int*)0, &i, &i, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange((int*)0, &i, &i, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange(&vi, (int*)0, &i, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange(&i, (int*)0, &i, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange(&vi, &i, (int*)0, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_compare_exchange(&i, &i, (int*)0, /*weak=*/0, memory_order_relaxed, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_add((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_add((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_sub((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_sub((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_and((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_and((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_or((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_or((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_xor((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_xor((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_min((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_min((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_max((volatile int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
(void)__atomic_fetch_max((int*)0, 42, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user