Page 1 of 2

Posted: Thu Aug 10, 2006 10:47 pm
by freak
> ... return the 1978 for the second debug? If the memory is freed, the value should exist anywhere in memory, right?

By freeing the memory, you just tell the OS that you do not need it anymore. What the OS
then does with it cannot predicted.
The the memory (and its content) can remain for quite a while, or be invalidated
immediately. You may even receive the exact same pointer in a future AllocateMemory() call.

So if you have sensitive Information (like a password), overwriting it with 0 might be a good
thing before freeing the memory.

As for freeing the structured memory: Fred promised a function, but we are still working on
Linux, and with the Mac inbetween the next Update for Windows will be a while.

Using FreeMemory() on the PB strings is something you should do. Yes, i know it seems to work. (at least on some Windows versions)
The truth is though, that PB uses a different Memory heap for AllocateMemory and for the string management.
So theoretically, freeing the one thing with the function for the other (according to the API docs) should not work.
The Memory management of Windows is known to be very forgiving in this respect, so usually it works, yes.
I do not know if this is the case for all Windows versions though. Also the string handling on Linux/Mac is different, so it probably won't work there either.

Here is a very simple trick, that does the job quite nicely. It works on all OS, in PB 3.94 as well as 4.00 and probably will with future Versions as well.
The perfect function so to say ;). Its all about tricking PB into freein the String:

Code: Select all

Procedure FreePBString(*Address)
  Protected String.String  ; the String Structure contains one String element, which is initialized to 0 on procedure start
  PokeL(@String, *Address) ; poke our strings address into the structure
EndProcedure               ; when returning, PB's string free routine for the local structure will actually free the passed string.
Use it like this:

Code: Select all

Structure MyStrings
  a.s
  b.s
  c.s
EndStructure

Procedure test()
  Protected *x.MyStrings = AllocateMemory(SizeOf(MyStrings))
  
  *x\a = Space(4000)
  *x\b = Space(4000)
  *x\c = Space(4000)
  
  FreePBString(@*x\a)
  FreePBString(@*x\b)
  FreePBString(@*x\c)
  
  FreeMemory(*x)
EndProcedure

CallDebugger

For i = 0 To 10000
  test()
Next i

CallDebugger

Posted: Thu Aug 10, 2006 11:30 pm
by helpy
That is really nice! Thank you, freak!

Posted: Fri Aug 11, 2006 12:13 am
by sverson
freak wrote:The perfect function so to say ;)
Great - thanks :)

After adding ZeroMemory it definitely is the perfect function!

Code: Select all

