Skip to content

Instantly share code, notes, and snippets.

@omonien
Created May 4, 2024 13:40
Show Gist options
  • Save omonien/9c7eae02c545dea2b805352c640a1da3 to your computer and use it in GitHub Desktop.
Save omonien/9c7eae02c545dea2b805352c640a1da3 to your computer and use it in GitHub Desktop.
Demo of Delphi for loop that runs into an overflow, because of using non-matching types
program ForLoopOverflow;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
begin
// Using unsigned ints or "short" types may lead to unexpected behaviour.
// This behaviour, such as "endless loops" is hidden, unless OVERFLOW checks are turned on
// In the scenario below only OVERFLOWCHECKS is relevant
// Both, RANGECHECKS and OVERFLOWCHECKS are turned on for DEBUG configurations from Delphi 11
// General recommendation is to turn these two ON for DEBUG for legacy projects.
// You might end up with some surprising exceptions - which are NOT a Delphi bug, but are due to errors in your code
// that you hid away, and which may have caused some subtile bugs in your apps.
var j: cardinal;
//Using Integer or any other signed "large enough" int type would be safer w/o any checks.
//track what's happening
var LoopExecuted: boolean;
var LoopException: boolean;
{$RANGECHECKS ON} {$OVERFLOWCHECKS ON}
Writeln('Loop1 ...');
LoopExecuted := false;
LoopException := false;
// Loop1 from 0 to -1 - should not execute by logic
j := 0;
try
for var i := 0 to j - 1 do
begin
LoopExecuted := true; // This should not execute
end;
except
on E: EIntOverflow do // This should raise
LoopException := true;
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
try
Assert(LoopExecuted = false);
Assert(LoopException = true);
Writeln('Loop1 done. Not executed. Overflow Exception raised.');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
{$RANGECHECKS OFF} {$OVERFLOWCHECKS OFF}
Writeln('Loop2 ...');
LoopExecuted := false;
LoopException := false;
// Loop2: From 0 to -1 - should not execute by logic
j := 0;
try
for var i := 0 to j - 1 do
begin
LoopExecuted := true; // This WILL(!) execute
break; // break to avoid endless loop
end;
except
on E: EIntOverflow do // This should raise
LoopException := true;
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
try
Assert(LoopExecuted = true); //The loop WILL execute!
Assert(LoopException = false); //NO exception will be raised!
Writeln('Loop2 done. Loop executed. No exception raised.');
except
on E: Exception do
Writeln('Loop2: ' + E.ClassName, ': ', E.Message);
end;
readln;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment