[fpc-devel] Wrong docs: not initialized global variables

Karoly Balogh (Charlie/SGR) charlie at scenergy.dfmk.hu
Thu Apr 5 16:22:01 CEST 2018


Hi,

Just some technical background to this discussion, I don't care who
documented what, I'm just stating how it works. :P

On Thu, 5 Apr 2018, Ondrej Pokorny wrote:

> >>> Now, it is also correct that the compiler developers are aware that
> >>> many people rely on this implementation detail.
> >>
> >> Since when is documented behavior considered as "implementation
> >> detail"? This is not an implementation detail. It is in official
> >> documentation.
> >
> > You and I know very well that this is an implementation detail, needed
> > for internal bookkeeping of the compiler. That the delphi manual states
> > otherwise, I have always considered a grave error on their part:
> > It contradicts one of the core tenets of pascal - see below.

The Delphi manual probably states the de-facto behavior. You cannot not
initialize global variables to zero on most modern Un*ces and Windows,
because the OS will zero out the bss section on executable loading, which
is where most global variables live. (Unless they're in the data section,
in which case they have a specified initial value, but that's more like
typed consts with an initial value in Pascal's context.)

But again, it's zeroed out, not really "initialized". So for example if
you have a type with say, 5..7 value range, it will still contain zero
after start. Hence, uninitialized, therefore the warning is correct. (See
below for examples.)

> Huh, no, I don't know this is an implementation detail. For me the
> initialization rules always were:
>
> 1.) Global variables are initialized. (Why is simple global variables
> initialization needed for internal bookkeeping of the compiler?)

As I wrote above, we cannot not "initialize" (as in: zero out) the global
variables on modern systems, because the compiler doesn't do it, but the
executable loader of the OS. (Well, it's actually a bit more complicated,
if threadvars are involved, but that's platform specific what happens
there, and the end result is the same - global variables are zeroed out.)

> 2.) Class fields are initialized. (Why is simple class fields
> initialization needed for internal bookkeeping of the compiler?)

I think this is something which happens when constructing the class, so
this is runtime behavior, and not compile or exe loading time, and again,
it's just clearing the allocation after GetMem()'ing the heap area for
the class, so you don't get trash in the fields. But they're don't
necessarily initialized to valid values (if zero is not valid).

> 3.) Everything else is not initialized.

> Yes, I have always relied on both 1.+2. For me both points 1.+2. are
> well documented and wanted behavior. Isn't it so?

Do you want initialized, or zeroed out? Zero out will happen,
initialization will not:

Take these two examples:

type
  qq = (foo, bar, klepp, mopp, fubb);
  q = klepp..fubb;

var
  c: q;

begin
  writeln(ord(c)); // will write 0;
  writeln(c); // will fail with runtime error (out of range)
end.


And:

{$MODE OBJFPC}

type
  qq = (foo, bar, klepp, mopp, fubb);
  q = klepp..fubb;

type
  clfoo = class
    c: q;
  end;

var
  x: clfoo;

begin
  x:=clfoo.create;
  writeln(ord(x.c)); // write 0;
  writeln(x.c); // runtime error (out of range)
end.

Tested with FPC 3.0.4 32bit on macOS.

I'd be interesting to know if Delphi behaved otherwise. But in the above
case the compiler warning about uninitialized variable is completely
valud, even if it's not random but initialized to zero due to OS and RTL
behavior.

Charlie



More information about the fpc-devel mailing list