Board index » delphi » test being initialised of pointers and objects

test being initialised of pointers and objects

Is it possible to test whether a pointer variable has its space on the
heap reserved or not?
The same question for an object. Find out wheter it's constructor has
been called or prevent making calls to the object after a calling it's
destructor, whithout crashing the program.

Something like

type pi:^integer;
var i: pi;

Procedure dosomething(var i:pi);
begin
  if not TestBeingInitialised(i) then new(i),
  i^=......
end;

begin
   dosomething(i);
....
 if TestBeingInitialised(i) then dispose(i);
   TestBeingInitialised(i);   {---->should return false now}
end.

A simple solution I've come up with is to check the pointer being nil,
but it is not relable.

const i:pi=nil;    {instead of var}

function testbeinginitialised(p:pointer):boolean;
begin
   testbeinginitialised := (p<>nil);
end

Dispose does not set the pointer back to nil, so this method is not
reliable.
I am working with programs of > 30000 lines of code in BP7.01. Mistakes
are usually very difficult to trace. If an error occurs the IDE is never
able to find it's error address. Why is that?, or better is it possible
to fix that.

tia
Femme

 

Re:test being initialised of pointers and objects


Quote

>Is it possible to test whether a pointer variable has its space on the
>heap reserved or not?
>The same question for an object. Find out wheter it's constructor has
>been called or prevent making calls to the object after a calling it's
>destructor, whithout crashing the program.

>Something like

>type pi:^integer;
>var i: pi;

>Procedure dosomething(var i:pi);
>begin
>  if not TestBeingInitialised(i) then new(i),
>  i^=......
>end;

>begin
>   dosomething(i);
>....
> if TestBeingInitialised(i) then dispose(i);
>   TestBeingInitialised(i);   {---->should return false now}
>end.

>A simple solution I've come up with is to check the pointer being nil,
>but it is not relable.

>const i:pi=nil;    {instead of var}

>function testbeinginitialised(p:pointer):boolean;
>begin
>   testbeinginitialised := (p<>nil);
>end

>Dispose does not set the pointer back to nil, so this method is not
>reliable.
>I am working with programs of > 30000 lines of code in BP7.01. Mistakes
>are usually very difficult to trace. If an error occurs the IDE is never
>able to find it's error address. Why is that?, or better is it possible
>to fix that.

>tia
>Femme

  After disposing a pointer set the pointer var back to nil,  that should make
the nil test functon reliable.

  The inability to track errors, I don't know, but would like to find out too.
I've only used TPW 1.5 and TP7. I've rarely used the error location capability
( in TPW 1.5 ), but when I have it always seemed to work.

cheers
jk

Re:test being initialised of pointers and objects


Quote
Femme Verbeek wrote in message ...
>Is it possible to test whether a pointer variable has its space on the
>heap reserved or not?
>The same question for an object. Find out wheter it's constructor has
>been called or prevent making calls to the object after a calling it's
>destructor, whithout crashing the program.

>Something like

>type pi:^integer;
>var i: pi;

>Procedure dosomething(var i:pi);
>begin
>  if not TestBeingInitialised(i) then new(i),
>  i^=......
>end;

>begin
>   dosomething(i);
>....
> if TestBeingInitialised(i) then dispose(i);
>   TestBeingInitialised(i);   {---->should return false now}
>end.

>A simple solution I've come up with is to check the pointer being nil,
>but it is not relable.

>const i:pi=nil;    {instead of var}

>function testbeinginitialised(p:pointer):boolean;
>begin
>   testbeinginitialised := (p<>nil);
>end

>Dispose does not set the pointer back to nil, so this method is not
>reliable.
>I am working with programs of > 30000 lines of code in BP7.01. Mistakes
>are usually very difficult to trace. If an error occurs the IDE is
never
>able to find it's error address. Why is that?, or better is it possible
>to fix that.

You could patch the RTL at runtime to set pointers to nil after
dispose/freemem. There's a unit in Swag (in MEMORY.SWG) that does
some runtime-patching of the heap-manager for real mode, but I'm
sure similar code can be produced for DPMI. If I can find the time
I'll have a look into it, but I'm not promising anything.

Robert
--
Robert AH Prins
pr...@bigfoot.com

Re:test being initialised of pointers and objects


Quote

>Femme Verbeek wrote in message ...
>>Is it possible to test whether a pointer variable has its space on the
>>heap reserved or not?
>>The same question for an object. Find out wheter it's constructor has
>>been called or prevent making calls to the object after a calling it's
>>destructor, whithout crashing the program.