Procedure DeletePBString(*Address,delete.b=#False)
  Protected String.String                  ; the String Structure contains one String element, which is initialized to 0 on procedure start
  PokeL(@String, *Address)                 ; poke our strings address into the structure
  If delete
    RtlZeroMemory_(*Address,Len(String\s)) ; fill the String with zero 
  EndIf
EndProcedure                               ; when returning, PB's string free routine for the local structure will actually free the passed string.

Code: Select all

Structure MyStrings
  a.s
  b.s
  c.s
EndStructure

Procedure.l AvailPhysMem()
  Protected MemStat.MEMORYSTATUS
  GlobalMemoryStatus_(@MemStat)
  ProcedureReturn (MemStat\dwAvailPhys>>10)
EndProcedure

Procedure test()
  Protected *x.MyStrings = AllocateMemory(SizeOf(MyStrings))
  
  *x\a = Space(4000)
  *x\b = Space(4000)
  *x\c = Space(4000)
  
  ; DeletePBString(@*x\a,#True)
  ; DeletePBString(@*x\b,#True)
  ; DeletePBString(@*x\c,#True)
  
  FreeMemory(*x)
EndProcedure

Debug Str((4001*3*10000)>>10)+" Kb allocated!"

mem1.l = AvailPhysMem()
For i = 0 To 10000
  test()
Next i
mem2.l = AvailPhysMem()
Debug Str(mem1)+" Kb"
Debug Str(mem2)+" Kb"
Debug Str(mem1-mem2)+" Kb"
CallDebugger
Uncomment DeletePBString to to free and clear all strings.
There will remain just a little difference due to other programs allocate or free memory while the test is running.

;-) sverson

Posted: Fri Aug 11, 2006 9:55 am
by Psychophanta
freak wrote:

Code: Select all

Procedure FreePBString(*Address)
  Protected String.String  ; the String Structure contains one String element, which is initialized to 0 on procedure start
  PokeL(@String, *Address) ; poke our strings address into the structure
EndProcedure               ; when returning, PB's string free routine for the local structure will actually free the passed string.
:?:
I don't understand a thing :?
Can anybody explain that better? Or write the same code in ASM to undestand it?

Posted: Fri Aug 11, 2006 10:12 am
by helpy
Psychophanta wrote:
freak wrote:

Code: Select all

Procedure FreePBString(*Address)
  Protected String.String  ; the String Structure contains one String element, which is initialized to 0 on procedure start
  PokeL(@String, *Address) ; poke our strings address into the structure
EndProcedure               ; when returning, PB's string free routine for the local structure will actually free the passed string.
:?:
I don't understand a thing :?
Can anybody explain that better? Or write the same code in ASM to undestand it?
"String.String" a local structure variable with ONE string element. All local structure variables are freed by PB when the procedure will be finished.

With "PokeL(@String, *Address) the passed string address is assigned to the structure variable. And know you have access to the string, which is identified by the passed string pointer, with the local structure variable String.String.

==> side effect: when the procedure is finished PB will free/release all local variables ... and also the local structure variables, which points to the passed string pointer.

Hope you understand a german native speaker ;-)

cu, helpy

Posted: Fri Aug 11, 2006 10:25 am
by Psychophanta
Thank you Helpy, you are a Helper :)
In fact this trick uses the PB internals.
It is curious (and understandable) that when used another local variable than string type it doesn't work, so i got crazy, but now it is clear.
However i see there is dangerous to play with the pointers of the strings, over all when them is passed to functions. :o

Posted: Fri Aug 11, 2006 11:03 am
by helpy
There is a conflict with the debugger!

Code: Select all

Structure MyStrings
	StructureUnion
  	a.s
  	pa.l
  EndStructureUnion
EndStructure

Procedure FreePBString(*Address)
  Protected String.String  ; the String Structure contains one String element, which is initialized to 0 on procedure start
  PokeL(@String, *Address) ; poke our strings address into the structure
EndProcedure               ; when returning, PB's string free routine for the local structure will actually free the passed string.

*x.MyStrings = AllocateMemory(SizeOf(MyStrings))

For x = 1 To 2
	*x\a = "A String ..."
	Debug Str(*x\pa) + " - " + *x\a
	
	FreePBString(@*x\a)
	Debug Str(*x\pa) + " - " + *x\a
Next x
 
FreeMemory(*x)
With debugger on it crashes when FreePBString is called the second time.

Without debugger it works without a crash.

cu, helpy

Posted: Fri Aug 11, 2006 11:46 am
by Psychophanta
If you free the .s field, you need to Allocate memory again for the variable.
Which means that the correct and safe way is to FreeMemory() after use the Timo's function, and then allocate again for the next loop.
Like that:

Code: Select all

Structure MyStrings
   StructureUnion
     a.s
     pa.l
  EndStructureUnion
EndStructure

Procedure FreePBString(*Address)
  Protected String.String  ; the String Structure contains one String element, which is initialized to 0 on procedure start
  PokeL(@String, *Address) ; poke our strings address into the structure
EndProcedure               ; when returning, PB's string free routine for the local structure will actually free the passed string.

For x = 1 To 2
  *x.MyStrings = AllocateMemory(SizeOf(MyStrings))

   *x\a = "A String ..."
   Debug Str(*x\pa) + " - " + *x\a
    
   FreePBString(@*x\a)
   Debug Str(*x\pa) + " - " + *x\a
  FreeMemory(*x.MyStrings)
Next x

Re: Freeing Strings

Posted: Sun Aug 13, 2006 1:25 pm
by mskuma
sverson wrote:see also SecureZeroMemory. (http://msdn.microsoft.com/library/defau ... memory.asp)
I was just having a look at this tonight.. unless I'm mistaken, it doesn't seem to work in PB4?

Code: Select all

SecureZeroMemory_(*buff, MemorySize(*buff)) ; fails with 'not function' error
but

Code: Select all

ZeroMemory_(*buff, MemorySize(*buff))   ; is ok

Posted: Mon Aug 14, 2006 12:10 am
by sverson
@mskuma:
  • http://msdn.microsoft.com/library/en-us ... frame=true
    ...The effect of RtlSecureZeroMemory is identical to that of RtlZeroMemory, except that it is guaranteed to zero the memory location, even if it is not subsequently written to. (The compiler can optimize away a call to RtlZeroMemory, if it determines that the caller does not access that memory range again.)...
Maybe PB does not optimize away a call to RtlZeroMemory so RtlZeroMemory does the job and RtlSecureZeroMemory is not needed?!?

;-) sverson

Posted: Mon Aug 14, 2006 12:26 am
by mskuma
Hi sverson. Thanks for your comment.
sverson wrote:Maybe PB does not optimize away a call to RtlZeroMemory so RtlZeroMemory does the job and RtlSecureZeroMemory is not needed?!?
Maybe.. who know? The above statement is similar to the one for SecureZeroMemory, i.e.
Use this function instead of ZeroMemory when you want to ensure that your data will be overwritten promptly, as the compiler can optimize a call to ZeroMemory by removing it entirely. A call to SecureZeroMemory will not be optimized.
My concern was I thought PB supported any WinAPI command by simply post-pending the underscore character to the function, but in this case (using SecureZeroMemory & also RtlZeroMemory) fails giving the error I mentioned. I'm not understanding something about PB obviously.

This issue about optimising away a statement is interesting though. I guess it only applies to MS tools :wink:

Posted: Sat Feb 17, 2007 3:27 pm
by srod
Have followed this thread with interest and now that I find myself using dynamically allocated structures containing strings, I am at last using Freak's tip.

I have one almost daft question, but I want to be absolutely sure that all memory is being freed correctly.

@Freak: in the following code which uses your 'perfect function' :) ,

