Recent

Author Topic: "Local variable does not seem to be initialized" for move, fillchar - won't fix?  (Read 12242 times)

Artlav

  • New Member
  • *
  • Posts: 36
    • Orbital Designs
So, there is many a line in the code to the effect of
Code: [Select]
fillchar(lambda[0],32,0);
Lazarus would give out a warning for it:
Code: [Select]
ecc.pas(146,11) Hint: Local variable "lambda" does not seem to be initialized
It's a useful warning in many cases, so i don't want to disable it completely.
I also don't want to be putting {%H-} everywhere.

So i edited the RTL of FPC, to redefine these functions like

Code: Pascal  [Select][+][-]
  1. Procedure FillChar(out x;count:SizeInt;Value:Byte);
  2. Procedure FillChar(out x;count:SizeInt;Value:Boolean);
  3. Procedure FillChar(out x;count:SizeInt;Value:Char);

This got rid of the warning, and for a time all was well.

However, i just tried to rebuild Lazarus, and there were a lot of weird crashes.
Rolling back that fix restored it's functionality, and left me with a profound feeling of WTF.

So, WTF?
Why do these generate a warning, and why making an output-only-by-definition parameter output-only breaks things?


Artlav

  • New Member
  • *
  • Posts: 36
    • Orbital Designs
Quote from: Graeme Geldenhuys
No, that is not possible. I once tried to change move and fillchar to use "out" parameters instead of "var" parameters, and the result was all sorts of crashes. The reason is that "out" has special semantics for reference counted types (they are finalized at the *caller* side), and move/fillchar are sometimes used to zero uninitialised data (so if the run time then tries to finalise garbage, you get crashes).

I see, thanks. That's the sort of thing i suspected might be happening.

Ok, so why wasn't this fixed some other way since then?
I.e. add a marker like {%H-}, only to be placed at the definition, telling the compiler to ignore a warning if it's about the definition with a marker?

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Ok, so why wasn't this fixed some other way since then?
I.e. add a marker like {%H-}, only to be placed at the definition, telling the compiler to ignore a warning if it's about the definition with a marker?

{%H-} is a Lazarus IDE directive. It is effective only within the Lazarus IDE, and when using the IDE to do builds and compiles. But I guess you could devise a macro to automatically insert this directive in FillChar code.
FPC knows nothing of such comments and does not use them, and correctly ignores them.

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
The way to hide specific messages locally is also documented in the users and programmers manual.
An example would be
Code: Pascal  [Select][+][-]
  1. program testmt;
  2.  
  3. procedure test;
  4. var
  5.   Buffer: array[0..9] of char;
  6. {$push}
  7. {$warn 5057 off}  // hide warning var not initialized
  8. begin
  9.   fillchar(buffer,32,10)
  10. end;
  11. {$pop}
  12.  
  13. begin
  14. end.
$push and $pop save and restore the currently active directives/environment.
Globally you can add the above w.o push/pop or use -vm5057 as option
http://freepascal.org/docs-html/current/user/usersu13.html#x36-430005.1.2
http://freepascal.org/docs-html/current/prog/progsu80.html#x87-860001.2.80

Note: the push and pop are here around the begin end block of the procedure, but in fact you can use it inside the procedure for defined blocks as well.
Since this procedure has no blocks, it surrounds the whole procedure. It doesn't work on statements alone. Unless that statement implies a block. (while, case, if then)

Note2: The easiest way to obtain the error number is to compile with  -vwhnlq which will give you line number + error code for warnings,hints and notes.
I am not aware of a standard unit with more readable defines for these numbers.
« Last Edit: April 01, 2017, 06:47:34 am by Thaddy »
Specialize a type, not a var.

creaothceann

  • Full Member
  • ***
  • Posts: 117
I did it in my code like this:

