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

Sanjoy Das via llvm-dev llvm-dev at lists.llvm.org
Sat Sep 15 16:51:51 PDT 2018


On Fri, Sep 14, 2018 at 3:45 PM Philip Reames via llvm-dev
<llvm-dev at lists.llvm.org> wrote:
>
> Sorry for the late response.  Reading over the thread, the general plan
> expressed seems non-objectionable, but I find myself questioning the
> premise.
>
> Can you give an example or two of how we miscompile such functions?   My

Maybe something like:

void f(int& x) {
  free(&x);
  for (;;) {
    if (false) {
      int k = x;
    }
  }
}

=>

void f(int& x) {
  free(&x);
  // "safe" to hoist since the "x" arg will be lowered to i32*
dereferenceable(4)
  int k = x;
  for (;;) {
    if (false) {
    }
  }
}


> mental model here is that free conceptually writes an unspecified value
> to the memory before actually releasing it. With that, I'd expect most
> obvious miscompiles to be inhibited by memory dependence.  Can you
> provide a concrete example to illustrate why my mental model is broken?
>
> Philip
>
>
> On 07/10/2018 07:01 PM, Hal Finkel via llvm-dev 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
> >
>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev


More information about the llvm-dev mailing list