Technisch Artikel

Range Check Errors (Range Check Fouten) in Delphi PDF-bibliotheken debuggen

Wanneer je grote arrays doorzoekt bij het parsen van bytes via pointers om PDF-streams (xref tabellen, bitmap arrays voor rendering) af te handelen, is ERangeError in Delphi een zware hindernis in C++ VCL wrappers. Delphi is in hoge mate een veilige, sterk getypeerde taal; wanneer je code vertelt om item 4 in een 3-object array te pakken, knipt C++ stilletjes geheugen, maar Delphi zal luidruchtig je applicatie stopzetten met Range Check Error-dialogen

Delphi compiler options showing the Range checking checkbox in RAD Studio options window
Delphi compileropties onthullen "Range checking" configuraties. Dit in- of uitschakelen heeft invloed op uitzonderingen van third-party code in bitmap-operaties.

Begrijpen waar ERangeError toeslaat

Wanneer het over PDF-bibliotheken (zoals Pdfium of PDFlib) gaat, komen Range Check Errors meestal bovendrijven op twee specifieke VCL-pijnpunten: Bitmap image processing scanlines die C++ byte pointers simuleren en statische array typecasting (bijv. PByteArray operaties)

Dit faalt als range checks aan staan en het document een enorm formaat op hoge DPI laadt dat verder reikt dan de 32K limiet van het gealiaste klassieke pointer type

var
  pBytes: PByteArray;
  i: Integer;
begin
  pBytes := PByteArray(PdfiumBitmap.GetBuffer);
  // Als de bitmap groter is dan 32767 bytes (vrijwel alle PDF-pagina's), zal Delphi een
  // ERangeError uitzondering gooien in de For loop omdat PByteArray intern
  // is gedefinieerd als array[0..32767] of Byte.
  for i := 0 to PdfiumBitmap.GetPitch * PdfiumBitmap.GetHeight - 1 do
  begin
    pBytes^[i] := 255; 
  end;
end;

Het PByteArray is overblijfsel code van oude Delphi System iteraties. PDF-rendering (op 300 DPI) genereert megabytes aan raster pixel arrays in het RAM in milliseconden. Wanneer je scanline iteraties en pointers in VCL bouwt, is de fix eenvoudig

Fixing via dynamische pointers en uitzetten via compilerrichtlijn (compiler directive)

De standaard Delphi-praktijk als je je ERangeError niet kunt repareren zonder de third-party open-source component wrappers direct te wijzigen, is het lokaal uitschakelen van bereikcontrole rond het problematische codeblok in de library zelf met {$R-} en deze vervolgens te herstellen met {$R+}

var
  pBytes: PByte; // Gebruik native pointer-berekeningen in plaats van array casts
  i: Integer;
  BufferLen: Integer;
begin
  pBytes := PdfiumBitmap.GetBuffer;
  BufferLen := PdfiumBitmap.GetPitch * PdfiumBitmap.GetHeight;
  
  {$R-} // Bereikcontrole in Delphi uitschakelen voor snelle brute RAM-wiskunde
  for i := 0 to BufferLen - 1 do
  begin
    pBytes^ := 255;
    Inc(pBytes); // Pointer rekenkunde in theorie, omzeilt strakke bounds.
  end;
  {$R+} // Veiligheid herstellen
end;

Door Pointer Math te gebruiken in plaats van Array Bounds, omzeil je het statische grens-oordeel (static boundary judgment) van de Delphi compiler. Wanneer je FPDF_Bitmap pointers verwerkt, dwingt de PDF-geheugentoewijzer deze methodologie van pointer-verhogingen af bij gebruik van DLL-oproepen met Delphi interop

PDF Array Bounds Fouten

Een tweede logisch falen bij ERangeError in PDF VCL code komt voor bij het interacteren met Delphi index limieten. Delphi gebruikt zowel 0-gebaseerde als 1-gebaseerde arrays asynchroon in de VCL, terwijl Pdfium (C++) strikt 0-gebaseerd is. PDF-pagina indices via FPDF_LoadPage(doc, 0) verwachten "0" als pagina 1. Wanneer je je iteraties bouwt om een factuur te splitsen (met Delphi's 1-gebaseerde arrays voor TStrings in een listbox voor batching), loop je over de grens heen, wat leidt tot Acces Violations die lijken op C++ "off-by-one" out-of-bounds in RAM of Delphi ERangeError string object mapping mislukkingen