Recent

Author Topic: How to detect uninitialised variables passed to a procedure  (Read 793 times)

ad1mt

  • Full Member
  • ***
  • Posts: 164
    • Mark Taylor's Home Page
How to detect uninitialised variables passed to a procedure
« on: December 02, 2023, 12:36:36 pm »
I have a record type like this:
Code: Pascal  [Select][+][-]
  1. T1=record
  2.    V1:array of T2;
  3.    Defined:boolean;
  4.    end;
  5.  
And I have a procedure which assigns/initialises vars of type T1, like this:
Code: Pascal  [Select][+][-]
  1. procedure init_T1(var R1:T1);
  2. begin
  3. if not R1.Defined then setlength(R1, T1_MAXLENGTH);
  4. end;
  5.  
The procedure detects whether an input parameter is initialised by looking at the Defined var, and if undefined, initialises R1 by calling setlength.
Unfortunately, my program has just crashed because a call to init_T1 was passed a R1 var that contained random values that caused R1.Defined to be evaluated = TRUE.
I can think of ways round this, but they would not be 100% reliable... my solution would very occasionally crash if random junk was on the stack that made the variable appear to be defined.
Can anyone suggest an elegant and 100% reliable solution to this problem?
Thanks.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11283
  • FPC developer.
Re: How to detect uninitialised variables passed to a procedure
« Reply #1 on: December 02, 2023, 12:39:20 pm »
There is no safe solution, the status is not known in a running program.

ad1mt

  • Full Member
  • ***
  • Posts: 164
    • Mark Taylor's Home Page
Re: How to detect uninitialised variables passed to a procedure
« Reply #2 on: December 02, 2023, 02:08:09 pm »
There is no safe solution, the status is not known in a running program.
I would like to suggest a new compiler feature...
A compiler switch/option, which would automatically initialize all local/stack variables to binary zeros upon allocation.

Thaddy

  • Hero Member
  • *****
  • Posts: 13968
  • Probably until I exterminate Putin.
Re: How to detect uninitialised variables passed to a procedure
« Reply #3 on: December 02, 2023, 02:26:55 pm »
Not a switch, but the default intrinsic would also zero out stack allocated variables.
Note that if you run into trouble at all you have a design flaw.
« Last Edit: December 02, 2023, 02:41:41 pm by Thaddy »
Specialize a type, not a var.

cdbc

  • Hero Member
  • *****
  • Posts: 955
    • http://www.cdbc.dk
Re: How to detect uninitialised variables passed to a procedure
« Reply #4 on: December 02, 2023, 02:40:09 pm »
Hi
Management operators like Initialize & Finalize gets called on entering scope and leaving scope, I think they're just what you're after... See: https://wiki.freepascal.org/management_operators
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

jamie

  • Hero Member
  • *****
  • Posts: 6030
Re: How to detect uninitialised variables passed to a procedure
« Reply #5 on: December 02, 2023, 04:20:00 pm »
For remote units, other than the main file, you can use the "Initialization" section to clear the variables that are global to the corrent unit if you don't want to deal with managed head acks.
The only true wisdom is knowing you know nothing

ad1mt

  • Full Member
  • ***
  • Posts: 164
    • Mark Taylor's Home Page
Re: How to detect uninitialised variables passed to a procedure
« Reply #6 on: December 03, 2023, 09:01:31 am »
Hi
Management operators like Initialize & Finalize gets called on entering scope and leaving scope, I think they're just what you're after... See: https://wiki.freepascal.org/management_operators
Regards Benny
Thanks for that suggestion... it does look like that's exactly what I need.

ad1mt

  • Full Member
  • ***
  • Posts: 164
    • Mark Taylor's Home Page
Re: How to detect uninitialised variables passed to a procedure
« Reply #7 on: December 03, 2023, 09:29:35 am »
Hi
Management operators like Initialize & Finalize gets called on entering scope and leaving scope, I think they're just what you're after... See: https://wiki.freepascal.org/management_operators
Regards Benny
I've justed tested it... unfortunately, it does not work for my purposes.
It appears that the Initiialize routine is called after assignment.  Whereas I need it to be called after memory is allocated, but before assignment.  The fact that it is called after assignment, I think is a bug, and sort of defeats the purpose of the idea.

So, to make it clear, my problem happens when a variable is allocated on the stack (e.g. for a function parameter, or a local variable), but has not yet been assigned a value.
If the variable allocation happens as part of an assignment, and then the initialize routine is called after a value is assigned, then the initialize function overwrites the value created in the assignment.
« Last Edit: December 03, 2023, 11:14:45 am by ad1mt »

440bx

  • Hero Member
  • *****
  • Posts: 3860
Re: How to detect uninitialised variables passed to a procedure
« Reply #8 on: December 03, 2023, 10:19:45 am »
Can anyone suggest an elegant and 100% reliable solution to this problem?
Thanks.
The solution is to add a signature field to the record, usually at the beginning of the record, that must be set to a specific value to denote the data in the record has been initialized and is therefore usable.

If the field is a DWORD set to a value that is uncommon, such as "INZD" (four bytes for "initialized" then, while not 100% reliable, it is very unlikely that  the value would just happen to occur.  If you want to make the probability even lower then have a signature field at the beginning of the record and another one at the end.  You can enforce a relationship between the two values to denote the record has been initialized.  You can also choose to make the signature a qword if your program is 64bit.  I'm sure, by now, you get the idea.

By the way, this method is fairly standard - likely older than I am.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.1 both fixes) on Windows 7 SP1 64bit.

kwyan

  • New Member
  • *
  • Posts: 23
Re: How to detect uninitialised variables passed to a procedure
« Reply #9 on: December 03, 2023, 10:28:19 am »
@ad1mt,

I read your original question and found your codes do not work. In fact, if you pass argument R1 as type T1 to the procedure,  you no need to SetLength to R1. The memory for R1 is already allocated by the caller program (which you haven't put in your original post).

For example: the caller procedure:

procedure Test_Init_T1;
var
   R : T1; // memory for R is already allocated.
begin
   init_T1(R);
end;

Do you mean that you want to SetLength to R1.V2 array?

If yes, you no need to create a new variable T1.Defined. You can directly check the length of R1.V2:

procedure init_T1(var R1:T1);
begin
   if not Assigned(R1.V2) then
     SetLength(R1.V2, 100);
end;

Note: Dynamic arrays are initialized to nil.
https://www.freepascal.org/docs-html/ref/refse20.html#x50-700003.9

 

TinyPortal © 2005-2018