I have a bug in my code. There's no doubt about it; it's my bug and entirely my fault:
procedure TfrmCageSetup.actDeleteFloatExecute(Sender: TObject);
var
conn: TADOConnection;
begin
...
if not float.CanDelete(conn, {out}noDeleteReason) then
begin
...
end;
I forgot to initialize the variable conn
. As a result, it is stack junk. And when the target callee checks the argument, it passes:
function TFloat.CanDelete(Connection: TADOConnection; out NoDeleteReason: string): Boolean;
begin
if Connection = nil then
raise EArgumentNullException.Create('Connection');
And i had a very strange access violation sometimes.
Yes it's my fault. But part of the reason i use a statically, strongly, typed language, is so that is can help me catch these stupid mistakes.
First i checked that i wasn't actually initializing it to some damage or destroyed object (perhaps it was initialized - just badly). But no, it really is uninitialized between declaration and first use:
Then i thought that perhaps i had turned off the warning:
Variable might not have been initialized
But no, it is enabled (globally, and for my platform, as for my release type):
So then i built it again (even though this bug has been in the code for months), to make sure i didn't miss the error. But no; aside from some bugs in the VCL and JVCL, Delphi isn't catching the error:
What can account for this?
I want to know if there's any other places in my code that have this same, awful, horrible, completely detectable, bug.
Perhaps it's the 64-bit compiler. There are grumblings that the 64-bit back-end (being all new) isn't as intelligent as the 32-bit backend. What if i try changing it to 32-bit?
Still no:
Same with 32-bit release and 64-bit release.
Steps to reproduce the warning does show:
procedure TForm1.FormCreate(Sender: TObject);
var
silverWarrior: Integer;
begin
IsWrong(silverWarrior);
end;
function TForm1.IsWrong(n: Integer): Boolean;
begin
Result := True;
end;
Gives warning:
W1036 Variable 'silverWarrior' might not have been initialized
You don't even have to be passing the value to another function; simply using an uninitialized variable gives the warning (depending on the mood of the compiler that particular day):
procedure TForm1.FormCreate(Sender: TObject);
var
silverWarrior: Integer;
theAnswer: Integer;
begin
theAnswer := silverWarrior + 42;
end;
gives a warning:
W1036 Variable 'silverWarrior' might not have been initialized
No; you still get the warning:
procedure TForm1.FormCreate(Sender: TObject);
var
localVariable1: Integer;
localVariable2: Integer;
localVariable3: Integer;
localVariable4: Integer;
localVariable5: Integer;
localVariable6: Integer;
localVariable7: Integer;
localVariable8: Integer;
localVariable9: Integer;
localVariable10: Integer;
localVariable11: Integer;
localVariable12: Integer;
localVariable13: Integer;
localVariable14: Integer;
localVariable15: Integer;
localVariable16: Integer;
localVariable17: Integer;
localVariable18: Integer;
localVariable19: Integer;
localVariable20: Integer;
localVariable21: Integer;
localVariable22: Integer;
localVariable23: Integer;
localVariable24: Integer;
localVariable25: Integer;
localVariable26: Integer;
localVariable27: Integer;
localVariable28: Integer;
localVariable29: Integer;
localVariable30: Integer;
localVariable31: Integer;
localVariable32: Integer;
localVariable33: Integer;
localVariable34: Integer;
localVariable35: Integer;
localVariable36: Integer;
localVariable37: Integer;
localVariable38: Integer;
localVariable39: Integer;
localVariable40: Integer;
localVariable41: Integer;
localVariable42: Integer;
localVariable43: Integer;
localVariable44: Integer;
localVariable45: Integer;
localVariable46: Integer;
localVariable47: Integer;
localVariable48: Integer;
localVariable49: Integer;
silverWarrior: Integer;
theAnswer: Integer;
begin
theAnswer := silverWarrior + 42;
end;
W1036 Variable 'silverWarrior' might not have been initialized
That's just how it is. The compiler isn't perfect at spotting such errors. As well as your problem (uninitialized variable that the compiler fails to warn about), it is quite possible to encounter an initialized variable that the compiler does warn about. And to compound the misery, it is possible to have code which the 32 bit compiler emits a warning, but the 64 bit compiler does not. And vice versa, sometimes the 64 bit compiler warns, and the 32 bit compiler does not.
I've not found any pattern to this. I have no solution. I have an inkling that control statements like break
and exit
could be associated with these problems, but I've got no hard proof that is so.
Only Embarcadero can solve this so the best that you can do is submit a bug report and hope that somebody at Embarcadero cares.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With