Code: Select all

Structure MyStrings 
  a.s 
EndStructure 

Procedure test() 
  Protected *x.MyStrings = AllocateMemory(SizeOf(MyStrings)) 
  
  *x\a = "Testing!"
  *x\a = "Will the preceeding string 'Testing' be freed by this allocation?"
  
  FreePBString(@*x\a) 
  
  FreeMemory(*x) 
EndProcedure 

CallDebugger 

For i = 0 To 10000 
  test() 
Next i 

CallDebugger
will the command:

Code: Select all

*x\a = "Will the preceeding string 'Testing' be freed by this allocation?"
automatically free the memory allocated by the previous command

Code: Select all

*x\a = "Testing!"
?

Common sense dictates an answer of 'yes, don't be an idiot all of your life' :) , but as I say I just want to be 100% sure that I am left with no memory leaks.

Thanks.

Posted: Sat Feb 17, 2007 3:32 pm
by Trond
Yes it will be freed.

Posted: Sat Feb 17, 2007 3:48 pm
by srod
Thanks. Always worth asking if even a tiny amount of doubt festers! :)

Posted: Fri Jul 20, 2007 5:16 pm
by Nico

Code: Select all

Procedure DeletePBString(*Address,delete.b=#False)
  Protected String.String                  ; the String Structure contains one String element, which is initialized to 0 on procedure start
  PokeL(@String, *Address)                 ; poke our strings address into the structure
  If delete
    RtlZeroMemory_(*Address,Len(String\s)) ; fill the String with zero
  EndIf
EndProcedure                               ; when returning, PB's string free routine for the local structure will actually free the passed string.
-->RtlZeroMemory_(*Address,Len(String\s)+1)