Files
android_external_libcxx/test/libcxx/atomics/diagnose_nonnull.fail.cpp
JF Bastien 8bacb9422b Add nonnull; use it for atomics
Summary:
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). We can therefore use the nonnull attribute to denote that:

  - A warning should be generated if the argument is null
  - It is undefined behavior if the argument is null (because a dereference will segfault)

This patch adds support for this attribute for clang and GCC, and sticks to the subset of the syntax both supports. In particular, work around this GCC oddity:
  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60625

The attributes are documented:

  - https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html
  - https://clang.llvm.org/docs/AttributeReference.html#nullability-attributes

I'm authoring a companion clang patch for the __c11_* and __atomic_* builtins, which currently only warn on a subset of the pointer parameters.

In all cases the check needs to be explicit and not use the empty nonnull list, because some of the overloads are for atomic<T*> and the values themselves are allowed to be null.

<rdar://problem/18473124>

Reviewers: arphaman, EricWF

Subscribers: aheejin, christof, cfe-commits

Differential Revision: https://reviews.llvm.org/D47225

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@333325 91177308-0d34-0410-b5e6-96231b3b80d8
2018-05-25 23:43:53 +00:00

93 lines
11 KiB
C++

//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// REQUIRES: verify-support
// UNSUPPORTED: libcpp-has-no-threads
// <atomic>
// Test that null pointer parameters are diagnosed.
#include <atomic>
int main() {
std::atomic<int> ai = ATOMIC_VAR_INIT(0);
volatile std::atomic<int> vai = ATOMIC_VAR_INIT(0);
int i = 42;
atomic_is_lock_free((const volatile std::atomic<int>*)0); // expected-error {{null passed to a callee that requires a non-null argument}}
atomic_is_lock_free((const std::atomic<int>*)0); // expected-error {{null passed to a callee that requires a non-null argument}}
atomic_init((volatile std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
atomic_init((std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
atomic_store((volatile std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
atomic_store((std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
atomic_store_explicit((volatile std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
atomic_store_explicit((std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_load((const volatile std::atomic<int>*)0); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_load((const std::atomic<int>*)0); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_load_explicit((const volatile std::atomic<int>*)0, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_load_explicit((const std::atomic<int>*)0, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_exchange((volatile std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_exchange((std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_exchange_explicit((volatile std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_exchange_explicit((std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_weak((volatile std::atomic<int>*)0, &i, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_weak((std::atomic<int>*)0, &i, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_strong((volatile std::atomic<int>*)0, &i, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_strong((std::atomic<int>*)0, &i, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_weak(&vai, (int*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_weak(&ai, (int*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_strong(&vai, (int*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_strong(&ai, (int*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_weak_explicit((volatile std::atomic<int>*)0, &i, 42, std::memory_order_relaxed, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_weak_explicit((std::atomic<int>*)0, &i, 42, std::memory_order_relaxed, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_strong_explicit((volatile std::atomic<int>*)0, &i, 42, std::memory_order_relaxed, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_strong_explicit((std::atomic<int>*)0, &i, 42, std::memory_order_relaxed, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_weak_explicit(&vai, (int*)0, 42, std::memory_order_relaxed, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_weak_explicit(&ai, (int*)0, 42, std::memory_order_relaxed, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_strong_explicit(&vai, (int*)0, 42, std::memory_order_relaxed, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_compare_exchange_strong_explicit(&ai, (int*)0, 42, std::memory_order_relaxed, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_add((volatile std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_add((std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_add((volatile std::atomic<int*>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_add((std::atomic<int*>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_add_explicit((volatile std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_add_explicit((std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_add_explicit((volatile std::atomic<int*>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_add_explicit((std::atomic<int*>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_sub((volatile std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_sub((std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_sub((volatile std::atomic<int*>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_sub((std::atomic<int*>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_sub_explicit((volatile std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_sub_explicit((std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_sub_explicit((volatile std::atomic<int*>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_sub_explicit((std::atomic<int*>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_and((volatile std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_and((std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_and_explicit((volatile std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_and_explicit((std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_or((volatile std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_or((std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_or_explicit((volatile std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_or_explicit((std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_xor((volatile std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_xor((std::atomic<int>*)0, 42); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_xor_explicit((volatile std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_fetch_xor_explicit((std::atomic<int>*)0, 42, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_flag_test_and_set((volatile std::atomic_flag*)0); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_flag_test_and_set((std::atomic_flag*)0); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_flag_test_and_set_explicit((volatile std::atomic_flag*)0, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_flag_test_and_set_explicit((std::atomic_flag*)0, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_flag_clear((volatile std::atomic_flag*)0); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_flag_clear((std::atomic_flag*)0); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_flag_clear_explicit((volatile std::atomic_flag*)0, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
(void)atomic_flag_clear_explicit((std::atomic_flag*)0, std::memory_order_relaxed); // expected-error {{null passed to a callee that requires a non-null argument}}
}