Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

problem with function named create in delphi

i have a base class declarated like this

type
  TBaseClass=class
   protected
    constructor Create(LoadData:boolean;const Param1,Param2:string); overload;
   public
    Destructor  Destroy; override;
  end;

Now in another unit a child class TChid_Class which descend from TBaseClass

  TChid_Class=class(TBaseClass)
   function Create(const Param1, Param2 : String;const Param3 : OleVariant ; var Param4 : LongInt): Integer;overload;
   constructor Create; overload;
   constructor Create(LoadData:boolean); overload;
  end;

in this class exist a function called Create like the constructors, the problem is , when i try to create a instance to the TChid_Class i have an access violation.

i wrote this small console app which show the problem

program TestClass;

{$APPTYPE CONSOLE}

uses
  Variants,
  SysUtils;

type
  TBaseClass=class
   protected
    constructor Create(LoadData:boolean;const Param1,Param2:string); overload;
   public
    Destructor  Destroy; override;
  end;

  TChid_Class=class(TBaseClass)
   function Create(const Param1, Param2 : String;const Param3 : OleVariant ; var Param4 : LongInt): Integer;overload;
   constructor Create; overload;
   constructor Create(LoadData:boolean); overload;
  end;

{ TBaseClass }

constructor TBaseClass.Create(LoadData: boolean; const Param1, Param2: string);
begin
   inherited Create;
   Writeln('constructor TBaseClass.Create(LoadData: boolean; const Param1, Param2: string);');
end;

destructor TBaseClass.Destroy;
begin
   //Code
  inherited;
end;

{ TChid_Class }

function TChid_Class.Create(const Param1, Param2: String;  const Param3: OleVariant; var Param4: Integer): Integer;
begin
   Writeln('function create');
   Result:=0;
end;

constructor TChid_Class.Create;
begin
   Writeln('constructor TChid_Class.Create');
   Create(True);
end;

constructor TChid_Class.Create(LoadData: boolean);
begin
  Writeln('constructor TChid_Class.Create(LoadData: boolean)'); //here is the access violation
  Create(LoadData,'Value 1','Value 2');
end;


var
   Invoker : TChid_Class;
   Pid     : integer;
begin
  try
     Invoker:=TChid_Class.Create;
     try
       Invoker.Create('','',Unassigned,Pid)
     finally
      Invoker.Free;
     end;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;

  readln;
end.

if i rename the function create, the problem is go away, but i am looking for a solution without rename the create function or the constructors.

using delphi 2007

Thanks in advance.

like image 867
Salvador Avatar asked Dec 15 '10 00:12

Salvador


1 Answers

With Delphi 7 I get an AV too. Renaming the method or moving it (as suggested by Sertac Akyuz) fixes the AV.

What I discovered by looking at the assembler:

When creating a new object a non-zero value is placed in register dl before calling the constructor.

mov dl,$01              // dl set to 1
mov eax,[$00401268]
call TChild_Class.Create

Then in the constructor, on the begin line, ClassCreate is called when dl is non-zero.

test dl,dl       
jz +$08          //if dl = 0 then do not call ClassCreate
add esp,-$10
call -$00000396  //calls ClassCreate

But then it goes wrong, with your code, the compiler sets dl to 1 again before calling Create(True), so on the begin line of TChid_Class.Create(LoadData: boolean);, ClassCreate is called again which results in an AV.

After renaming your function or moving its declaration, the compiler clears dl (xor edx,edx) instead of setting it to 1, before calling Create(True).

My guess is that it is a bug in the Delphi compiler which is fixed in Delphi 2010 and higher.

like image 92
The_Fox Avatar answered Sep 21 '22 03:09

The_Fox