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