Jump to content
aehimself

Using uninitialized object works on Win32, throws AV on Win64

Recommended Posts

15 minutes ago, dummzeuch said:

And other calls to that procedure might actually require an input value:

 

How should the compiler determine whether passing an uninitialized variable to procedure bla is a problem, without analyzing the procedure itself?

OK, when we change it to this, so there is an unitialized variable:

procedure bla(var _Value1: integer; _Value2: integer);
begin
  if _Value2 > 0 then
    _Value1 := _Value2+1;
end;

procedure blub;
var
  Value1: integer;
begin
  bla(Value1, 3);
  writeln(Value1);
end;

What will be the value of Value1? I would prefer to get a warning in this case.

Share this post


Link to post
2 hours ago, Uwe Raabe said:

If a variable is given to a method as var or out parameter that should be sufficient to rate that variable as initialized inside that method. If that would always issue a warning, you will have to make a redundant initialization just to make the warning vanish. I strongly reject this request.

In C# you can't pass an uninitialized variable to a ref param, but you can to an out param. 

Share this post


Link to post
59 minutes ago, Vandrovnik said:

OK, when we change it to this, so there is an unitialized variable:


procedure bla(var _Value1: integer; _Value2: integer);
begin
  if _Value2 > 0 then
    _Value1 := _Value2+1;
end;

procedure blub;
var
  Value1: integer;
begin
  bla(Value1, 3);
  writeln(Value1);
end;

What will be the value of Value1? I would prefer to get a warning in this case.

Easy: Value1 will be 4, since Value2 > 0 and therefore Value1 will be assigned Value2+1 = 3+1 = 4.

So I guess your example has a bug. 😉

  • Like 1

Share this post


Link to post
39 minutes ago, David Heffernan said:

In C# you can't pass an uninitialized variable to a ref param, but you can to an out param. 

Yes, but that has always been the case, so there won't be any legacy code that passed an uninitialised variable to a ref parameter, and all of a sudden became invalid code. Delphi introduced the out parameter declaration "recently" (Delphi 5?), so there is legacy code that uses var rather than out.

 

OK I change my vote to: This should emit a hint or a warning, because nowadays it's bad design and should be fixed ASAP.

  • Like 1

Share this post


Link to post
4 minutes ago, dummzeuch said:

Yes, but that has always been the case, so there won't be any legacy code that passed an uninitialised variable to a ref parameter, and all of a sudden became invalid code. Delphi introduced the out parameter declaration "recently" (Delphi 5?), so there is legacy code that uses var rather than out.

I understand all of that, hence my first post. I explained why Delphi behaves the way it does, because var is both in/out and out. 

Share this post


Link to post
37 minutes ago, dummzeuch said:

Easy: Value1 will be 4, since Value2 > 0 and therefore Value1 will be assigned Value2+1 = 3+1 = 4.

So I guess your example has a bug. 😉

Ups, yes, it has a bug 🙂  I was reading it as

_Value1 := _Value1+1;

Share this post


Link to post
2 hours ago, David Heffernan said:

In C# you can't pass an uninitialized variable to a ref param, but you can to an out param. 

Why is it relevant how c# works? It's completely different.

won't compile:

bool a(out int i)
{
    if (1 != 2)
        return false;
    i = 43;
    return true;
}

 

Share this post


Link to post
11 minutes ago, Attila Kovacs said:

It's completely different.

Because it has been designed correctly with ref, out and by value arguments handling the three different parameter semantics. C# is an example of how delphi should be, and the entire issue with this missing warning is because delphi is so badly designed in this area. 

  • Like 4

Share this post


Link to post
1 minute ago, David Heffernan said:

Because it has been designed correctly with ref, out and by value arguments handling the three different parameter semantics. C# is an example of how delphi should be, and the entire issue with this missing warning is because delphi is so badly designed in this area. 

but c# does not only giving hints, it is enforcing a lot of things. or is it possible to turn them off?

Share this post


Link to post
4 minutes ago, Attila Kovacs said:

but c# does not only giving hints, it is enforcing a lot of things. or is it possible to turn them off?

A variable has to be initialized before being passed to a ref param

Share this post


Link to post
1 minute ago, David Heffernan said:

A variable has to be initialized before being passed to a ref param

A variable has to be initialized before being passed to a ref param, yes

you have to decorate with "ref" or "out" -or whatever- the parameters at call:  myproc(ref param1, out param2); <- this is the call, not the definition!

you _have_ to set an "out" parameter before using it or before returning from the routine, even if you won't use that value (see my example)

who knows what else...

 

And I'm afraid this is because you can't just show hints for coding guidance as they will first disappear when you do what the compiler wants you to do.

So it would be basically an error, like in c#.

Am I right? Do we need that?

 

Share this post


Link to post

