[llvm-dev] Heap problems with 3.8.0rc2 in combination with vs2015 sp1

Michael Kruse via llvm-dev llvm-dev at lists.llvm.org
Tue Mar 1 03:47:34 PST 2016


Thank you for your investigation. Do maybe have a suggestion for a
patch that would make LLVM compatible with the /sdl switch?

MIchael


2016-02-26 9:59 GMT+01:00 koffie drinker via llvm-dev <llvm-dev at lists.llvm.org>:
> Turns out llvm initializes memory before the constructor is invoked. Visual
> studio has /sdl by default on, and the __autoclassinit2 will zero the memory
> before the constructor is reached causing all the setters to be default
> zero. which clears the hashungoff var and causing the delete to flow in
> wrong part.
>
> When /sdl is enabled, the compiler generates code to perform these checks at
> run time:
> — Performs class member initialization. Automatically initializes all class
> members to zero on object instantiation (before the constructor runs). This
> helps prevent the use of uninitialized data associated with class members
> that the constructor does not explicitly initialize.
>
> Disabling the /SDL switch and everything works as intended. It might be
> handy to put this in the windows docs since it costed me quite some time to
> discover.
>
> This is for reference to other users that are having heap issues:
> http://stackoverflow.com/questions/25026488/c11-vs2013-class-pod-member-initialization
>
> On Thu, Feb 25, 2016 at 4:33 PM, koffie drinker <gekkekoe at gmail.com> wrote:
>>
>> I found the root cause, but I don't know what's the best approach to fix
>> it.
>>
>> Under windows, 64 bit, when a function is created the void *User::operator
>> new(size_t Size) operator allocates space + Use*.
>> In the Use* the HasHungOffUses is set to true. So the ptr to the use* is
>> returned as new object. This ptr is NOT the ptr that was allocated by the
>> system. For that ptr you need ptr - word length. It's important that we use
>> free on the original ptr.
>>
>> The void User::operator delete(void *Usr) deletes the use* when dtor is
>> called. However, tracing through the Function() ctor I see that the
>> HasHungOffUses is set to False (!).  And when we arrive at the
>> User::delete, the HasHungOffUses has the wrong value causing it to flow into
>> the else part.
>>
>> void User::operator delete(void *Usr) {
>>   // Hung off uses use a single Use* before the User, while other
>> subclasses
>>   // use a Use[] allocated prior to the user.
>>   User *Obj = static_cast<User *>(Usr);
>>   if (Obj->HasHungOffUses) {
>>     assert(!Obj->HasDescriptor && "not supported!");
>>
>>     Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
>>     // drop the hung off uses.
>>     Use::zap(*HungOffOperandList, *HungOffOperandList +
>> Obj->NumUserOperands,
>>              /* Delete */ true);
>>     ::operator delete(HungOffOperandList);
>>   } else if (Obj->HasDescriptor) {
>>     Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands;
>>     Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */
>> false);
>>
>>     auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
>>     uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
>>     ::operator delete(Storage);
>>   } else {
>>     Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
>>     Use::zap(Storage, Storage + Obj->NumUserOperands,
>>              /* Delete */ false);
>>     ::operator delete(Storage);
>>   }
>> }
>>
>> The storage address is computed wrongly in this case, it's off by 1 word
>> length. And so visual studio sees that I'm not freeing the org allocated ptr
>> and throws heap error. During debug when I force HasHungOffUses = true,
>> everything is fine and the correct original ptr is computed and freed. So
>> I'm guessing that that value should have stayed true.
>>
>> I also have set a data breakpoint on HashHungOffUses when it's accessed
>> and did noticed that
>>   ConsoleEngine.exe!llvm::Function::__autoclassinit2(unsigned __int64) C++
>> ConsoleEngine.exe!llvm::Function::Create(llvm::FunctionType * Ty,
>> llvm::GlobalValue::LinkageTypes Linkage, const llvm::Twine & N, llvm::Module
>> * M) Line 116 C++
>>
>> caused it to be set to False. So do I need to trace into all the Function
>> bases classes and find out where it is set to false? or do I need to fix the
>> Storage address computation in the else part?
>>
>> Cheers,
>>
>>
>> On Thu, Feb 25, 2016 at 1:07 PM, koffie drinker <gekkekoe at gmail.com>
>> wrote:
>>>
>>> I made the llvm::Function() constructor public (for testing purpose) and
>>> used the non-overloaded new.
>>>
>>> auto func = ::new llvm::Function(...)
>>> if (func) func->eraseFromParent();
>>>
>>> And the heap corruption is gone! Did something changed in llvm::User::new
>>> between 3.7.1 and 3.8.0 ?
>>> I found a bug in llvm ?
>>>
>>>
>>> On Thu, Feb 25, 2016 at 12:10 PM, koffie drinker <gekkekoe at gmail.com>
>>> wrote:
>>>>
>>>> I downloaded 3.8.0rc3 and I also have it in 3.8.0rc3.
>>>> I did set a data access breakpoint on the first function ptr that causes
>>>> the invalid heap. This would allow me to break whenever someone is touching
>>>> that address. It did not show double deletes during debugging. Further more
>>>> I managed to narrow it down to 2 function calls:
>>>>
>>>> // stupid code, but its just for triggering heap error
>>>> auto func = llvm::Function::Create(...);
>>>> if (func) func->eraseFromParent();
>>>>
>>>> The erase from parent triggers the invalid heap. I used appverif.exe and
>>>> gflags.exe (page heap checks) but they could not find anything.
>>>> The Function::Create is just a wrapper for new Function(). I also traced
>>>> into this call, but did not see anything weird. It returns a valid ptr.
>>>> Somehow the ptr returned by the new seems to be broken. If i'm not
>>>> mistaken the new operator is overloaded by llvm? I could not try to use the
>>>> default new Function() since its constructor is not accessible from outside.
>>>>
>>>> I'm kinda lost where to look next. There's not much that could go wrong
>>>> with creating a function and deleting it?
>>>> I'm using visual studio 2015 update1, and could not find any known issue
>>>> regarding heaps. I'm at a point where I'm suspecting my compiler.
>>>> But its weird that the same compiler works fine with 3.7.1
>>>>
>>>> any ideas would be appreciated
>>>>
>>>>
>>>> On Wed, Feb 24, 2016 at 9:10 AM, koffie drinker <gekkekoe at gmail.com>
>>>> wrote:
>>>>>
>>>>>
>>>>> I recently upgraded from llvm 3.7.1 to a pre release of llvm (3.8.0rc2)
>>>>> in order to test some issues regarding bug 24233.
>>>>> After upgrading I starting to see heap corruption messages in vs 2015
>>>>> sp1 when my program exits.
>>>>> "HEAP[ConsoleEngine.exe]: Invalid address specified to RtlValidateHeap(
>>>>> 0000000000290000, 0000000000318698 )"
>>>>>
>>>>> Initially I only got it in Release build. Debug build seems to be fine,
>>>>> but recently I also got them in Debug build.
>>>>> I traced it down how to trigger it in Debug Mode. It happens when I put
>>>>> the ExecutionEngine creation in the constructor in the cpp file.
>>>>> If I put it in the h file then there's no problem. This leads me to
>>>>> believe that it is probably not my code that is causing it since I never
>>>>> seem to have
>>>>> this issue in the past (3.6.x - 3.7.x). I've include the stack traces
>>>>> below this email.
>>>>>
>>>>> It fails when the dtor is called for the first module. MCJIT only has 2
>>>>> modules, the first one only has function declarations. The second one is
>>>>> empty. No codegen is taking place.
>>>>>
>>>>> I googled for the error message and it seems to be happen when you
>>>>> delete a resource twice.
>>>>> Did something change for 3.8.0 regarding to function decl. creation in
>>>>> a module? Any tips on how to trace it down further? I can't seem to make a
>>>>> small example demonstration the problem. It only seems to be triggered in a
>>>>> larger project (again: nearly code works fine in 3.6.x-3.7.x)
>>>>>
>>>>>
>>>>> -- Release mode stack trace
>>>>>   ntdll.dll!RtlReportCriticalFailure() Unknown
>>>>>   ntdll.dll!RtlpReportHeapFailure() Unknown
>>>>>   ntdll.dll!RtlpHeapHandleError() Unknown
>>>>>   ntdll.dll!RtlpLogHeapFailure() Unknown
>>>>>   ntdll.dll!string "Enabling heap debug options\n"() Unknown
>>>>>   ucrtbase.dll!free() Unknown
>>>>>   ConsoleEngine.exe!llvm::Function::`vector deleting
>>>>> destructor'(unsigned int) C++
>>>>>   ConsoleEngine.exe!llvm::Module::~Module(void) C++
>>>>>
>>>>> ConsoleEngine.exe!llvm::MCJIT::OwningModuleContainer::freeModulePtrSet(class
>>>>> llvm::SmallPtrSet<class llvm::Module *,4> &) C++
>>>>>   ConsoleEngine.exe!llvm::MCJIT::~MCJIT(void) C++
>>>>>   ConsoleEngine.exe!llvm::MCJIT::`vector deleting destructor'(unsigned
>>>>> int) C++
>>>>>
>>>>> -- Debug Mode stack trace
>>>>> ntdll.dll!RtlpBreakPointHeap() Unknown
>>>>>   ntdll.dll!string "Enabling heap debug options\n"() Unknown
>>>>>   ntdll.dll!RtlValidateHeap() Unknown
>>>>>   KernelBase.dll!HeapValidate() Unknown
>>>>>   ucrtbased.dll!_CrtIsValidHeapPointer() Unknown
>>>>>   ucrtbased.dll!_calloc_base() Unknown
>>>>>   ucrtbased.dll!_free_dbg() Unknown
>>>>>   ConsoleEngine.exe!operator delete(void * block) Line 21 C++
>>>>> ConsoleEngine.exe!llvm::User::operator delete(void * Usr) Line 195 C++
>>>>>   ConsoleEngine.exe!llvm::Function::`scalar deleting
>>>>> destructor'(unsigned int) C++
>>>>>
>>>>> ConsoleEngine.exe!llvm::ilist_node_traits<llvm::Function>::deleteNode(llvm::Function
>>>>> * V) Line 160 C++
>>>>>
>>>>> ConsoleEngine.exe!llvm::iplist<llvm::Function,llvm::SymbolTableListTraits<llvm::Function>
>>>>> >::erase(llvm::ilist_iterator<llvm::Function> where) Line 519 C++
>>>>>
>>>>> ConsoleEngine.exe!llvm::iplist<llvm::Function,llvm::SymbolTableListTraits<llvm::Function>
>>>>> >::erase(llvm::ilist_iterator<llvm::Function> first,
>>>>> llvm::ilist_iterator<llvm::Function> last) Line 601 C++
>>>>>
>>>>> ConsoleEngine.exe!llvm::iplist<llvm::Function,llvm::SymbolTableListTraits<llvm::Function>
>>>>> >::clear() Line 605 C++
>>>>>   ConsoleEngine.exe!llvm::Module::~Module() Line 61 C++
>>>>>   ConsoleEngine.exe!llvm::Module::`scalar deleting destructor'(unsigned
>>>>> int) C++
>>>>>
>>>>> ConsoleEngine.exe!llvm::MCJIT::OwningModuleContainer::freeModulePtrSet(llvm::SmallPtrSet<llvm::Module
>>>>> *,4> & MPS) Line 175 C++
>>>>>
>>>>> ConsoleEngine.exe!llvm::MCJIT::OwningModuleContainer::~OwningModuleContainer()
>>>>> Line 82 C++
>>>>>   ConsoleEngine.exe!llvm::MCJIT::~MCJIT() Line 102 C++
>>>>>   ConsoleEngine.exe!llvm::MCJIT::`scalar deleting destructor'(unsigned
>>>>> int) C++
>>>>>
>>>>> ConsoleEngine.exe!std::default_delete<llvm::ExecutionEngine>::operator()(llvm::ExecutionEngine
>>>>> * _Ptr) Line 1195 C++
>>>>>
>>>>> ConsoleEngine.exe!std::unique_ptr<llvm::ExecutionEngine,std::default_delete<llvm::ExecutionEngine>
>>>>> >::~unique_ptr<llvm::ExecutionEngine,std::default_delete<llvm::ExecutionEngine>
>>>>> >() Line 1398 C++
>>>>>
>>>>
>>>
>>
>
>
> _______________________________________________
> 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