Scott Moore wrote:
From: Russell Whitaker russ@ashlandhome.net
On Mon, 10 Dec 2007, Scott Moore wrote:
[..]
What did you expect to happen?
I expected "dispose" to undo what "new" does. Could not find a comment in gpc's source that states otherwise.
At present,
new(p)
- allocates a block of memory from the heap, the size is the size that p wants to point to.
- returns the address of that memory block.
dispose(p)
- marks the block of memory that p points to as free. (I say "marks" because the block doesn't disapear)
Thus, this works, but shouldn't:
writeln( p^ ); dispose( p ); writeln( p^ );
============================================= 6.5.4 Identified-variables An identified-variable shall denote the variable, if any, identified by the value of the pointer-variable of the identified-variable (see 6 .4 .4 and 6 .6 .5 .3) shall be accessible until the termination of the activation of the program-block or until the variable is made inaccessible (see the required procedure 28 ISO/IEC 7185 :1990(E) dispose, 6.6 .5 .3). NOTE | The accessibility of the variable also depends on the existence of a pointer-variable that has attributed to it the corresponding identifying-value. A pointer-variable shall be a variable-access that denotes a variable possessing a pointer-type . It shall be an error if the pointer-variable of an identified-variable either denotes a nil-value or is undefined. It shall be an error to remove from the set of values of the pointer-type the identifying-value of an identified-variable (see 6 .6 .5 .3) when a reference to the identified-variable exists. Examples: p1fi p1f .fatherf p1's .sibling's .father's 6.5 =========================================================== The statement "writeln( p^ );" after dispose is an "error", dispose left p undefined.
If you dig into gpc's heap.pas you will find code that is the equivalent of:
if p <> nil then dispose(p);
What I'd like to see is the equivalent of:
if p <> nil then begin dispose(p); p := nil; end else writeln( stderr,"WARN: illegal use of dispose");
In places the specs are hard to follow, but I think the specs would allow this.
Russ
====================================================== 6.6 .5.3 Dynamic allocation procedures
...
dispose(q)
shall remove the identifying-value denoted by the expression q from the pointer-type of q . It shall be an error if the identifying-value had been created using the form new(p,c l , . . .,cn).
dispose(q,kl , . . .,km)
shall remove the identifying-value denoted by the expression q from the pointer-type of q . The case-constants k 1, . . .,km shall be listed in order of increasing nesting of the variant-parts . It shall be an error unless the variable had been created using the form new(p,c 1 , . . .,cn ) and m is equal to n . It shall be an error if the variants in the variable identified by the pointer value of q are different from those specified by the values denoted by the case-constants k 1, . . .,km.
NOTE | The removal of an identifying-value from the pointer-type to which it belongs renders the identifiedvariable inaccessible (see 6 .5.4) and makes undefined all variables and functions that have that value attributed (see 6 .6 .3 .2 and 6 .8 .2 .2).
It shall be an error if q has a nil-value or is undefined.
So, again, it is an error (to pass nil to dispose). However, the standard leaves it up to the implementation when and if such errors are detected, so this is a "quality" issue:
================================================= 3.1 Error A violation by a program of the requirements of this International Standard that a processor is permitted to leave undetected. ==================================================
I'll bet a nickel that the dispose nil behavior you saw was designed to compensate for disposals of zero length data. I had to solve that problem, but did it using a key address, i.e., new() returns a specific, predefined location that is the universal zero length pointer.
Scott Moore
Scott Moore wrote:
So, again, it is an error (to pass nil to dispose). However, the standard leaves it up to the implementation when and if such errors are detected, so this is a "quality" issue:
GPC produces an error in standard modes.
I'll bet a nickel that the dispose nil behavior you saw was designed to compensate for disposals of zero length data. I had to solve that problem, but did it using a key address, i.e., new() returns a specific, predefined location that is the universal zero length pointer.
Not really -- it's more for convenience (not having to check for nil before each Dispose; we might have let Dispose set to the pointer to nil afterwards as well if it was reliable; as has been pointed out in this thread, it's not).
For allocations we rely on the underlying C library's heap management. On the system I'm currently on (Linux, glibc), it does allocate some memory (perhaps for internal data) and returns different addresses on each zero allocation, but AFAICS it's allowed according to the C standard to return NULL.
So now that you mention it, there may indeed be a bug on systems whose libc does the latter, with GPC in standard mode, i.e. New (empty-record-pointer) would return nil, and Dispose (nil) would yield a spurious error.
Frank
Frank Heckenbach wrote:
Not really -- it's more for convenience (not having to check for nil before each Dispose; we might have let Dispose set to the pointer to nil afterwards as well if it was reliable; as has been pointed out in this thread, it's not).
There is no replacement in programming for the necessity of careful thinking with everything you do. There is no such thing like absolute "safety" against programming errors. In that regard, any discussion about "safety" is pointless. But, as Peter pointed out, defensive programming will help. Especially if accompanied with good design (for example, it should be crystal clear in the software who owns the pointer).
Regards,
Adriaan van Os