I can crash program (core.exception.InvalidMemoryOperationError) by using __FUNCTION__ in a class ctor

Steven Schveighoffer schveiguy at gmail.com
Fri Jan 18 17:03:59 UTC 2019


On 1/18/19 11:37 AM, James Blachly wrote:
> On Friday, 18 January 2019 at 15:42:55 UTC, Steven Schveighoffer wrote:
>> On 1/18/19 10:35 AM, Steven Schveighoffer wrote:
>>
>>>
>>> https://github.com/blachlylab/dhtslib/blob/master/source/dhtslib/htslib/hts_log.d#L94 
>>>
>>>
>>>
>>> That is your problem. toStringz is going to attempt to allocate using 
>>> the GC. Allocating during a GC collection causes an 
>>> InvalidMemoryOperationError.
>>>
>>> Take that out of your destructor, and you should not cause that error.
>>>
>>> Alternatively, fix the logger so it doesn't use the GC.
>>
>> If I had to guess why __FUNCTION__ causes it and others do not, then I 
>> would say it's because toStringz has particular cases where it DOESN'T 
>> allocate, and that depends completely on the length of the string.
>>
>> https://github.com/dlang/phobos/blob/master/std/string.d#L364-L365
>>
> 
> Steve: Thanks for your quick reply. Why does manipulation of the default 
> constructor, which is never called, affect whether or not the destructor 
> throws the error?

It's a good question.

My explanation above is slightly wrong, though, it's not just the 
length, but the address of the end byte. If the end byte is on a 4-byte 
boundary, then it allocates, otherwise it checks for a zero (which is 
very likely true, especially with string literals), and then just 
returns the pointer.

When you have behavior changes based on where something is allocated, 
many bets are off. It's almost like the randomness of memory corruption.

I would say, if you fix the destructor to not allocate, and your 
problems all go away, you should assume that's the fix and move on.

Something to consider using instead of toStringz: 
https://github.com/dlang/phobos/blob/5e6fe2f9c8f72f4c3b0497dc363fc61d823ff489/std/internal/cstring.d#L77

This only allocates on the C heap (if necessary) and cleans itself up 
upon going out of scope.

Use like this:

import std.internal.cstring;
auto cmsg = tempCString(msg);
auto cctx = tempCString(ctx);
hts_log(htsLogLevel.HTS_LOG_DEBUG, cctx, cmsg);

-Steve


More information about the Digitalmars-d mailing list