Page 1 of 1

Memory (re)allocation / structure pointer initialisation safety

Posted: Fri Jul 25, 2025 10:50 am
by SnowyDog
In this code I am initialising a memory pointer and a pointer to a structure in a sub function for use outside the sub function. It compiles and works, but is it safe - i.e. will the pointers always stay valid outside the sub function?

I was particularly surprised that ReAllocateMemory() accepts a null pointer. Surely if this is not safe, then the compiler should raise an exception?

Code: Select all

EnableExplicit
; Memory allocation / structure pointer initialisation
; This works, but is it safe?

Structure AStruct
	iVal.i
	*AMemoryBlock
	qVal.q
	*IntegerPointer.Integer
EndStructure

Declare Main()
Declare.i Init(*MyStruct.AStruct)
End Main()

Procedure Main()
	Protected MyStruct.AStruct
	
	MyStruct\iVal=$01234567
	MyStruct\qVal=$0123456789ABCDEF
	
	Debug("MyStruct\AMemoryBlock=$"+Hex(MyStruct\AMemoryBlock))	
	
	Init(@MyStruct)
	
	If MyStruct\AMemoryBlock
		Debug("MyStruct\AMemoryBlock=$"+Hex(MyStruct\AMemoryBlock))
		Debug("MemorySize(MyStruct\AMemoryBlock)="+Str(MemorySize(MyStruct\AMemoryBlock)))
		ShowMemoryViewer(MyStruct\AMemoryBlock,MemorySize(MyStruct\AMemoryBlock))
	EndIf
	
	Debug("MyStruct\iVal=$"+Hex(MyStruct\iVal))
	Debug("MyStruct\qVal=$"+Hex(MyStruct\qVal))	
	Debug("MyStruct\IntegerPointer\i=$"+Hex(MyStruct\IntegerPointer\i))
	
	ProcedureReturn
	
EndProcedure

Procedure.i Init(*MyStruct.AStruct)
	
	Debug("Before realloc, *MyStruct\AMemoryBlock=$"+Hex(*MyStruct\AMemoryBlock))
	*MyStruct\AMemoryBlock=ReAllocateMemory(*MyStruct\AMemoryBlock,131072)
	Debug("After realloc, *MyStruct\AMemoryBlock=$"+Hex(*MyStruct\AMemoryBlock))
	
	If *MyStruct\AMemoryBlock
		FillMemory(*MyStruct\AMemoryBlock,MemorySize(*MyStruct\AMemoryBlock),$A55A5AA5,#PB_Long)
	EndIf
	
	*MyStruct\iVal=$01234567
	*MyStruct\qVal=$0123456789ABCDEF
	*MyStruct\IntegerPointer=AllocateStructure(Integer)
	*MyStruct\IntegerPointer\i=$76543210
	
	ProcedureReturn
	
EndProcedure

Sample output:-

Code: Select all

MyStruct\AMemoryBlock=$0
Before realloc, *MyStruct\AMemoryBlock=$0
After realloc, *MyStruct\AMemoryBlock=$4730048
MyStruct\AMemoryBlock=$4730048
MemorySize(MyStruct\AMemoryBlock)=131072
MyStruct\iVal=$1234567
MyStruct\qVal=$123456789ABCDEF
MyStruct\IntegerPointer\i=$76543210
...(and ShowMemoryViewer() shows that AMemoryBlock contains the $A55A5AA5 pattern as expected)

[Using PB 6.21, Windows 11]

Re: Memory (re)allocation / structure pointer initialisation safety

Posted: Fri Jul 25, 2025 11:45 am
by NicTheQuick
Yes, the pointer will remain valid. They are basically just numbers.
But you've got another problem here if you do the same thing in another context. You need to free the memory again before leaving the Main() procedure because MyStruct will be freed automatically resulting in a memory leak.
In your example you immediately end the program, so that's no problem. But in any other case, do not forget to use FreeMemory().

Re: Memory (re)allocation / structure pointer initialisation safety

Posted: Fri Jul 25, 2025 12:25 pm
by SnowyDog
Yes, the pointer will remain valid. They are basically just numbers.
Do you mean the pointer itself or the allocated memory block it references will remain valid?

Re: Memory (re)allocation / structure pointer initialisation safety

Posted: Fri Jul 25, 2025 12:45 pm
by NicTheQuick
Both. When you allocate memory using ReAllocateMemory() it will exists until you use FreeMemory(). Nothing else will free it again. But if you lost the corresponding pointer it will result in a memory leak because will never be able to free it again without knowing the pointer.

And I just found one minor issue in your code:

Code: Select all

*MyStruct\AMemoryBlock=ReAllocateMemory(*MyStruct\AMemoryBlock,131072)
If ReAllocateMemory fails to allocate 131072 bytes, it will return 0 and the old pointer will still be valid. In this case you lost that initial pointer.
Better do it like so:

Code: Select all

	Protected *newmem
	*newmem = ReAllocateMemory(*MyStruct\AMemoryBlock,131072)
	If Not *newmem
		DebuggerError("Memory could not be allocated."
		ProcedureReturn
	*MyStruct\AMemoryBlock = *newmem