Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2015-12

Problem with objects

13 messages · 6 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Santiago Amposta

Hello:
I use fpc 2.6.4 and I have a problem of memory leaks, strange errors, etc. Finally I have tracked it to this:

TSimpleArrayString=object
    List:array of String;
end;
TDerivedArrayString=object(TSimpleArrayString)
    other_field:integer;
end;
procedure TestSimple;
var
 A:TSimpleArrayString;
begin
  setLength(A.List,0);
end;
procedure TestDerived;
var
 A:TDerivedArrayString;
begin
  setLength(A.List,0);
end;
TestSimple; // Works Fine,
TestDerived; // rises an exception SIGSEGV on setLength

What am I doing wrong?

Regards Santiago A.
Dennis Poon
to Santiago Amposta
Santiago Amposta wrote 32 lines
Hello: I use fpc 2.6.4 and I have a problem of memory leaks, strange errors, etc. Finally I have tracked it to this: TSimpleArrayString=object List:array of String; end; TDerivedArrayString=object(TSimpleArrayString) other_field:integer; end; procedure TestSimple; var A:TSimpleArrayString; begin setLength(A.List,0); end; procedure TestDerived; var A:TDerivedArrayString; begin setLength(A.List,0); end; TestSimple; // Works Fine, TestDerived; // rises an exception SIGSEGV on setLength What am I doing wrong?

Did you call A.Create before calling TestDerived? Maybe A.List was not initialized (which is done in constructor Create) and contains an invalid pointer (to dynamic array of string).
When you call SetLength, it decrements the reference count of A.List (which is not nil) and raisesSIGSEGV.

Dennis

Santiago A.
to Dennis Poon
Dennis Poon wrote 45 lines
Santiago Amposta wrote: > Hello: > I use fpc 2.6.4 and I have a problem of memory leaks, strange errors, > etc. Finally I have tracked it to this: > > TSimpleArrayString=object > List:array of String; > end; > > TDerivedArrayString=object(TSimpleArrayString) > other_field:integer; > end; > > procedure TestSimple; > var > A:TSimpleArrayString; > begin > setLength(A.List,0); > end; > > procedure TestDerived; > var > A:TDerivedArrayString; > begin > setLength(A.List,0); > end; > > > TestSimple; // Works Fine, > TestDerived; // rises an exception SIGSEGV on setLength > > What am I doing wrong? > Did you call A.Create before calling TestDerived? Maybe A.List was not initialized (which is done in constructor Create) and contains an invalid pointer (to dynamic array of string). When you call SetLength, it decrements the reference count of A.List (which is not nil) and raisesSIGSEGV. Dennis _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

It's an object, not a class inherited from Tobject, so it hasn't create constructor.

Saludos Santi
Howard Page-Clark
to Santiago A.
Santiago A. wrote
It's an object, not a class inherited from Tobject, so it hasn't create constructor.
Try this:
program simpleObjConsole;
type
   { TSimpleArrayString }
   TSimpleArrayString=object
   public
      List:array of String;
      constructor Init;
      destructor Destroy;
      function AddedTextIndex(const aText: string): integer;
      function StringCount: integer;
   end;
   constructor TSimpleArrayString.Init;
   begin
     SetLength(List, 0);
   end;
   destructor TSimpleArrayString.Destroy;
   begin
     SetLength(List, 0);
   end;
   function TSimpleArrayString.AddedTextIndex(const aText: string): integer;
   begin
     Result:=Length(List);
     SetLength(List, Result+1);
     List[Result]:=aText;
   end;
   function TSimpleArrayString.StringCount: integer;
   begin
     Result:=Length(List);
   end;