There are probably plenty of methods, built-in or from 3d party libraries, that offer only var parameters where out would be the better choice, but we are not able to change the signature.

Share this post


Link to post
44 minutes ago, Uwe Raabe said:

There are probably plenty of methods, built-in or from 3d party libraries, that offer only var parameters where out would be the better choice, but we are not able to change the signature.

The thing is, for value types, there is actually no practical difference between var and out in Delphi which is the problem. In practice out and var behave identically. So what's the point of out? 

 

I appreciate that legacy makes it hard to change. It was just a screw up by the designers that leads to oddities like the absent warning in this question. 

Share this post


Link to post
58 minutes ago, David Heffernan said:

So what's the point of out? 

One could argue that an out parameter counts as initialized while a var does not. Due to the history of var/out that doesn't work in a consistent manner. As @Dalija Prasnikar said, out has its merits, too.

Share this post


Link to post
11 minutes ago, Uwe Raabe said:

One could argue that an out parameter counts as initialized while a var does not. Due to the history of var/out that doesn't work in a consistent manner. As @Dalija Prasnikar said, out has its merits, too.

Without the compiler enforcing it, it's next to pointless

  • Like 1

Share this post


Link to post
On 1/29/2022 at 10:20 PM, aehimself said:

What can be the explanation?

I guess the reason is the way you call the function. Likely the code before function call zeroed the corresponding stack area on x32 but didn't on x64

Share this post


Link to post
13 hours ago, Dalija Prasnikar said:

But, Delphi out parameters have some unpleasantries and many developers choose to use var instead. 

 

https://delphisorcery.blogspot.com/2021/04/out-parameters-are-just-bad-var.html

Good article. The main point against using the out parameter in Delphi is sub-optimal generated code, due to the need to maintain compatibility with C++ Builder.

 

But how often is Delphi code used in C++? Maybe a better solution would be to add additional checks and parameter initializations to the calling C++ code?

Edited by Kryvich

Share this post


Link to post
18 hours ago, Attila Kovacs said:

It's not the compilers job to do code analysis for you?

Checking the initialization of var parameters before use is a basic thing that does not require deep analysis. In fact, it has already implemented for parameters passed by value.

procedure Test;

 procedure DoStuff({var} a: Integer);
 begin
  if a = 0 then
    a := 1;
 end;

var
 a: Integer;
begin
  DoStuff(a); // W1036 Variable 'a' might not have been initialized
  Writeln(a);
end;

 

Edited by Kryvich

Share this post


Link to post
40 minutes ago, Kryvich said:

In fact, it has already implemented for parameters passed by value.

Indeed. And it is simply the fact that var serves as both in/out and out that explains why there is no such warning for var parameters.

 

Since we have out then a very simple thing for the designers to do would be to enable this very warning for var parameters too. If you encountered it on a var that was masquerading as a pure out parameter, you could simply change the parameter definition to be out.

  • Like 2

Share this post


Link to post
1 minute ago, David Heffernan said:

If you encountered it on a var that was masquerading as a pure out parameter, you could simply change the parameter definition to be out.

that won't help much as out parameter also taking inputs without any warnings, which is more screwed as the original problem

Share this post


Link to post
24 minutes ago, David Heffernan said:

If you encountered it on a var that was masquerading as a pure out parameter, you could simply change the parameter definition to be out.

As I said, this may not always be possible:

12 hours ago, Uwe Raabe said:

There are probably plenty of methods, built-in or from 3d party libraries, that offer only var parameters where out would be the better choice, but we are not able to change the signature.

 

  • Like 1

Share this post


Link to post
26 minutes ago, Attila Kovacs said:

that won't help much as out parameter also taking inputs without any warnings, which is more screwed as the original problem

The compiler should generate absolutely the same code for var and out parameters, both for the calling and for the called subroutines. The only difference will be in the warnings it issues:

Warning                                            var parameter    out parameter   Where to show
1. W1036 Variable might not have been initialized  yes              no              Calling routine
2. The parameter must be initialized before use    no               yes             Called routine
3. Return value of parameter might be undefined    no               yes             Called routine

Warnings 2. and 3. should work in the same way as for the Return value of a function (W1035 Return value of function might be undefined). That is, all the necessary checks (W1035, W1036) are already in the compiler, Embarcadero only has to apply them to the parameters where necessary.

Edited by Kryvich

Share this post


Link to post

as I mentioned before, to avoid the hints you have to act so you could make it an error instead of a hint

or are you the guy who having 2 kilometer of hints after a build?

Share this post


Link to post
1 hour ago, Kryvich said:

Good article. The main point against using the out parameter in Delphi is sub-optimal generated code, due to the need to maintain compatibility with C++ Builder.

 

But how often is Delphi code used in C++? Maybe a better solution would be to add additional checks and parameter initializations to the calling C++ code?

Easier said than done.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×