>>Something like

>>type pi:^integer;
>>var i: pi;

>>Procedure dosomething(var i:pi);
>>begin
>>  if not TestBeingInitialised(i) then new(i),
>>  i^=......
>>end;

>>begin
>>   dosomething(i);
>>....
>> if TestBeingInitialised(i) then dispose(i);
>>   TestBeingInitialised(i);   {---->should return false now}
>>end.

>>A simple solution I've come up with is to check the pointer being nil,
>>but it is not relable.

>>const i:pi=nil;    {instead of var}

>>function testbeinginitialised(p:pointer):boolean;
>>begin
>>   testbeinginitialised := (p<>nil);
>>end

>>Dispose does not set the pointer back to nil, so this method is not
>>reliable.
>>I am working with programs of > 30000 lines of code in BP7.01. Mistakes
>>are usually very difficult to trace. If an error occurs the IDE is
>never
>>able to find it's error address. Why is that?, or better is it possible
>>to fix that.

>You could patch the RTL at runtime to set pointers to nil after
>dispose/freemem. There's a unit in Swag (in MEMORY.SWG) that does
>some runtime-patching of the heap-manager for real mode, but I'm
>sure similar code can be produced for DPMI. If I can find the time
>I'll have a look into it, but I'm not promising anything.

>Robert
>--
>Robert AH Prins
>pr...@bigfoot.com

  I wasn't suggesting a patch of the RTL, just inserting a p:=nil statement (
for example) after each call to dispose in the program code.

jk

Re:test being initialised of pointers and objects


Quote

> You could patch the RTL at runtime to set pointers to nil after
> dispose/freemem. There's a unit in Swag (in MEMORY.SWG) that does
> some runtime-patching of the heap-manager for real mode, but I'm
> sure similar code can be produced for DPMI. If I can find the time
> I'll have a look into it, but I'm not promising anything.

> Robert
> --
> Robert AH Prins
> pr...@bigfoot.com

I would be very endebted and thankful if you would do so. Doing such a
thing goes far beyond my capabilities as programmer. I'm simply trying to
write very stable code, which warns against errors like this. It does not
occur very often, but when it does the error is very hard to trace.

Actually I was hoping that there would be a possibility to search the
pointer lookup table and see if the pointed memory is indeed reserved for
that pointer. I have no idea how that works internally. Something simlar
for objects.

thnx
Femme

Re:test being initialised of pointers and objects


"Gdt876" <gdt...@aol.comhello> schreef in bericht
news:20021019174501.14633.00002299@mb-fw.aol.com...

Quote

> >Is it possible to test whether a pointer variable has its space on the
> >heap reserved or not?
> >The same question for an object. Find out wheter it's constructor has
> >been called or prevent making calls to the object after a calling it's
> >destructor, whithout crashing the program.

> >Something like

> >type pi:^integer;
> >var i: pi;

> >Procedure dosomething(var i:pi);
> >begin
> >  if not TestBeingInitialised(i) then new(i),
> >  i^=......
> >end;

> >begin
> >   dosomething(i);
> >....
> > if TestBeingInitialised(i) then dispose(i);
> >   TestBeingInitialised(i);   {---->should return false now}
> >end.

> >A simple solution I've come up with is to check the pointer being nil,
> >but it is not relable.

> >const i:pi=nil;    {instead of var}

> >function testbeinginitialised(p:pointer):boolean;
> >begin
> >   testbeinginitialised := (p<>nil);
> >end

> >Dispose does not set the pointer back to nil, so this method is not
> >reliable.
> >I am working with programs of > 30000 lines of code in BP7.01.
Mistakes
> >are usually very difficult to trace. If an error occurs the IDE is
never
> >able to find it's error address. Why is that?, or better is it
possible
> >to fix that.

> >tia
> >Femme

>   After disposing a pointer set the pointer var back to nil,  that
should make
> the nil test functon reliable.

Of cource and I'm using that.
The problem is that in my programs there are often >100 000 pointers
defined of all different kinds at hundreds of places in the program.
Parts of the code are older than 10 - 15 years. Most of the pointers
themselves are dynamically defined, within a complex object structure,
who themselves can be pointers or not.
Errors don't occur very often, but when they do, they are very difficult
to trace.

Quote
>   The inability to track errors, I don't know, but would like to find
out too.
> I've only used TPW 1.5 and TP7. I've rarely used the error location
capability
> ( in TPW 1.5 ), but when I have it always seemed to work.