Code: Pascal  [Select][+][-]
  1. procedure MemClear(out DATA;  const ByteCount : u64);
  2. begin
  3. System.FillChar((@DATA)^, ByteCount, 0);
  4. end;
  5.  
  6.  
  7. function MemCompare(p1, p2 : pointer;  ByteCount : u64) : bool;
  8. var p1_08 : ^u8 absolute p1;    p1_16 : ^u16 absolute p1;    p1_32 : ^u32 absolute p1;    p1_64 : ^u64 absolute p1;
  9. var p2_08 : ^u8 absolute p2;    p2_16 : ^u16 absolute p2;    p2_32 : ^u32 absolute p2;    p2_64 : ^u64 absolute p2;
  10. begin
  11. while (ByteCount >= 8) do begin  if (p1_64^ <> p2_64^) then exit(False);  Inc(p1_64);  Inc(p2_64);  Dec(ByteCount, 8);  end;
  12. while (ByteCount >= 4) do begin  if (p1_32^ <> p2_32^) then exit(False);  Inc(p1_32);  Inc(p2_32);  Dec(ByteCount, 4);  end;
  13. while (ByteCount >= 2) do begin  if (p1_16^ <> p2_16^) then exit(False);  Inc(p1_16);  Inc(p2_16);  Dec(ByteCount, 2);  end;
  14. while (ByteCount >= 1) do begin  if (p1_08^ <> p2_08^) then exit(False);  Inc(p1_08);  Inc(p2_08);  Dec(ByteCount   );  end;
  15. Result := True;
  16. end;
  17.  
  18.  
  19. procedure MemCopy(const SRC;  out DEST;  const ByteCount : u64);
  20. begin
  21. System.Move((@SRC)^, (@DEST)^, ByteCount);
  22. end;

(u64 = QWord, bool = Boolean)
« Last Edit: April 01, 2017, 09:44:04 am by creaothceann »

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
Look at the date.....
Specialize a type, not a var.

Artlav

  • New Member
  • *
  • Posts: 36
    • Orbital Designs
The way to hide specific messages locally is also documented in the users and programmers manual.
Yes, this does work.
The problem is not that it's impossible to do, it's that every way to do it that exists now is quite ugly.

I want a way to cut such obviously invalid warnings at the source, instead of slapping tentacles forever.

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
You can use

Code: [Select]
procedure fillptr(p: pointer; size: integer; v: integer = 0); inline;
begin
  fillchar(p^, size, v);
end;     

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
And for smaller sizes you can of course simply initialize at declaration:
Code: Pascal  [Select][+][-]
  1. procedure test;
  2. var
  3.   Buffer: array[0..9] of byte =(32,32,32,32,32,32,32,32,32,32);
  4. begin
  5. end;
  6.  
Specialize a type, not a var.

creaothceann

  • Full Member
  • ***
  • Posts: 117
It's actually enough to set only one item of an array (or one field of a record) to make the message go away.

Code: Pascal  [Select][+][-]
  1. procedure Test;
  2. var buffer : array[0..9] of byte;
  3. begin
  4. buffer[0] := 0;
  5. // ...
  6. end;

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
It's actually enough to set only one item of an array (or one field of a record) to make the message go away.

Code: Pascal  [Select][+][-]
  1. procedure Test;
  2. var buffer : array[0..9] of byte;
  3. begin
  4. buffer[0] := 0;
  5. // ...
  6. end;
And that... is conceptually wrong..
It is rather strange that the compiler doesn't warn there, because the array is NOT initialized. Just one element is.
Actually it is much worse than the original bogus warning. Can get you into a lot of trouble.
Don't try that at home.. You may well be introducing bugs in other cases than to prevent the not initialized warning when it is initialized by fillchar.
Specialize a type, not a var.

creaothceann

  • Full Member
  • ***
  • Posts: 117
In FPC's defense, it's probably unreasonable to let the compiler keep track of every single byte of an array/record... I could easily declare and use a 30GB array in RAM (on my machine), but not if the compiler tries to keep track of it (without some clever logic).

del

  • Sr. Member
  • ****
  • Posts: 258
Code: Pascal  [Select][+][-]
  1. buff: array[1..BUF_SIZE] of byte;
  2.  
  3. begin
  4.  buff[1] := 0;

I went this route myself. (BUF_SIZE is 2048). The warnings are just to draw your attention to things. The compiler just wants to feel comfortable that you're aware of the situation. That's why the compiler warns you about "implicit" conversions. So instead of "muting" the compiler, I signal to the compiler that I'm aware of the situation. And the compiler calms down.

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Code: Pascal  [Select][+][-]
  1.  buff[1] := 0;

The first element of the array is 0 not 1.

See Thaddy's warning above about doing this: the cure may be worse than the disease.

Personally I'd use initialize:

Code: Pascal  [Select][+][-]
  1. procedure foo;
  2. var
  3.   buffer : array[0..9] of byte;
  4. begin
  5.   initialize(buffer, length(buffer));
  6.  ...

Finally, you're replying to a 4 year old thread.

 

TinyPortal © 2005-2018