4

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.

But why didn't Delphi catch it?

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:

enter image description here

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):

enter image description here

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:

enter image description here

I want Delphi to help me

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:

enter image description here

Same with 32-bit release and 64-bit release.

1/25/2015 - Does it even show such a warning?

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

enter image description here

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

More than 32 local variables causes failure?

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

10
  • It seems they've done changes which add many brand new hints and warnings that never existed before, but things like this...... make me lose faith. Our legacy software with millions of lines of code, when upgrading from XE2 to XE7 has literally over 5,000 brand new hints and warnings that were never there before. Commented Jan 23, 2015 at 16:57
  • @Jerry That sounds odd. I don't recall new hints/warnings in XE2 to XE7. Commented Jan 23, 2015 at 17:20
  • @David Not that new hints/warnings were added to Delphi, but due to certain changes, it caused them to arise. Most commonly H2443 as pictured above. Commented Jan 23, 2015 at 17:23
  • @Jerry Why would that make you lose faith. They moved some functions around. You should deal with the hints. Commented Jan 23, 2015 at 17:27
  • @David it's things like this question which make me lose faith. Embarcadero seems to not care how difficult they make things for us. My point was in the midst of adding thousands of new hints and warnings to our project, Ian's problem points out that others were lost. Commented Jan 23, 2015 at 17:30

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Coincidentally, Embarcadero is shutting down QualityCentral. I assume they want to get rid of the pesky backlog of bugs.
I don't think so. I think they want to use a better bug tracking system. I've submitted many fine bugs in the new system.
That's what i thought at first. But after searching QualityPortal, i see they didn't transfer any of the existing bugs.
That's probably hard to do. They don't need to transfer the bugs to the new system.
It will suck when 16 years of outstanding bugs, and their workarounds, vanish when QC is retired (e.g. the article in Ken's answer)
|
4

I know of at least 1 case where this warning can be lost.

QC#62702 Compiler should give warning for uninitialized object variables (archive.is)

In short, it seems that if a variables is passed as a var or out parameter to a 2nd function, it disable the warning for the whole current function.

procedure A
var obj : Tobject;
begin
  obj.Free; <--Warning here
end;

procedure B
var obj : Tobject;
begin
  obj.Free; <--No warning here, even if it's only passed as var/out after this line.
  FreeAndNil(obj);
end;

1 Comment

Ouch!! That's an absolute stinker!
0

Another factor: There has been a will-not-fix "bug" in Delphi's variable tracking. It breaks badly if you have more than 32 local variables. Since that's not reasonable code they haven't done anything about it.

Could you have hit this?

2 Comments

More than 32 local variables in the method? Because, no, there's only four. More than 32 local variables in the entire project? Absolutely. But even with more than 32 local variables in the method, i still get the warning.
@IanBoyd Ok. I didn't know if it was the whole code or only the relevant bits.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.