Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mysterious stack overflow in constructor

This is class hierarchy that my program uses:

enter image description here

The constructor of TForm_Upgrade_Database is looking like following:

__fastcall TForm_Upgrade_Database::TForm_Upgrade_Database(TComponent* Owner, int newest_version) : TForm(Owner) { }

After trying to create instance of formular

TForm_Upgrade_Database *dlg = new TForm_Upgrade_Database(this, newest_version);

my program throws EStackOverflow exception

enter image description here

I stopped program and ran it again with breakpoint in TForm_Upgrade_Database constructor. After few steps callstack looks like this:

enter image description here

How is it that TCustomForm constructor keeps trying to call constructor of its descendant???

Minimal test case:

so_project.cpp:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "f_form.h"
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
   TForm_Upgrade_Database *form = new TForm_Upgrade_Database(NULL, 10);
   delete form;
   form = NULL; 

   return 0;
}
//---------------------------------------------------------------------------

f_form.cpp:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "f_form.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm_Upgrade_Database *Form1;
//---------------------------------------------------------------------------
__fastcall TForm_Upgrade_Database::TForm_Upgrade_Database(TComponent* Owner, int x)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------

f_form.h:

//---------------------------------------------------------------------------

#ifndef f_formH
#define f_formH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm_Upgrade_Database : public TForm
{
__published:    // IDE-managed Components
private:    // User declarations
public:     // User declarations
   __fastcall TForm_Upgrade_Database(TComponent* Owner, int x);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm_Upgrade_Database *Form1;
//---------------------------------------------------------------------------
#endif
like image 802
truthseeker Avatar asked Mar 19 '12 15:03

truthseeker


2 Answers

TForm has a virtual construtor that takes TComponent* and int parameters, in that order. You are overriding that constructor. By calling the base-class constructor that only takes a TComponent* parameter, you are in fact creating a recursive loop when those constructors call each other internally.

The solution is what truthseeker said. You have to change the parameters of your derived constructor so you are not overriding the base class TComponent*/int constructor anymore. Changing the order of the parameters is enough, or you can change the int to a different data type.

like image 163
Remy Lebeau Avatar answered Nov 14 '22 09:11

Remy Lebeau


I think this has to do with some non-standard solutions in delphi library. VCL libraries are written and compiled in Delphi Pascal. Cooperation with C++ is made through interface files (with extension *.hpp). Compiled binary code is probably searching for constructor parameters on incorrect memory offsets. So this is probably a problem of calling convention.

I succeeded creating instance of formular when changing parameters in constructor so that the new parameter is first.

f_form.h:

__fastcall TForm_Upgrade_Database(int x, TComponent* Owner);

f_form.cpp:

__fastcall TForm_Upgrade_Database::TForm_Upgrade_Database(int x, TComponent* Owner)
    : TForm(Owner)
{
}

so_project.cpp:

TForm_Upgrade_Database *form = new TForm_Upgrade_Database(10, NULL);
like image 45
truthseeker Avatar answered Nov 14 '22 09:11

truthseeker