This is an archive of the discontinued LLVM Phabricator instance.

Make atomic non-member functions as nonnull
ClosedPublic

Authored by jfb on May 22 2018, 2:43 PM.

Details

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

Diff Detail

Repository
rL LLVM

Event Timeline

jfb created this revision.May 22 2018, 2:43 PM
arphaman added inline comments.May 23 2018, 6:15 PM
lib/Sema/SemaChecking.cpp
3497 ↗(On Diff #148104)

Nit: might make more sense to check if ByValType is a pointer here instead of duplicating the if condition from above.

jfb updated this revision to Diff 148458.May 24 2018, 11:37 AM
jfb marked an inline comment as done.
  • Address nit.
jfb added a comment.May 24 2018, 11:38 AM

Addressed nit.

rsmith accepted this revision.May 24 2018, 3:21 PM
rsmith added a subscriber: rsmith.

Either the previous version of this patch or a version with a bool factored out seem OK to me.

lib/Sema/SemaChecking.cpp
3497 ↗(On Diff #148104)

I think the suggestion was to check ByValType->isPointerType() here. But... that doesn't work, because we could have a pointer value being passed by value (where a null is allowed), rather than a value being passed by address (where a null is disallowed). I think this comparison is actually less clear than the !IsC11 && !IsN check; factoring out a bool IsPassedByAddress or similar instead would aid readability here.

This revision is now accepted and ready to land.May 24 2018, 3:21 PM
jfb updated this revision to Diff 148504.May 24 2018, 4:50 PM
jfb marked an inline comment as done.
  • Address nit.
  • Change suggested by Richard
jfb added inline comments.May 24 2018, 4:51 PM
lib/Sema/SemaChecking.cpp
3497 ↗(On Diff #148104)

I went with the bool as you suggested.

This revision was automatically updated to reflect the committed changes.

This is causing breaks in fuchsia,

Code that looks like this

uintptr_t last_unlogged =
     atomic_load_explicit(&unlogged_tail, memory_order_acquire);
 do { 
     if (last_unlogged == 0)
         return;
 } while (!atomic_compare_exchange_weak_explicit(&unlogged_tail,
                                                 &last_unlogged, 0,
                                                 memory_order_acq_rel,
                                                 memory_order_relaxed));

Where unlogged_tail is somewhere on the stack. And 'atomic_compare_exchange_weak_explicit' is an #define alias for '__c11_atomic_compare_exchange_weak'

Full context here: https://fuchsia.googlesource.com/zircon/+/master/third_party/ulib/musl/ldso/dynlink.c#822

jfb added a comment.May 25 2018, 10:15 AM

This is causing breaks in fuchsia,

Code that looks like this

uintptr_t last_unlogged =
     atomic_load_explicit(&unlogged_tail, memory_order_acquire);
 do { 
     if (last_unlogged == 0)
         return;
 } while (!atomic_compare_exchange_weak_explicit(&unlogged_tail,
                                                 &last_unlogged, 0,
                                                 memory_order_acq_rel,
                                                 memory_order_relaxed));

Where unlogged_tail is somewhere on the stack. And 'atomic_compare_exchange_weak_explicit' is an #define alias for '__c11_atomic_compare_exchange_weak'

Full context here: https://fuchsia.googlesource.com/zircon/+/master/third_party/ulib/musl/ldso/dynlink.c#822

Here's a repro for what seems to be happening:

#include <stdatomic.h>
void foo() {
  atomic_int s;
  int a;
  atomic_compare_exchange_weak_explicit(&s, &a, 0, memory_order_acq_rel, memory_order_relaxed);
}

Yields:

./foo.c:5:3: warning: null passed to a callee that requires a non-null argument [-Wnonnull]
  atomic_compare_exchange_weak_explicit(&s, &a, 0, memory_order_acq_rel, memory_order_relaxed);
  ^                                             ~
/s/llvm1/llvm/debug/lib/clang/7.0.0/include/stdatomic.h:144:47: note: expanded from macro 'atomic_compare_exchange_weak_explicit'
#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak
                                              ^

The problem is that my patch checks that the "desired" value is non-null, but that's incorrect because it's not a pointer. I'll do a follow-up fix. Thanks for catching this!

jfb added a comment.May 25 2018, 10:41 AM

Fixed by r333290.