type
   { TDerivedArrayString }
   TDerivedArrayString=object(TSimpleArrayString)
      other_field:integer;
   public
      constructor Init(anInt: integer);
   end;
   constructor TDerivedArrayString.Init(anInt: integer);
   begin
     inherited Init;
     other_field:=anInt;
   end;
   procedure TestDerived;
   var
     idx, n: integer;
     das: TDerivedArrayString;
   begin
     das.Init(19);
     idx:=das.AddedTextIndex('test string');
     n:=das.StringCount;
     WriteLn('das has ',das.StringCount,' string(s), and
das.other_field=',das.other_field);
     if (n > 0) then
       WriteLn('First string in das.List is "',das.List[idx],'" at
index:',idx);
     ReadLn;
     das.Destroy;
   end;
begin
   TestDerived;
end.

---
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Lukasz Sokol
to Santiago Amposta: Hello: I use fpc 2.6.4 and I have a problem of memory leaks, strange errors, etc. Finally…
Santiago Amposta wrote 32 lines
Hello: I use fpc 2.6.4 and I have a problem of memory leaks, strange errors, etc. Finally I have tracked it to this: TSimpleArrayString=object List:array of String; end; TDerivedArrayString=object(TSimpleArrayString) other_field:integer; end; procedure TestSimple; var A:TSimpleArrayString; begin setLength(A.List,0); end; procedure TestDerived; var A:TDerivedArrayString; begin setLength(A.List,0); end; TestSimple; // Works Fine, TestDerived; // rises an exception SIGSEGV on setLength What am I doing wrong?

I might be wrong... but I just tried:

stepping into TestSimple in the order OP specified, hovering over A.List (actually over .List only, see below*) gives
A.List = (0x0)
before setLength

and
A.List = ()
after the setLength;

then stepped through to TestDerived, in which the hover over .List gives

A.List = ()

before setLength,
and an External: SIGSEGV At Address 403CDC when trying to step over setLength

Then if I change the order
TestDerived; // first
TestSimple;  // second

and step through, the A.List in Test Derived is A.List = () from the start, it is as-if it was preinitialized?

But then. If I comment out the other_field, both routines pass through with A.List = (0x0) in TestSimple before SetLength, it also seems to pass without a problem and without the * problem below, even with A.List = () before and after SetLength.

* problem : with the other_field still IN TDerivedArrayString, if I step through the (passing with no error) TestSimple, and hover mouse over A, I get a GDB crash. Regardless which A I hover over (the one in Test Derived does that too, even if out of scope [execution point currently in the other Test procedure] Again this does NOT happen with the other_field commented out.

If I run either one Test* procedures at a time between rebuilds, with other_field defined, TestSimple passes with no error,
TestDerived shows .List hovering A.List = (0x10000 '=') ; hovering over A crashes GDB too;

Say if I only leave TestDerived call, and if I pause execution before SetLength, hovering over .List in EITHER procedure shows A.List = () (yes even in TestSimple which is commented out in main begin..end;) (and I get GDB crash when hovering over A of either procedure)

BUT.

If I truly comment out the unused procedure, only leaving the one currently being tested, like TestDerived, hovering over .List before SetLength call gives A.List = (0x10000 '=') hovering over A crashes GDB

after rebuild, program completes with NO SIGSEGV.

?

FPC 2.6.4 under Lazarus 1.4.4 from tarball release [ 2015-10-03, svn 49931 i386-win32-win32/win64 ] under WinXP SP3.

Dennis Poon
to Santiago A.: It's an object, not a class inherited from Tobject, so it hasn't create constructor.…
Santiago A. wrote 15 lines
El 23/12/2015 a las 12:13, Dennis Poon escribió: > > Did you call A.Create before calling TestDerived? Maybe A.List was not > initialized (which is done in constructor Create) and contains an > invalid pointer (to dynamic array of string). > When you call SetLength, it decrements the reference count of A.List > (which is not nil) and raisesSIGSEGV. > > Dennis > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal It's an object, not a class inherited from Tobject, so it hasn't create constructor.

Even if it is an object, you can still define a constructor. A constructor should initialize the memory area of the object to 0, even if you don't explicitly assign List := nil;
It is safer to call this constructor before you handle the List. The fact that it raises SIGEGV in TestDervived but not in TestSimple might just be a random luck in how the compiler handles the memory space involved.
You should not rely on this behavior.

Dennis

Santiago A.
to Lukasz Sokol: I might be wrong... but I just tried: stepping into TestSimple in the order OP specified,…
Lukasz Sokol wrote
On 23/12/15 09:37, Santiago Amposta wrote: I might be wrong... but I just tried: .......

What's the conclusion? As far as I see, there is some kind of bug.

There is no reason for getting different results depending on how you execute two independent and isolated procedures or if you comment in or out an unused procedure.

Saludos Santiago A.
Santiago A.
to Dennis Poon: Even if it is an object, you can still define a constructor. A constructor should…
Dennis Poon wrote 6 lines
Even if it is an object, you can still define a constructor. A constructor should initialize the memory area of the object to 0, even if you don't explicitly assign List := nil; It is safer to call this constructor before you handle the List.

Well, AFAIK, according with the documentation, the constructor of an object is only necessary if it has virtual methods. It looks that calling a constructor that does nothing is a workaround solves the problem.

But it doesn't make me feel secure.

Saludos Santi
Dennis Poon
to Santiago A.

I think for both Record or Object, you need to initialize any dynamic array or strings fields before using them.

If you don't use any constructor , you need to initialize the fields yourself.

Being an object, just gives you the added automatic zeroing of its content. Advanced Record does not have constructor so you must initialize yourself.

The documentation should state that constructor of object also clears the memory space.

Dennis

Santiago A. wrote
al method
Lukasz Sokol
to Santiago A.: What's the conclusion? As far as I see, there is some kind of bug. There is no reason for…
Santiago A. wrote 12 lines
El 23/12/2015 a las 16:24, Lukasz Sokol escribió: > On 23/12/15 09:37, Santiago Amposta wrote: > I might be wrong... but I just tried: > > ....... What's the conclusion? As far as I see, there is some kind of bug. There is no reason for getting different results depending on how you execute two independent and isolated procedures or if you comment in or out an unused procedure.

Puzzled me too,

also the GDB crashing.

See how the A.List points to memory that contains something? Does using a constructor get that straight?

(also sorry, my post underwent a few revisions, and the 'i might be wrong' portion does not belong where it's found any more ;) )

el es

Jonas Maebe
to Santiago Amposta: Hello: I use fpc 2.6.4 and I have a problem of memory leaks, strange errors, etc. Finally…
Santiago Amposta wrote 30 lines
I use fpc 2.6.4 and I have a problem of memory leaks, strange errors, etc. Finally I have tracked it to this: TSimpleArrayString=object List:array of String; end; TDerivedArrayString=object(TSimpleArrayString) other_field:integer; end; procedure TestSimple; var A:TSimpleArrayString; begin setLength(A.List,0); end; procedure TestDerived; var A:TDerivedArrayString; begin setLength(A.List,0); end; TestSimple; // Works Fine, TestDerived; // rises an exception SIGSEGV on setLength What am I doing wrong?

This is a bug in FPC 2.6.4 (it did not initialise managed fields of parent objects for child objects that do not declare extra managed fields). It is fixed in FPC 3.0.

Dennis Poon wrote
I think for both Record or Object, you need to initialize any dynamic array or strings fields before using them.

That is incorrect, the compiler takes care of it (or is supposed to, anyway).

Jonas

Santiago A.
to Jonas Maebe
Jonas Maebe wrote 7 lines
Santiago Amposta wrote: This is a bug in FPC 2.6.4 (it did not initialise managed fields of parent objects for child objects that do not declare extra managed fields). It is fixed in FPC 3.0.

I have used constructors as a workaround now I have a problem of memory leaks.

 TSimpleArrayString=object
    List:array of String;
    constructor Init;
 end;

{ TDerivedArrayString }

 TDerivedArrayString=object(TSimpleArrayString)
    other_field:integer;
    constructor Init;
 end;
constructor TDerivedArrayString.Init;
begin
  // nothing
end;
constructor TSimpleArrayString.Init;
begin
  // nothing
end;
procedure TestSimple;
var
 A:TSimpleArrayString;
begin
  a.init;
  setLength(A.List,16);
end;
procedure TestDerived;
var
 A:TDerivedArrayString;
begin
  a.init;
  SetLength(a.list,16);
  SetLength(a.list,0);  // If i comment this line, when I finish the
program, the debug says there are unfreed blocks
end;

In TDerivedArrayString I need to manually set the length of the list to zero. If I don't, the memory is not freed, but in TSimpleArrayString it frees memory.

Is it also a known bug of 2.6.4?

Saludos Santiago A.
Jonas Maebe
to Santiago A.
Santiago A. wrote 5 lines
In TDerivedArrayString I need to manually set the length of the list to zero. If I don't, the memory is not freed, but in TSimpleArrayString it frees memory. Is it also a known bug of 2.6.4?

Yes, it was fixed at the same time IIRC.

Jonas