Recent

Author Topic: Memory error for SetLength  (Read 1042 times)

Okoba

  • Hero Member
  • *****
  • Posts: 612
Memory error for SetLength
« on: December 14, 2023, 05:47:11 pm »
Is there a way so I can prevent SetLength from raising exceptions if there is no memory left?
I can do similar for GetMem with ReturnNilIfGrowHeapFails = True.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5858
  • Compiler Developer
Re: Memory error for SetLength
« Reply #1 on: December 14, 2023, 09:14:16 pm »
No, there is not, because GetMem provides a return value that you can check, SetLength does not. If you want to protect it, then use tryexcept blocks.

ASerge

  • Hero Member
  • *****
  • Posts: 2379
Re: Memory error for SetLength
« Reply #2 on: December 14, 2023, 09:20:43 pm »
Example:
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2. {$MODE OBJFPC}
  3. {$LONGSTRINGS ON}
  4.  
  5. function SetLengthSafe(var S: string; ALength: PtrUInt): Boolean;
  6. var
  7.   P: Pointer;
  8. begin
  9.   ReturnNilIfGrowHeapFails := True;
  10.   try
  11.     P := GetMem(ALength * SizeOf(Char) + 24);
  12.     Result := Assigned(P);
  13.     if Result then
  14.       FreeMem(P);
  15.   finally
  16.     ReturnNilIfGrowHeapFails := False;
  17.   end;
  18.   if Result then
  19.     SetLength(S, ALength);
  20. end;
  21.  
  22. var
  23.   S: string;
  24. begin
  25.   if not SetLengthSafe(S, 1000 * MaxInt) then
  26.     Writeln('Not enough memory for ', 1000 * MaxInt);
  27.   if not SetLengthSafe(S, 1000) then
  28.     Writeln('Not enough memory for ', 1000);
  29.   S := 'OK';
  30.   Writeln(S);
  31.   Readln;
  32. end.

Okoba

  • Hero Member
  • *****
  • Posts: 612
Re: Memory error for SetLength
« Reply #3 on: December 14, 2023, 09:27:06 pm »
@PascalDragon try except does work if I do not set ReturnNilIfGrowHeapFails to True, but I need to set it to True as I want to control the memory allocation. If I set ReturnNilIfGrowHeapFails to True, even with try except, it throws error on finalizing the array on end of function. Is this a correct behavior or a bug?

@ASerge, that is an interesting way, but is it not slow to allocation twice?

PascalDragon

  • Hero Member
  • *****
  • Posts: 5858
  • Compiler Developer
Re: Memory error for SetLength
« Reply #4 on: December 14, 2023, 10:14:31 pm »
@PascalDragon try except does work if I do not set ReturnNilIfGrowHeapFails to True, but I need to set it to True as I want to control the memory allocation. If I set ReturnNilIfGrowHeapFails to True, even with try except, it throws error on finalizing the array on end of function. Is this a correct behavior or a bug?

Please provide a full example.

Okoba

  • Hero Member
  • *****
  • Posts: 612
Re: Memory error for SetLength
« Reply #5 on: December 14, 2023, 10:19:14 pm »
Sure.
Here:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   Classes,
  5.   SysUtils;
  6.  
  7.   procedure Test;
  8.   var
  9.     A: array of Byte;
  10.   begin
  11.     ReturnNilIfGrowHeapFails := True; //With this line, after 'Error', it continues raising an Access violation exception
  12.     try
  13.       SetLength(A, 100 * 1000 * 1000 * 1000);
  14.     except
  15.       WriteLn('Error');
  16.     end;
  17.   end;
  18.  
  19. begin
  20.   Test;
  21. end.                        

ASerge

  • Hero Member
  • *****
  • Posts: 2379
Re: Memory error for SetLength
« Reply #6 on: December 14, 2023, 10:53:46 pm »
If you want to protect it, then use tryexcept blocks.
I don't think it will help. An error inside SetLength that does not check the return value, but immediately refers to the offset from nil. This causes an exception or a series of exceptions, and, of course, the allocated memory (all until exhausted) is no longer freed.

 

TinyPortal © 2005-2018