It never worked in protected mode.
For small programs it works but only in real mode. If you are using OOP
it usually still can't find the error address.
Sometimes I recompile to real mode with a minimum of data so I can debug
it. I know I should use the stand alone de{*word*81} for that but I did not
use that yet.

Femme

Re:test being initialised of pointers and objects


Quote

>"Gdt876" <gdt...@aol.comhello> schreef in bericht
>news:20021019174501.14633.00002299@mb-fw.aol.com...

>> >Is it possible to test whether a pointer variable has its space on the
>> >heap reserved or not?
>> >The same question for an object. Find out wheter it's constructor has
>> >been called or prevent making calls to the object after a calling it's
>> >destructor, whithout crashing the program.

>> >Something like

>> >type pi:^integer;
>> >var i: pi;

>> >Procedure dosomething(var i:pi);
>> >begin
>> >  if not TestBeingInitialised(i) then new(i),
>> >  i^=......
>> >end;

>> >begin
>> >   dosomething(i);
>> >....
>> > if TestBeingInitialised(i) then dispose(i);
>> >   TestBeingInitialised(i);   {---->should return false now}
>> >end.

>> >A simple solution I've come up with is to check the pointer being nil,
>> >but it is not relable.

>> >const i:pi=nil;    {instead of var}

>> >function testbeinginitialised(p:pointer):boolean;
>> >begin
>> >   testbeinginitialised := (p<>nil);
>> >end

>> >Dispose does not set the pointer back to nil, so this method is not
>> >reliable.
>> >I am working with programs of > 30000 lines of code in BP7.01.
>Mistakes
>> >are usually very difficult to trace. If an error occurs the IDE is
>never
>> >able to find it's error address. Why is that?, or better is it
>possible
>> >to fix that.

>> >tia
>> >Femme

>>   After disposing a pointer set the pointer var back to nil,  that
>should make
>> the nil test functon reliable.

>Of cource and I'm using that.
>The problem is that in my programs there are often >100 000 pointers
>defined of all different kinds at hundreds of places in the program.
>Parts of the code are older than 10 - 15 years. Most of the pointers
>themselves are dynamically defined, within a complex object structure,
>who themselves can be pointers or not.
>Errors don't occur very often, but when they do, they are very difficult
>to trace.

  If you can't live with the errors then the program has to be rewritten so it
doesn't call uninitialized objects, or some type of error catching scheme will
have to be implemented to catch errors and deal with them in a graceful manner.
I don't see any other way than a rewrite.
  I've rewritten old program code for employers before, to make it bulletproof,
but they didn't want to go through all the testing necessary to ensure that it
was completely safe. They would rather just stick with old dodgy code and live
with the problems it created. If thats what the customer wants, so be it,

  OTOH, if they want a rewritten app that is bulletproof, hooray for them ! :)

jk

.    

Re:test being initialised of pointers and objects


Quote
Gdt876 wrote in message <20021020100731.08496.00002...@mb-cj.aol.com>...

>>Femme Verbeek wrote in message ...
>>>Is it possible to test whether a pointer variable has its space on
the
>>>heap reserved or not?
>>>The same question for an object. Find out wheter it's constructor has
>>>been called or prevent making calls to the object after a calling
it's
>>>destructor, whithout crashing the program.

>>>Something like

>>>type pi:^integer;
>>>var i: pi;

>>>Procedure dosomething(var i:pi);
>>>begin
>>>  if not TestBeingInitialised(i) then new(i),
>>>  i^=......
>>>end;

>>>begin
>>>   dosomething(i);
>>>....
>>> if TestBeingInitialised(i) then dispose(i);
>>>   TestBeingInitialised(i);   {---->should return false now}
>>>end.

>>>A simple solution I've come up with is to check the pointer being
nil,
>>>but it is not relable.

>>>const i:pi=nil;    {instead of var}

>>>function testbeinginitialised(p:pointer):boolean;
>>>begin
>>>   testbeinginitialised := (p<>nil);
>>>end

>>>Dispose does not set the pointer back to nil, so this method is not
>>>reliable.
>>>I am working with programs of > 30000 lines of code in BP7.01.
Mistakes
>>>are usually very difficult to trace. If an error occurs the IDE is
>>never
>>>able to find it's error address. Why is that?, or better is it
possible
>>>to fix that.

>>You could patch the RTL at runtime to set pointers to nil after
>>dispose/freemem. There's a unit in Swag (in MEMORY.SWG) that does
>>some runtime-patching of the heap-manager for real mode, but I'm
>>sure similar code can be produced for DPMI. If I can find the time
>>I'll have a look into it, but I'm not promising anything.

