Hey, I'm not sure if this counts as a bug or not so thought I'd ask about it here:
I have the following code:
type
GoodboySave* = object
data: array[5000, uint8]
proc `=destroy`*(s: var GoodboySave) =
discard
var sav: GoodboySave
reset(sav)
The generated C code for system.reset under ARC looks like this:
N_LIB_PRIVATE N_NIMCALL(void, reset__main_6)(tyObject_GoodboySave__V3NLTqc4Fsuvs9b4KG9a39bzg* obj__G9bGxRHjC5xtc0ZF9cAh9cDTA) {
tyObject_GoodboySave__V3NLTqc4Fsuvs9b4KG9a39bzg T1_;
NIM_BOOL* nimErr_;
{nimErr_ = nimErrorFlag();
nimZeroMem((void*)(&T1_), sizeof(tyObject_GoodboySave__V3NLTqc4Fsuvs9b4KG9a39bzg));
eqsink___main_20((&(*obj__G9bGxRHjC5xtc0ZF9cAh9cDTA)), (&T1_));
if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;
}BeforeRet_: ;
}
as you can see, it allocates a new structure T1_ on the stack, zeroes it out, then calls =sink (which was presumably generated due to there being a destructor for the type) to assign it to the destination object.
This turns out to be really terrible for me, because I'm targeting a platform with very little RAM, I don't have 5KB of stack space to spare. So this code clears data far beyond the stack, causing my program to crash unexpectedly further down the line.
Does this count as a compiler bug? Could system.reset be modified so that it calls =destroy in-place, avoiding this issue? Or is it just something I'll have to be aware of?
I think T1_ represents a temporary object, and =sink means =, so this code:
N_LIB_PRIVATE N_NIMCALL(void, reset__main_6)(tyObject_GoodboySave__V3NLTqc4Fsuvs9b4KG9a39bzg* obj__G9bGxRHjC5xtc0ZF9cAh9cDTA) {
tyObject_GoodboySave__V3NLTqc4Fsuvs9b4KG9a39bzg T1_;
NIM_BOOL* nimErr_;
{nimErr_ = nimErrorFlag();
nimZeroMem((void*)(&T1_), sizeof(tyObject_GoodboySave__V3NLTqc4Fsuvs9b4KG9a39bzg));
eqsink___main_20((&(*obj__G9bGxRHjC5xtc0ZF9cAh9cDTA)), (&T1_));
if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;
}BeforeRet_: ;
}
is equivalent to:
proc reset(obj: var GoodboySave) =
obj = GoodboySave()
where GoodboySave() is T1_.
To make it efficient, the implementation can be changed to
proc reset(obj: var GoodboySave) =
`=destroy`(obj)
wasMoved(obj)
But I think you can just define a resetting proc that fits your case, instead of relaying on the standard one.