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

Philip Reames via llvm-dev llvm-dev at lists.llvm.org
Fri Sep 14 15:45:18 PDT 2018


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 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



More information about the llvm-dev mailing list