[futurebasic] Re: [FB] Detecting clicks in edit fields

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : June 2011 : Group Archive : Group : All Groups

From: Robert Purves <listrp@...>
Date: Thu, 30 Jun 2011 17:15:42 +1200
Dan Baeckström wrote:

> When I find some really useful code, like Alain's, I want to rearrange it into one (or a set of) local fns that can be called by many different programs, and then put them into MyReallyUsefulFns.incl which is then included in any code that wants to use the fns. Ideally, it would look like this in the case of Alains code (note that the fns probably would have to change places in some cases to avoid errors):

> local fn makectrleventhandler(butno as long,userfn as pointer)
> dim as controlhandlrec chrec  //this record is used as user data
> chrec.ctrlno=butno
> chrec.fnaddress=userfn
> fn CEAddEvent(_kEventClassControl,_kEventControlHitTest)
> fn CEInstallControlEventHandler( button&(butno), @fn MyControlHitHandler,@chrec,0 )
> end fn


Unfortunately, makectrleventhandler() should be in a file "ReallyBadIdeas.incl". You have fallen foul of a notorious gotcha.
<http://en.wikipedia.org/wiki/Dangling_pointer>

After setting the fields of chrec, you stash its address @chrec for use later, after makectrleventhandler() has returned. For this to work, obviously the content of that memory must not change before you access it.

Local variables such as chrec have only temporary existence. They reside on the stack, an area of memory shared by all functions. Only one function at a time claims a particular range of the stack. On returning, a function gives up its claim so as to make the memory available to subsequently called functions. Those function are free to overwrite the memory in any way they choose (which may be different from one compiler to another). 

When makectrleventhandler() returns, the values of chrec.ctrlno and chrec.fnaddress become undefined; that is they could be any value.


The demo below gives wrong results with most choices of compiler and optimization level.

Robert P.

'------------------
include "ConsoleWindow"

begin record Thing
dim as long a, b, c, d
end record

begin globals
dim as ^Thing  gThingP
end globals


local fn PrintThing
'~'1
print gThingP.a, gThingP.b, gThingP.c, gThingP.d
end fn


local fn SetThingAndSaveAddress
'~'1
dim as Thing  t // local var on stack
t.a = 1
t.b = 2
t.c = 3
t.d = 4
gThingP = @t // address of local var
end fn

print "Dangling pointer demo"
fn SetThingAndSaveAddress
// gThingP now points to 'stale' stack memory
fn PrintThing
'------------------