>  I wasn't suggesting a patch of the RTL, just inserting a p:=nil
> statement (for example) after each call to dispose in the program
> code.

Patching the RTL is very difficult, you will have to reverse
disassemble some x86 code and IIRC the object handling RTL module
also calls the low level heap de-allocation routine and so would
also need patching.

However, run-time patching of the RTL would generate the shortest
possible code and you don't have to worry about missing any
pointers.

Robert
--
Robert AH Prins
pr...@bigfoot.com

Re:test being initialised of pointers and objects


Quote
In article <ur663nj6cfd...@corp.supernews.com>, Femme Verbeek wrote:

> Of cource and I'm using that.
> The problem is that in my programs there are often >100 000 pointers
> defined of all different kinds at hundreds of places in the program.
> Parts of the code are older than 10 - 15 years. Most of the pointers
> themselves are dynamically defined, within a complex object structure,
> who themselves can be pointers or not.
> Errors don't occur very often, but when they do, they are very difficult
> to trace.

Do you use some kind of heap-trace unit?

Re:test being initialised of pointers and objects


Quote
In article <ur663m6qs59...@corp.supernews.com>, Femme Verbeek wrote:

> I would be very endebted and thankful if you would do so. Doing such a
> thing goes far beyond my capabilities as programmer. I'm simply trying to
> write very stable code, which warns against errors like this. It does not
> occur very often, but when it does the error is very hard to trace.

How would this be possible btw? Do freemem and getmem et al use VAR
or CONST parameters?

If not, the called procedure doesn't have the address to NIL.

IIRC that was the reason why Delphi switched to using a different function
FREEANDNIL()

Re:test being initialised of pointers and objects


Quote
Femme Verbeek <f...@{*word*104}jet.nl> wrote:
> Is it possible to test whether a pointer variable has its space on the
> heap reserved or not?

  Generally: NO :(

[deleted]

  You can only dispose variable via self-wrote function like this:

Uses Objects;
{...}
procedure DisposeObj(Var P);
begin
  if PtrRec (P).Seg > 0 then
   begin
    Dispose (PObject(P), Done);
    Pointer(P) := nil;
   end;
end;

  And then testing pointers via

Quote
> function testbeinginitialised(p:pointer):boolean;
> begin
>    testbeinginitialised := (p<>nil);
> end

  Also built-in function ASSIGNED() :)

P.S.  Of course if you have RTL sources, you can correct
Dispose()/FreeMem() code in it ;)

--
   Varjonov Konstantin       varkos^mail.ru      http://ghsrl.newmail.ru

Re:test being initialised of pointers and objects


Quote
Femme Verbeek wrote in message ...

>> You could patch the RTL at runtime to set pointers to nil after
>> dispose/freemem. There's a unit in Swag (in MEMORY.SWG) that does
>> some runtime-patching of the heap-manager for real mode, but I'm
>> sure similar code can be produced for DPMI. If I can find the time
>> I'll have a look into it, but I'm not promising anything.

> I would be very endebted and thankful if you would do so. Doing
> such a thing goes far beyond my capabilities as programmer.

From what you've told us since you've been posting to clpb, I think
you're pretty modest.

Quote
> I'm simply trying to write very stable code, which warns against
> errors like this. It does not  occur very often, but when it
> does the error is very hard to trace.

What environment are you writing for, real mode or DPMI, or Gates'
Garbage?

Quote
> Actually I was hoping that there would be a possibility to search
> the pointer lookup table and see if the pointed memory is indeed
> reserved for that pointer. I have no idea how that works internally.
> Something simlar for objects.

For real mode this would definitely be possible, just scan the freelist
and check that the pointer contains a non-freelist address. DPMI would
be a bit trickier, but I'm sure that it would be possible to document
the method storage is allocated.

Yesterday evening I had a look at the code and as I mentioned in my
previous posting, there is need to reverse disassemble x86 code, as
the dispose routine is passed a value parameter rather than a var
parameter. There's also the slightly tinier problem of the $G switch,
which causes the compiler to either generate 'mov ax, value/push ax',
'push word-extended immediate byte' or 'push immediate word'. The
pointer itself can be pushed in a variety of ways, either as
'push [addr[+2]]', 'push [bp[+x[+2]]]', 'push [bp+di[+x[+2]]]' and
possibly even others, but all have one thing in common, subtract
0x3830 from the first word of the instruction encoding and add 0x0000
after it to create the 'mov ....' to zero the segment & offset parts
of the pointer.

