#1 2022-10-09 16:16:58

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 392

PopHead in TDynArray will try finalize an 'object' if is not null

I was getting random exceptions from an ilist with objects
The exception is coming from mormot.core.data line 6988 (fInfo.ArrayRtti.ValueFinalize)

procedure TDynArray.ItemMoveTo(index: PtrInt; Dest: pointer);
var
  p: pointer;
begin
  p := ItemPtr(index);
  if (p = nil) or
     (Dest = nil) then
    exit;
  if (fInfo.ArrayRtti <> nil) and
     not fNoFinalize then
    fInfo.ArrayRtti.ValueFinalize(Dest); // also handle T*ObjArray
  MoveFast(p^, Dest^, fInfo.Cache.ItemSize);
  FillCharFast(p^, fInfo.Cache.ItemSize, 0);
end;

which is called by same unit, line 6858

function TDynArray.PopHead(var Dest): boolean;
begin
  result := GetCount <> 0;
  if result then
  begin
    ItemMoveTo(0, @Dest);
    Delete(0);
  end;
end;

The problem was that the object variable passed to pophead was not null and before poping the new object  ItemMoveTo try to finalize it.
probably adding a Dest:=nil; somewhere before ItemMove in PopHead?
Or, probably adding this requirement (dest must be nil) in Pop's documentation?

Last edited by dcoun (2022-10-09 16:28:54)

Offline

#2 2022-10-09 18:46:42

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,207
Website

Re: PopHead in TDynArray will try finalize an 'object' if is not null

It seems to be a feature to me.
Forcing FillCharFast(Dest^, fInfo.Cache.ItemSize, 0) would leak memory in most use cases.

How to you use PopHead() ?
The Dest variable should indeed be valid (filled with zeros, or containing a valid instance).

Offline

#3 2022-10-09 19:13:11

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 392

Re: PopHead in TDynArray will try finalize an 'object' if is not null

The definition is:

lowr:ilist<TepGenericSlave>;

The creation is:

lowr:=Collections.NewList<TepGenericSlave>;

The pop is used like the following and produces exceptions:

TepGenericSlave=class
....

obj:=TepGenericSlave.create;
...
repeat
...
lowr.Pop(obj,[popFromHead]);
...
until ....;

The pop is used like the following and does not produce exceptions:

TepGenericSlave=class
....

obj:=TepGenericSlave.create;
...
repeat
...
obj:=nil;
lowr.Pop(obj,[popFromHead]);
...
until ....;

Last edited by dcoun (2022-10-09 21:29:18)

Offline

#4 2022-10-10 08:41:22

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,207
Website

Re: PopHead in TDynArray will try finalize an 'object' if is not null

Pop() will extract the instance from the internal array storage.
It won't fill the destination properties, but copy the instance, after having released the existing instance.

I have added a test which shows how memory is managed, and that there is no leak:
https://github.com/synopse/mORMot2/commit/eadf3f20

If you got a GPF it is very likely than your "obj" instance life time was not correct.

Offline

#5 2022-10-10 09:36:44

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 392

Re: PopHead in TDynArray will try finalize an 'object' if is not null

Last commit is perfect. Thank you a lot @ab

Offline

Board footer

Powered by FluxBB