Memory (re)allocation / structure pointer initialisation safety

Just starting out? Need help? Post your questions and find answers here.
User avatar
SnowyDog
User
User
Posts: 33
Joined: Tue Jun 10, 2014 8:18 pm

Memory (re)allocation / structure pointer initialisation safety

Post 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]
User avatar
NicTheQuick
Addict
Addict
Posts: 1504
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

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

Post 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().
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
SnowyDog
User
User
Posts: 33
Joined: Tue Jun 10, 2014 8:18 pm

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

Post 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?
User avatar
NicTheQuick
Addict
Addict
Posts: 1504
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

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

Post 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
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Post Reply