The intercept routine would have to modify the return address of the
RTL FreeMem routine to point to a routine that disassembles the code
just before the generated far call to FreeMem and builds the required
move instructions, or possibly, given that the 8086/286 are all but
extinct, a single 386 MOV (or shorter, AND) instruction...

Doing the same for the extended Dispose(p, destruct) construction
might be easier, but you'll have to send me some very simple code that
actually uses objects (use my onetel address!), because I have never
used them and I simply don't have the time to learn about them now.

Robert
--
Robert AH Prins
pr...@bigfoot.com

Re:test being initialised of pointers and objects


Quote
"Femme Verbeek" <f...@{*word*104}jet.nl> wrote in message

news:ur31rc32cj237f@corp.supernews.com...

Quote
> Is it possible to test whether a pointer variable has its space on the
> heap reserved or not?
> The same question for an object. Find out wheter it's constructor has
> been called or prevent making calls to the object after a calling it's
> destructor, whithout crashing the program.

Don't know about pointers in general, but for objects with virtual methods,
TP can check whether the constructor has been called. With range checking
turned on, before calling a virtual method, TP finds the address of the VMT
(which it has to anyway, to launch a virtual method) and adds the first
couple of words in the VMT. The first word is sizeof(that type) and the
second is that * -1 so adding the two gives 0. If it doesn't, the pointer
mustn't have been pointing at a constructed object. This only applies with
{$R+}; it works in real mode, I don't know about PM.

FP

Re:test being initialised of pointers and objects


From: "Robert AH Prins" <pr...@onetel.net.uk>

Quote
> Gdt876 wrote in message <20021020100731.08496.00002...@mb-cj.aol.com>...

> >>Femme Verbeek wrote in message ...
...

> >>You could patch the RTL at runtime to set pointers to nil after
> >>dispose/freemem. There's a unit in Swag (in MEMORY.SWG) that does
> >>some runtime-patching of the heap-manager for real mode, but I'm
> >>sure similar code can be produced for DPMI. If I can find the time
> >>I'll have a look into it, but I'm not promising anything.

> >  I wasn't suggesting a patch of the RTL, just inserting a p:=nil
> > statement (for example) after each call to dispose in the program
> > code.

> Patching the RTL is very difficult, you will have to reverse
> disassemble some x86 code and IIRC the object handling RTL module
> also calls the low level heap de-allocation routine and so would
> also need patching.

> However, run-time patching of the RTL would generate the shortest
> possible code and you don't have to worry about missing any
> pointers.

If you modify NewPtr and DisposePtr (BP\RTL\SYS\HEAP.ASM) and recompile the
RTL you can do lots of stuff - you don't necessarily need to patch the RTL.
I don't see how you could set pointers to NIL automatically, although you
can certainly fill new'd or disposed memory with an obviously-uninitialised
value ($CC is suggested), add guard blocks and so on. And write a list of
allocated/freed pointers and the calling address to file, if you're not in a
hurry, so you can look for mismatches later. Get the calling address off the
heap and subtract (PrefixSeg+$10) from the segment. (I don't know of a
freely available modification that will do this; I know it's possible
because there was such a patched RTL in the last place I worked in, but I'm
not there any more.)

FP

Re:test being initialised of pointers and objects


"Marco van de Voort" <mar...@toad.stack.nl> schreef in bericht
news:slrnar7jf6.2b2n.marcov@toad.stack.nl...

Quote
> In article <ur663nj6cfd...@corp.supernews.com>, Femme Verbeek wrote:

> > Of cource and I'm using that.
> > The problem is that in my programs there are often >100 000 pointers
> > defined of all different kinds at hundreds of places in the program.
> > Parts of the code are older than 10 - 15 years. Most of the pointers
> > themselves are dynamically defined, within a complex object
structure,
> > who themselves can be pointers or not.
> > Errors don't occur very often, but when they do, they are very
difficult
> > to trace.

> Do you use some kind of heap-trace unit?

No never hard of such a thing. It would probably be to complicated if you
have 10000 pointers defined.
For me the common way to find these very difficult errors, is to
implement a trace routine. Which writes remarks to a file to tell whre it
was. I simply place lots such commands in the code near where I suspect
the error. After the crash the log file can be read. By narrowing it down
it is possible to find the error relatively quickly. But in most cases
the error is occurs in the older well tested routines, while the cause
lies in a new application that was build from it.

Femme

Go to page: [1] [2]

Other Threads