Sign in Join

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

Mailing lists / fpc-pascal / 2022-09

Access Violation When SetLength(DynArray, Value)

14 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

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

Anthony Walter

Is there a known edge case issue connected to setting the length of dynamic arrays?

I have a program that simulates a billiards game, and during the rerack balls method of TPoolTable the number of pool balls on the table varies based on the rerack option used. Currently, I am having a problem where an exception is thrown if I try to SetLenth(Balls, 10) or greater than 10. Values less than 10 work fine, but at 10 balls and above an exception is thrown right at the SetLength call.

External: SIGSEGV

000000000041DCA4 eb12 jmp 0x41dcb8 <SYSTEM_$$_SYSGETMEM_VAR$QWORD$$POINTER+264>
000000000041DCA6 4c89f0 mov %r14,%rax 000000000041DCA9 488b5008 mov 0x8(%rax),%rdx 000000000041DCAD 488b4018 mov 0x18(%rax),%rax 000000000041DCB1 488982a8000000 mov %rax,0xa8(%rdx) ^ instruction pointer is at this line ^

I tried compiler both FPC 3.3.1 from trunk source and 3.2.2 from the official Sourceforge binary. The same error occurs when building with both compilers. My platform is x86_64 Linux.

For reference here is the type of Balls:

  TVec2 = record
     X, Y: Single;
  end;
  TPoolBall = record
    Pos: TVec2;
    Dir: TVec2;
    Speed: Double;
    Color: LongWord;
    Touched: Boolean;
    Sinking: Single;
    SinkPocket: Integer;
    SinkPos: TVec2;
    Pocketed: Boolean;
    Index: Integer;
  end;
  TPoolBalls = array of TPoolBall;

... later inside TPoolTable ...

  Balls: TPoolBalls;
Jonas Maebe
to Anthony Walter
Anthony Walter wrote
Is there a known edge case issue connected to setting the length of dynamic arrays?

No, and the location where you're getting the crash suggests an issue in your program that has corrupted the heap manager state.

Jonas

Peter B
to Anthony Walter: Is there a known edge case issue connected to setting the length of dynamic arrays? I…

I suggest trying without optimisations and/or using cmem, to see if that changes the outcome.

Also, if the array is corrupted prior to the setlength, then iterating the array with a trivial   with... Writeln(Color)
or whatever, should trigger an exception.

That could then be used at various parts of the program to identify the point of corruption, which might seem unrelated to array in question if the heap is getting messed up somehow.

Cheers,
Peter

P.S.

I had a strange (possible) heap corruption issue with a large program a year ago that broke stringlists. I never found the cause, and after many minor code changes, the problem just dissappeared.

Unknown author
to Anthony Walter
Anthony Walter wrote
Please ignore this post. I fixed the issue.

curious minds want to know: what was the fix?

NOTE: No off-list assistance is given without prior approval. *Please keep mailing list traffic on the list where it belongs!*
Anthony Walter
to Unknown author
curious minds want to know: what was the fix?

In a separate part of the pool table initialization, I was precalculating the midpoints and normals for bumper rails. I had carelessly written this code:

  for I := 0 to Length(Rails) do
    RailInit(Rails[I], I);
Luca Olivetti
to Anthony Walter

El 8/9/22 a les 16:53, Anthony Walter via fpc-pascal ha escrit:

Show quoted text 8 lines
> curious minds want to know: what was the fix? In a separate part of the pool table initialization, I was precalculating the midpoints and normals for bumper rails. I had carelessly written this code:   for I := 0 to Length(Rails) do     RailInit(Rails[I], I);

To avoid this kind of error you can use

    for i:= 0 to High(Rails) do

or even

    for i:= Low(Rails) to High(Rails) do

Bye

Luca
James Richters
to Luca Olivetti

I only recently learned about using Low() and High() and it is so much nicer than
For I:= 0 to Length(MyArray)-1 Do

That I actually went though all my code replacing the Length() - 1's with High()

I still end up with a lot of
SetLength(MyArray,Length(MyArray)+1);
Every time I want to add one more thing to the array.

Almost all of my dynamic arrays do this, because I can only add one thing at a time to the array... and the reason I wanted it to be dynamic in the first place.

Is there some nifty way to increase a dynamic array by 1 that is more elegant?
Inc(MyArray); would sure be nice

James

Show quoted text 7 lines
To avoid this kind of error you can use for i:= 0 to High(Rails) do or even for i:= Low(Rails) to High(Rails) do
Luca Olivetti
to James Richters

El 9/9/22 a les 14:58, James Richters via fpc-pascal ha escrit:

Is there some nifty way to increase a dynamic array by 1 that is more elegant? Inc(MyArray); would sure be nice

If I know that I have to regularly add a single element to an array, instead of using a dynamic array I just use a TFPGList (if the elements are simple types or records) or a TFPGObjectList (if the element are objects and I want automatic housekeeping) from the fgl unit, then I can just do MyList.Add(element).

I don't know if it is more or less efficient than using a dynamic array but I think it's nicer.

There are other generic classes that may be more efficient than fgl but I'm just used to fgl.

Bye

Luca
James Richters
to Sven Barth: James Richters via fpc-pascal schrieb am Fr., 9. Sep. 2022, 14:58: With FPC 3.2.0 and…
With FPC 3.2.0 and newer you can do "Concat(MyArray, [TheNewElement])" or (if modeswitch ArrayOperators is active) "MyArray := MyArray + [TheNewElement]".
I have a lot of arrays of records, but I just build the record into the array elements, like this:
                                          SetLength(MathArray,Length(MathArray)+1);
                                          MathArray[High(MathArray)].Variable:=NewVariable;
                                          MathArray[High(MathArray)].Formula:=NewEquation;
Could either of the methods mentioned work directly with something like this or would I have to build the record first and do:
MyRecord.Variable:=NewVariable;
MyRecord.Formula:=NewEquation;
MathArray:= MathArray+ MyRecord;

I thought I would make my own IncArray() function:

Procedure IncArray(Var TheArray);
Begin
   SetLength(TheArray,Length(TheArray)+1);
End;

But I get a 'Type Mismatch' Any ideas how this could be done? Is this even possible without specifying the exact type of array?

James

Sven Barth
to James Richters
James Richters wrote 7 lines
I thought I would make my own IncArray() function: Procedure IncArray(Var TheArray); Begin SetLength(TheArray,Length(TheArray)+1); End; But I get a 'Type Mismatch' Any ideas how this could be done? Is this even possible without specifying the exact type of array?

You can't simply use a formal parameter for that as SetLength requires information about the type which is missing in that case. What you can do is use a generic procedure:

=== code begin ===

generic procedure IncArray<T>(var aArray: specialize TArray<T>);
begin
   SetLength(aArray, Length(aArray) + 1);
end;
var
   arr: array of LongInt;
begin
   arr := [1, 2, 3];
   specialize IncArray<LongInt>(arr);
end.

=== code end ===

In 3.3.1 you can also enable the modeswitch
ImplicitFunctionSpecialization and you can then simply use the following as the compiler is able to derive the type to specialize with:

=== code begin ===

IncArray(arr);

=== code end ===

Regards,
Sven