Is the compiler treatment of implicit interface variables documented?

前端 未结 2 444
生来不讨喜
生来不讨喜 2020-12-13 23:18

I asked a similar question about implicit interface variables not so long ago.

The source of this question was a bug in my code due to me not being aware of the exis

相关标签:
2条回答
  • 2020-12-14 00:06

    You can not guarantee that compiler will not decide to create a temporal invisible variable.

    And even if you do, the turned off optimization (or even stack frames?) may mess up your perfectly checked code.

    And even if you manage to review your code under all possible combinations of project options - compiling your code under something like Lazarus or even new Delphi version will bring hell back.

    A best bet would be to use "internal variables can not outlive routine" rule. We usually do not know, if compiler would create some internal variables or not, but we do know, that any such variables (if created) would be finalized when routine exists.

    Therefore, if you have code like this:

    // 1. Some code which may (or may not) create invisible variables
    // 2. Some code which requires release of reference-counted data
    

    E.g.:

    Lib := LoadLibrary(Lib, 'xyz');
    try
      // Create interface
      P := GetProcAddress(Lib, 'xyz');
      I := P;
      // Work with interface
    finally
      // Something that requires all interfaces to be released
      FreeLibrary(Lib); // <- May be not OK
    end;
    

    Then you should just wrap "Work with interface" block into subroutine:

    procedure Work(const Lib: HModule);
    begin
      // Create interface
      P := GetProcAddress(Lib, 'xyz');
      I := P;
      // Work with interface
    end; // <- Releases hidden variables (if any exist)
    
    Lib := LoadLibrary(Lib, 'xyz');
    try
      Work(Lib);
    finally
      // Something that requires all interfaces to be released
      FreeLibrary(Lib); // <- OK!
    end;
    

    It is a simple, but effective rule.

    0 讨论(0)
  • 2020-12-14 00:12

    If there is any documentation of this behavior, it will probably be in the area of compiler production of temporary variables to hold intermediate results when passing function results as parameters. Consider this code:

    procedure UseInterface(foo: IInterface);
    begin
    end;
    
    procedure Test()
    begin
        UseInterface(Create());
    end;
    

    The compiler has to create an implicit temp variable to hold the result of Create as it is passed into UseInterface, to make sure that the interface has a lifetime >= the lifetime of the UseInterface call. That implicit temp variable will be disposed at the end of the procedure that owns it, in this case at the end of the Test() procedure.

    It's possible that your pointer assignment case may fall into the same bucket as passing intermediate interface values as function parameters, since the compiler can't "see" where the value is going.

    I recall there have been a few bugs in this area over the years. Long ago (D3? D4?), the compiler didn't reference count the intermediate value at all. It worked most of the time, but got into trouble in parameter alias situations. Once that was addressed there was a follow up regarding const params, I believe. There was always a desire to move disposal of the intermediate value interface up to as soon as possible after the statement in which it was needed, but I don't think that ever got implemented in the Win32 optimizer because the compiler just wasn't set up for handling disposal at statement or block granularity.

    0 讨论(0)
提交回复
热议问题