[llvm-dev] [RFC] A nofree (and nosynch) function attribute: Mixing dereferenceable and delete

Hal Finkel via llvm-dev llvm-dev at lists.llvm.org
Wed Jul 11 17:20:52 PDT 2018


Thanks, Richard.

Based on the feedback from this thread, I'll move forward with the
patches for nofree, nosync, adding a new corresponding dereferenceable
attribute (my suggestion is to name this dereferenceable_on_entry;
suggestions welcome), and updating Clang is emit this new attribute
instead of the current one.

 -Hal

On 07/11/2018 06:43 PM, Richard Smith wrote:
> On Wed, 11 Jul 2018 at 16:13, Hal Finkel via llvm-dev
> <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote:
>
>     [+Richard]
>
>
>     On 07/11/2018 08:29 AM, Sanjoy Das wrote:
>     > I'm not sure if nosynch is sufficient.  What if we had:
>     >
>     > void f(int& x) {
>     >   if (false) {
>     >     int r0 = x;
>     >   }
>     > }
>     >
>     > // other thread
>     > free(<pointer to x>);
>     >
>     > The source program is race free, but LLVM may speculate the read
>     from
>     > x (seeing that it is dereferenceable) creating a race.
>
>     Interestingly, I'm not sure. I trust that Richard can answer this
>     question. :-)
>
>     So, if we had:
>
>     int y = ...;
>     ...
>     f(y);
>
>     then I think that Clang's use of dereferenceable is almost certainly
>     okay (because the standard explicitly says, 9.2.3.2p5, "A reference
>     shall be initialized to refer to a valid object or
>     function."). Because the reference must have been valid when f(y)
>     began
>     executing, unless it synchronizes somehow with the other thread, any
>     asynchronous deletion of y must be a race.
>
>     On the other hand, if we have:
>
>     int &y = ...;
>     ...
>     f(y);
>
>     do we know that, when f(y) begins executing, the reference points to a
>     valid object? My reading of 9.3.3p2, which says, "Argument passing
>     (7.6.1.2) and
>     function value return (8.6.3) are initializations.", combined with the
>     statement above, implies that, perhaps surprisingly, the same holds
>     here. When the argument to f is initialized, it must refer to a valid
>     object (even if the initializer is another reference).
>
>     Richard, what do you think?
>
>
> First, see also core issue 453 <http://wg21.link/cwg453>, under the
> guise of which we're fixing the wording in [dcl.ref](9.2.3.2)p5 from
>
>   "A reference shall be initialized to refer to a valid object or
> function."
>
> to something like
>
>   "If an lvalue to which a reference is directly bound designates
> neither an existing object or function of an appropriate type (11.6.3
> [dcl.init.ref]), nor a region of storage of suitable size and
> alignment to contain an object of the reference's type (4.5
> [intro.object], 6.8 [basic.life], 6.9 [basic.types]), the behavior is
> undefined."
>
> My take is that, if the end of the duration of the region of storage
> is unsequenced with respect to the binding of the reference, then
> behavior is undefined. Generally when we refer to a thing happening
> while some condition is true, we mean that the execution point when
> the condition became true is sequenced before the thing happening, and
> the execution point where it becomes not true again is sequenced after.
>
> So the behavior of that program is undefined regardless of whether 'f'
> actually loads through 'x'.
>  
>
>     Thanks again,
>     Hal
>
>     P.S. If I'm right, then I might be happy, but it's also somewhat scary
>     (although we've been doing this optimization for multiple releases
>     and I
>     don't think we have a bug along these lines), and I'd at least
>     smell the
>     need for a sanitizer.
>
>     >
>     > -- Sanjoy
>     > On Tue, Jul 10, 2018 at 7:01 PM Hal Finkel via llvm-dev
>     > <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote:
>     >> Hi, everyone,
>     >>
>     >> I'd like to propose adding a nofree function attribute to
>     indicate that
>     >> a function does not, directly or indirectly, call a
>     memory-deallocation
>     >> function (e.g., free, C++'s operator delete). Clang/LLVM can
>     currently
>     >> misoptimize functions that:
>     >>
>     >>  1. Have a reference argument.
>     >>
>     >>  2. Free the memory backing the object to which the reference
>     is bound
>     >> during the function's execution.
>     >>
>     >> Because we tag, in Clang, all reference arguments using the
>     >> dereferenceable attribute, LLVM assumes that the pointer is
>     >> unconditionally dereferenceable throughout the course of the entire
>     >> function. This isn't true, however, if the memory is freed
>     during the
>     >> execution of the function. For more information, please see the
>     >> discussion in https://reviews.llvm.org/D48239.
>     >>
>     >> To solve this problem, we need to give LLVM more information in
>     order to
>     >> help it determine when a pointer, which is dereferenceable when the
>     >> functions begins to execute, will still be dereferenceable
>     later on in
>     >> the function's execution. This nofree attribute can be part of that
>     >> solution. If we know that free (and friends) are not called by the
>     >> function (nor by any function called by the function, and so
>     on), then
>     >> we know that pointers that started out dereferenceable will
>     stay that
>     >> way (except as explained below).
>     >>
>     >> I'm initially proposing this to be only a function attribute,
>     although
>     >> one could easily imagine a parameter attribute as well (that
>     indicates
>     >> that a particular pointer argument is not freed by the
>     function). This
>     >> might be useful, but for the use case of helping
>     dereferenceable, it
>     >> would be subtle to use, unless the parameter was also marked as
>     noalias,
>     >> because you'd need to know that the parameter was not also
>     aliased with
>     >> another argument (or had not been captured). Another analysis
>     would need
>     >> to provide this kind of information.
>     >>
>     >> Also, just because a function does not, directly or indirectly,
>     call
>     >> free does not mean that it cannot cause memory to be
>     deallocated. The
>     >> function might communicate (synchronize) with another thread
>     causing
>     >> that other thread to delete the memory. For this reason, to use
>     >> dereferenceable as we currently do, we also need to know that the
>     >> function does not synchronize with any other threads. To solve this
>     >> problem, like nofree, I propose to add a nosynch attribute (to
>     indicate
>     >> that a function does not use (non-relaxed) atomics or otherwise
>     >> synchronize with any other threads (e.g., perform I/O or, as a
>     practical
>     >> matter, use volatile accesses).
>     >>
>     >> I've posted a patch for the nofree attribute
>     >> (https://reviews.llvm.org/D49165). nosynch's implementation
>     would be
>     >> very similar (except instead of looking for calls to free, it
>     would look
>     >> for uses of non-relaxed atomics, volatile ops, and known
>     functions that
>     >> are not I/O functions).
>     >>
>     >> With both of these attributes (nofree and nosynch), a function
>     argument
>     >> with the dereferenceable attribute will be known to be
>     dereferenceable
>     >> throughout the execution of the attributed function. We can update
>     >> isDereferenceableAndAlignedPointer to include these additional
>     checks on
>     >> the current function.
>     >>
>     >> One more choice we have: We can, as I proposed above,
>     essentially weaken
>     >> the current semantics of dereferenceable to not exclude
>     >> mid-function-execution deallocation. We can also add a second
>     attribute
>     >> with the current, stronger, semantics. We can keep the current
>     attribute
>     >> as-is, and add a second attribute with the weaker semantics
>     (and switch
>     >> Clang to use that).
>     >>
>     >> Please let me know what you think.
>     >>
>     >> Thanks again,
>     >>
>     >> Hal
>     >>
>     >> --
>     >> Hal Finkel
>     >> Lead, Compiler Technology and Programming Languages
>     >> Leadership Computing Facility
>     >> Argonne National Laboratory
>     >>
>     >> _______________________________________________
>     >> LLVM Developers mailing list
>     >> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>
>     >> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
>     -- 
>     Hal Finkel
>     Lead, Compiler Technology and Programming Languages
>     Leadership Computing Facility
>     Argonne National Laboratory
>
>     _______________________________________________
>     LLVM Developers mailing list
>     llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>
>     http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>

-- 
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20180711/b4ac5cc2/attachment.html>


More information about the llvm-dev mailing list