[Bug] FPC TParallel.For Access Violation

Summary

System.Threading TParallel.For raises an EAccessViolation in FPC when compiled with optimization levels higher than -O1.

A local copy of System.Threading.pas compiled with -O1 works. The RTL version (built with higher optimization) crashes.

Steps to reproduce

  1. Compile and run the demo program below.

  2. With the RTL version of System.Threading (built by FPCUPDeluxe), the program throws an EAccessViolation.

  3. Copy System.Threading.pas into the project folder, reference this in our demo

  4. compile with -O1 optimization level: → Works correctly.

  5. compile with -O2 or above optimization level: → Access Violation returns.

System Information

  • OS: Windows 10 (64-bit)
  • CPU: x86-64
  • Compiler: FPC Trunk (Free Pascal Compiler version 3.3.1-18896-g2aeddc8041-dirty [2025/11/30] for x86_64)
  • Device: Desktop PC

Example Program

program TestParallelForBug;

{$MODE DELPHI}

uses
  SysUtils, System.Threading;

const
  NUM_ITEMS = 16;

procedure RunTest(AParallelism: Integer);
var
  Data, SerialData: TArray<Integer>;
  I: Integer;
begin
  Writeln('--- Parallelism = ', AParallelism, ' ---');

  SetLength(Data, NUM_ITEMS);
  SetLength(SerialData, NUM_ITEMS);

  for I := 0 to NUM_ITEMS - 1 do
    SerialData[I] := I * 2;

  TParallel.&For(
    0, AParallelism - 1,
    procedure(Lane: Integer)
    var
      J, StartIdx, EndIdx, ChunkSize: Integer;
    begin
      ChunkSize := NUM_ITEMS div AParallelism;
      StartIdx := Lane * ChunkSize;

      if Lane = AParallelism - 1 then
        EndIdx := NUM_ITEMS - 1
      else
        EndIdx := StartIdx + ChunkSize - 1;

      for J := StartIdx to EndIdx do
        Data[J] := J * 2;
    end
  );
end;

begin
  RunTest(1);
  RunTest(4);
end.

Current behavior

When compiled normally (RTL optimized at >O1):

--- Parallelism = 1 ---
EAccessViolation: Access violation
Done. Press ENTER to exit.

Expected behavior

Program should run without exceptions.

Notes

  • The issue occurs at optimization level -O2 or higher.
  • Compiling with -O1 avoids the problem.
  • This points to an optimization-related compiler bug.