diff --git a/Test/ArrayPass/array_bounds_int64_dynamic.pas b/Test/ArrayPass/array_bounds_int64_dynamic.pas new file mode 100644 index 00000000..87660b03 --- /dev/null +++ b/Test/ArrayPass/array_bounds_int64_dynamic.pas @@ -0,0 +1,36 @@ +// Red test for a bounds-check bypass on dynamic arrays accessed through +// a non-variable base expression. +// +// TDynamicArrayExpr.EvalAsInteger / EvalAsString / ... (Source/dwsArrayExprs.pas +// around lines 1367..1459) declares the index as a 32-bit `Integer`, +// even though IndexExpr.EvalAsInteger returns an Int64. Any index whose +// low 32 bits land inside the array's length silently bypasses +// BoundsCheckPassed and indexes the wrong element. The function-call base +// here forces the non-`Var` code path so the bug manifests on every platform +// (the variable-base path adds a separate Cardinal-truncation issue that we +// keep out of this test to avoid platform-dependent access violations). +// +// Expected (safe) behaviour: an out-of-bounds exception is raised. +function MakeArr : array of Integer; +begin + Result := new Integer[5]; + for var i := 0 to 4 do + Result[i] := 100 + 10*i; +end; + +var base : Integer := 0; +base := base + 4294967296; // 2^32; low 32 bits are 0 + +try + PrintLn(MakeArr()[base]); // truncates to MakeArr()[0] today + PrintLn('FAIL no exception (MakeArr()[2^32])'); +except + on E: Exception do PrintLn('OK out-of-bounds raised for 2^32'); +end; + +try + PrintLn(MakeArr()[base + 4]); // truncates to MakeArr()[4] today + PrintLn('FAIL no exception (MakeArr()[2^32 + 4])'); +except + on E: Exception do PrintLn('OK out-of-bounds raised for 2^32 + 4'); +end; diff --git a/Test/ArrayPass/array_bounds_int64_dynamic.txt b/Test/ArrayPass/array_bounds_int64_dynamic.txt new file mode 100644 index 00000000..b6e616dd --- /dev/null +++ b/Test/ArrayPass/array_bounds_int64_dynamic.txt @@ -0,0 +1,2 @@ +OK out-of-bounds raised for 2^32 +OK out-of-bounds raised for 2^32 + 4 diff --git a/Test/ArrayPass/array_bounds_int64_static.pas b/Test/ArrayPass/array_bounds_int64_static.pas new file mode 100644 index 00000000..bbe46252 --- /dev/null +++ b/Test/ArrayPass/array_bounds_int64_static.pas @@ -0,0 +1,45 @@ +// Red test for a bounds-check bypass on static arrays. +// +// TStaticArrayExpr.GetIndex (Source/dwsArrayExprs.pas:1250) evaluates the +// index as Int64 but stores `EvalAsInteger(exec) - FLowBound` into a 32-bit +// `Result : Integer` before performing a Cardinal-based range check. Any +// index whose low 32 bits land inside the declared range silently bypasses +// the check and reads (or writes) the wrong element instead of raising +// `Upper bound exceeded`. +// +// Expected (safe) behaviour: an out-of-bounds exception is raised for every +// index >= Length even when bits above 2^31 are set. +var a : array[0..4] of Integer; +var i : Integer; +for i := 0 to 4 do + a[i] := 100 + i; + +// Build the indices at runtime so the compiler cannot constant-fold them +// into a static range error. +var base : Integer := 0; +base := base + 4294967296; // 2^32; low 32 bits are 0 + +try + PrintLn(a[base]); // truncates to a[0] today + PrintLn('FAIL no exception (a[2^32])'); +except + on E: Exception do PrintLn('OK out-of-bounds raised for 2^32'); +end; + +try + PrintLn(a[base + 3]); // truncates to a[3] today + PrintLn('FAIL no exception (a[2^32 + 3])'); +except + on E: Exception do PrintLn('OK out-of-bounds raised for 2^32 + 3'); +end; + +try + a[base + 2] := 999; // truncates write to a[2] today + PrintLn('FAIL no exception on write (a[2^32 + 2])'); +except + on E: Exception do PrintLn('OK out-of-bounds raised on write'); +end; + +// Witness corruption: if the bounds check was bypassed the previous write +// will have clobbered a[2]. +PrintLn(a[2]); diff --git a/Test/ArrayPass/array_bounds_int64_static.txt b/Test/ArrayPass/array_bounds_int64_static.txt new file mode 100644 index 00000000..eb1b901e --- /dev/null +++ b/Test/ArrayPass/array_bounds_int64_static.txt @@ -0,0 +1,4 @@ +OK out-of-bounds raised for 2^32 +OK out-of-bounds raised for 2^32 + 3 +OK out-of-bounds raised on write +102