[PATCH] D37933: Prevent InstCombine from miscompiling `operator delete`

Richard Smith - zygoloid via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 15 15:07:02 PDT 2017


rsmith added inline comments.


================
Comment at: lib/Analysis/MemoryBuiltins.cpp:351
 
+/// hasSideEffectsFreeCall - Returns true if the call has side effects.
+bool llvm::hasSideEffectsFreeCall(const CallInst *CI,
----------------
This is a really confusing name. It sounds like it's detecting whether a call is free of side-effects, whereas it's *actually* detecting whether the call is to a `free`-like function that has side-effects.


================
Comment at: lib/Analysis/MemoryBuiltins.cpp:363-368
+  return TLIFn == LibFunc_ZdlPv ||                   // operator delete(void*)
+         TLIFn == LibFunc_ZdaPv ||                   // operator delete[](void*)
+         TLIFn == LibFunc_msvc_delete_ptr32 ||       // operator delete(void*)
+         TLIFn == LibFunc_msvc_delete_ptr64 ||       // operator delete(void*)
+         TLIFn == LibFunc_msvc_delete_array_ptr32 || // operator delete[](void*)
+         TLIFn == LibFunc_msvc_delete_array_ptr64;   // operator delete[](void*)
----------------
I really don't like duplicating this list here, in a way that means we would miscompile again if the list in `isFreeCall` is extended but this list is not. (Notably, this list is already missing cases from `isFreeCall`, and as it happens, the one in `isFreeCall` is also missing cases.)

Perhaps instead changing this function to determine whether a call is known to be side-effect free when given a null pointer, and special-casing the very small number of functions for which that's true, would be a better and more maintainable approach?


================
Comment at: lib/Analysis/MemoryBuiltins.cpp:393-394
   // Check free prototype.
   // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin
   // attribute will exist.
   FunctionType *FTy = Callee->getFunctionType();
----------------
Note that this function returns the wrong value for a `nobuiltin` call, and thus may still miscompile calls to `free` when building with `-fno-builtin=free`.


================
Comment at: lib/Transforms/InstCombine/InstructionCombining.cpp:2231
 
   // free undef -> unreachable.
   if (isa<UndefValue>(Op)) {
----------------
This is wrong too. Either passing `undef` to *any* pointer parameter in a function call results in UB, or you cannot assume that passing `undef` to `::operator delete` results in UB. The user-provided `::operator delete` might ignore its argument, for example.

I don't know if this is the reason, but LLVM miscompiles calls to `operator delete` in cases where it ignores its argument too: https://godbolt.org/g/dvvirQ


================
Comment at: lib/Transforms/InstCombine/InstructionCombining.cpp:2242
   if (isa<ConstantPointerNull>(Op))
     return eraseInstFromFunction(FI);
 
----------------
Wrong for `operator delete`.


https://reviews.llvm.org/D37933





More information about the llvm-commits mailing list