[lazarus] New Bug Entered
Michael Van Canneyt
michael.vancanneyt at wisa.be
Mon Jul 14 09:30:58 EDT 2003
On Mon, 14 Jul 2003, Mattias Gaertner wrote:
> On Mon, 14 Jul 2003 14:38:50 +0200 (W. Europe Daylight Time)
> Michael Van Canneyt <michael.vancanneyt at wisa.be> wrote:
>
> >
> >
> > On Mon, 14 Jul 2003, Mattias Gaertner wrote:
> >
> > > On Sun, 13 Jul 2003 18:28:08 -0400
> > > bugtracker at miraclec.com wrote:
> > >
> > > >
> > > > Title: Datamodule generates AV on Lazarus exit
> > > >
> > > > Entered by: Tom Lisjac
> > > >
> > > > When a datamodule is renamed, OldCreateOrder is set and OnCreate and
> > > > OnDestroy events exist, Lazarus will AV upon exit with 1.0.10. Here
> > > > are the steps to reproduce:
> > > >
> > > > Bring up Lazarus in a new project.
> > > > Add a datamodule with File | New | Datamodule
> > > > With Property editor:
> > > > Rename the datamodule to dmt
> > > > Set OldCreationOrder to True
> > > > Create empty OnCreate and OnDestroy event handlers
> > > > Exiting Lazarus (saving or not) generates an AV
> > > >
> > > > This problem appeared after upgrading to 1.0.10 in a datamodule that
> > > > had been working fine with 1.0.7.
> > >
> > > Now, there you found a difficult thing. I always wonder, when it will
> > > appear. The IDE creates datamodule/forms descendents on the fly. That
> > > means, it really creates new classes and procedures at runtime. These
> > > procedures are empty and do nothing. The current trick is to copy an
> > > empty procedure. I was always sure, that this will give us trouble, as
> > > soon as the caller checks the stack or uses some special calling
> > > convention. Now you find an example:
> > >
> > > try
> > > AnEvent(Self);
> > > except
> > > end;
> > >
> > > When the 'except' frees the exception frame, it runs into trouble
> > > (internal error).
> > > I have commented the try..except in the LCL, so this error is hidden.
> > > One correct solution is to create better "empty procedures". This means
> > > an empty procedure, with the right length of parameters. I'm not sure
> > > how to do this for all kinds of calling conventions and processors.
> >
> > You can't.
>
> Why that?
Because the callee clears the stack. This is unlike C, where the caller
knows how much is pushed on the stack, and removes exactly this amount.
in FPC, the caller expects a certain amount on the stack, and removes
this amount from the stack, irrespective of whether this amount was
indeed pushed or not.
> > > Another solution is to simulate procedures. That means the procedures
> > > are not really set. But this requires changing TReader/TWriter to handle
> > > fake events and the RTTI will be incomplete.
> > > I prefer the first solution.
> > >
> > > Maybe a fpc guru can give me a hint.
> >
> > Before destroying your instances, all methods should simply be set to nil.
> > This is OK as long as it happens after the form file was written.
>
> Why do you think, the problem is only the destructor?
> Maybe this helps:
> When the IDE creates an event (reading a form or user creates a new event)
> it needs a TMethod record. That means the Self pointer "Data" and the
> procedure address "Code". Because the FCL and the RTTI uses the Code to
> identify a procedure, every event needs a unique procedure. The IDE uses a
> dirty trick and allocates a few bytes and copies the code from an empty
> method.
> Because the empty method has no parameters, it is, strictly speaking, only
> compatible to events without parameters. In fact it is something like this:
>
> MyDataModule.AnNotifyEvent:=TNotifyEvent(@MyDataModule.SimpleProc);
>
> A simple
>
> AnNotifyEvent(Self)
>
> works (at least on i386). But a
>
> try
> AnNotifyEvent(Self);
> except
> end;
>
> does not work.
Of course not, since the stack is messed up.
The exact error will depend on the particular code.
The way I see it is that during design time, NO callbacks may be set.
This also means that you must
- After form load, replace all filled in event handlers with nil, and
keep a record of this.
- In the object inspector, show the 'fake' record which you saved.
- When creating new events, put them in fake records.
- Before form saving, fill all callbacks again
- after form saving clear them again.
The best way of doing it IMHO is to make descendents of the
TReader/TWriter which do this automatically, and which also keep the
list of 'fake' records.
Michael.
More information about the Lazarus
mailing list