Skip to content

Wrong pointer arithmetics in conjunction with constant folding

Very serious and important bug!

Pointer arithmetics behaves wrong when doing several additions in a row, regardless of the base type. (Subtractions are mysteriously fine.)

See this program:

{$mode objfpc} {$h+} {$typedaddress on}
type
	pBaseType = ^BaseType;
	BaseType = uint32; // can be replaced with an arbitrary-sized array or record

procedure Check(pstart, px: pBaseType; refIx: SizeInt; const desc: string);
var
	ix: SizeInt;
begin
	ix := px - pstart;
	writeln(desc, ' points at element #', ix);
	if ix = refIx then
		writeln('ok')
	else
		writeln('WRONG, must be #', refIx);
	writeln;
end;

var
	x: array[0 .. 19] of BaseType;
	p: pBaseType;

begin
	p := pBaseType(x);
	Check(p, p + 2,         2,  'p + 2');
	Check(p, p + 2 + 3,     5,  'p + 2 + 3');
	Check(p, p + 2 + 3 + 5, 10, 'p + 2 + 3 + 5');

	// These casts don't help.
	Check(p, pBaseType(pBaseType(p + 2) + 3) + 5, 10, 'pBaseType(pBaseType(p + 2) + 3) + 5');

	// These work, but prevent constant folding.
	Check(p, pBaseType(pointer(pBaseType(pointer(p + 2)) + 3)) + 5, 10, 'pBaseType(pointer(pBaseType(pointer(p + 2)) + 3)) + 5');

	Check(p, p + (2 + 3 + 5),   10, 'p + (2 + 3 + 5)');
	Check(p, p + 2 + 3 + 5 + 7, 17, 'p + 2 + 3 + 5 + 7');
end.

and its output:

p + 2 points at element #2
ok

p + 2 + 3 points at element #20
WRONG, must be #5

p + 2 + 3 + 5 points at element #100
WRONG, must be #10

pUint32(pUint32(p + 2) + 3) + 5 points at element #100
WRONG, must be #10

pUint32(pointer(pUint32(pointer(p + 2)) + 3)) + 5 points at element #10
ok

p + (2 + 3 + 5) points at element #10
ok

p + 2 + 3 + 5 + 7 points at element #428
WRONG, must be #17
Edited by Rika
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information