[fpc-pascal]The compiler messes up some pointers.

Michael.VanCanneyt at Wisa.be Michael.VanCanneyt at Wisa.be
Sun Sep 23 03:12:32 CEST 2001


On Sat, 22 Sep 2001 yendor at nic.fi wrote:

>
>
>
> Michael.VanCanneyt at Wisa.be wrote:
> >
> > On Sat, 22 Sep 2001, Jonas Maebe wrote:
> > >
> > > On Sat, 22 Sep 2001 yendor at nic.fi wrote:
> > >
> > > > I have a problem where FPC modifies a pointer without me
> instructing it
> > > > to do so.
> > > > With stucture :
> > > > Type
> > > >   PAnsiString = ^AnsiString;
> > > >   PPAnsiString = ^PAnsiString;
> > > >
> > > > Var
> > > >   RowAP : ^PPAnsiString;
> > > >
> > > > I first create two rows (that are the ansistrings in a pointer of array
> of
> > > > pointer of ansistring structure) and set some data into them. After
> that I
> > > > add one row between these two and initialize it with exactly these
> rows :
> > > >
> > > >   GetMem(RowAP^[1], SizeOf(AnsiString));
> > > >   Writeln(LongInt(RowAP^[2]));
> > > >   RowAP^[1]^ := 'a';
> > > >   Writeln(LongInt(RowAP^[2]));
> > > >
> > > > The program outputs two lines that are : "4284808" and "4284807"
> (the
> > > > values differ of course, but not the difference) which isn't right. I
> can't
> > > > reproduce this in other programs (haven't tried very extensively)
> but I
> > > > don't think that I could ever mess up my program to produce this
> kind of
> > > > thing.
> > >
> > > You are doing very dangerous things. Ansistrings are reference
> counted,
> > > which measn that the compiler normally does a lot of things behind
> your
> > > back. With the above construction, it fails to do these things...
> > >
> > > You have to intialize all memory you allocate this way for storing
> > > ansistrings in explcitely with 0 before storing an ansistring in them, or
> > > you may get random memory corruption.
> > >
> > > I don't know whether the compile should do that automatically in this
> > > case, it's possible it should (but it definitely doesn't currently)
> >
> > It doesn't do it, and isn't supposed to do it. Only New() will initialize
> > any memory for use with ansistrings. When using GetMem() you should
> > explicitly zero out any memory that should be occuped by ansistrings
> > before using it. Failing to do so may and will result in memory
> corruption.
> > In the above case, this should definitely be done.
>
> I agree with Michael about that. The problem is (at least I think that it's)
> that most pascal programmers don't think ansistring as a pointer. Also
> note that you can't do a New(AnsiStringVar); and implementing this will
> require it to properly handle the reference count.
>
> By the way. My
> Var
>   TempL : ^LongInt;
>   A : AnsiString;
>   B : AnsiString;
> Begin
>   A := 'Blaah3';
>   B := A;
>   TempL := Pointer(A);
>   Dec(TempL);
>   Writeln(TempL^);
> End.
>  - proggie returns -1. Is reference counting working?

Yes.
This is an optimization by FPC; constant strings always have item count
-1, whatever the number of strings pointing to it. All other routines
(adding assignment etc) take care of this.

Try
  A := 'Blaah3';
  A := A+'3haalB'b
  B:=A;

Then you should get 3. 3, not 2 because the temporary variable used to
do the assignment is only cleaned when the program reaches the 'end.'
statement.

Doing however:

var
  A : AnsiString;

procedure test (Var b : AnsiString);

Begin
  A := 'Blaah3';
  A := A + '3haalB';
  B := A;
end;

var
  B : AnsiString;
  TempL : ^LongInt;

begin
  test(B);
  TempL := Pointer(B);
  Dec(TempL);
  Writeln(TempL^);
End.

will print 2. Moving the declaration of A into the procedure test will
print 1.

Michael.





More information about the fpc-pascal mailing list