?
Solved

Invalid Pointer Operation - TApplication.Components holds bad reference

Posted on 2012-03-29
17
Medium Priority
?
712 Views
Last Modified: 2012-03-30
[EDIT] I am using Delphi XE2 with update 3. We cannot upgrade to 4 at this time.

Hey there, hopefully there is a simple solution here because this problem is rather urgent. I will likely not be able to test solutions until morning though.

This closely mirrors our code. It uses a session component and a query component in the ODAC suite by Corelab. I am not sure that those exact components matter. I think I could get the same results with any TComponent. Following this access violation, shutting down the application generates Invalid Pointer Operation and the application hangs. It will not close. Application.Components still maintains a reference to the created TForm2 even though the free is being called.

uses
  Unit2, Ora;

type
  TMyClass = class
  public
    Sess: TOraSession;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Frm: TForm2;
  MyClass: TMyClass;
begin
  Frm := TForm2.Create(Application);
  try
    Frm.Qry.Session := MyClass.Sess; // AV generated here
  finally
    Frm.Free;
  end;
end;

Open in new window


Thanks in advance,
Michael
0
Comment
Question by:MichaelStaszewski
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 10
  • 7
17 Comments
 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37784640
I forgot to add that the problems go away if nil is used as TForm2's owner (as expected) and that Frm.release and freeandnil(frm) have no effect.

Also, the code that is failing is when TApplication destroy's its components. Going to test Delphi 2009 now to see if this issue is a new addition to Delphi.

Delphi 2009 also fails. Any insight on how to avoid this would be fantastic. Ideally we'll not code in exceptions :-) but we have a ton of code and unfortunately things slip through. It would be nice to have EurekaLog grab the unhandled ones and still let the application shutdown without hanging.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 37785079
you aren't showing MyClass := TMyClass.Create; line

the AV you get here is correct as MyClass has not been instantiated and thus
if Assigned(MyClass) is false


if Assigned(MyClass) then
  frm.qry.Session := MyClass.Session;


maybe MyClass is owned by a other form which gets freed just before Form2  gets freed
0
 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37785184
I apologize, but I should have been clearer. I am not creating TMyClass intentionally to produce the AV. We have an AV condition in our code that we can solve, but it illustrates a scenario I thought was impossible. In my code, above, frm.free is being called. It is my understanding that this will remove the object from the components list of its owner. In this case, Application.Components retains a reference to the freed form and invalid pointer operation is raised at shutdown. The exception is only seen when debugging in the IDE. The application is still running with no taskbar button and pegs the CPU. Why is this? Why does Application retain the reference?

I'll try to find a reproducible scenario using native components in the morning. Thanks.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37785191
I should also add that i have 2 forms. TForm2 contains a query component and no code. TForm1 contains a TButton and only the code shown above in the implementation section.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 37785199
it should come down to where you create the session and where it is freed
and after it is freed, where it is still referenced

always use freeandnil to free a component (even a form)
0
 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37785205
Freeandnil has no effect here. The raised exception is somehow preventing the call to free from notifying its owner that it is no longer instantiated. The owner still thinks it owns this freed object.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 37785310
the form will only free objects which it owns

you probably have this

unit Form1:
var MyClass: TClass;
MyClass := TClass.Create(Form1);

Form2
Close > MyClass.Free;

why not add logging to the destructor of TMyClass ?

destructor TMyClass.Destroy;
begin
  //>> Breakpoint and Call stack Ctrl-F3 to find where freed
  inherited Destroy;
end;
0
 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37785746
No. I have only as described and what you see in my sample code. My sample project, used purely for illustrative purposes has two forms. TForm1 (AKA Application.mainform) has a single TButton with assigned OnClick and a simple class. All code for the class and OnClick are shown above. There is nothing more in TForm1. Another form, TForm2, contains a single component. It is a TSmartQuery from a 3rd party library we use. There is no code at all in TForm2. This is the *entire* code in my sample app created to isolate the behavior I'm seeing.

The AV is trivial. We have isolated and fixed it in our production app. What is unclear to me is why TApplication continues to think that it owns an instance of TForm2 (in my sample app) when it has clearly been freed. It is the first time in my 10 years of Delphi experience that I've seen this and the same goes for my colleagues who each have more Delphi experience than myself. Ideally what we'd like to do is prevent this scenario from occuring for cases where we may not catch exceptions before we release our product. Our product is large, 3.2 million lines of code, and although it is tested thouroughly before release some bugs do escape detection and in those cases it would be nice to avoid this hanging scenario. If it's just the way it is then so be it, but I've not knowingly seen this before.

I hope the problem is more clearly described now.

Thanks,
Michael
0
 
LVL 38

Accepted Solution

by:
Geert Gruwez earned 2000 total points
ID: 37786288
it's a bit of a bad sample in your header question
> myclass is not instantiated

we use devart components ODAC too (former corelab) and don't have this issue
we aren't using the XE2 yet.
> we have had issues with ODAC but they got resolved within 1 or 2 weeks.

usually when it comes to hanging, i have to investigate the order of freeing objects
and especially the order of freeing objects in the finalization of units.

maybe you should open a case with Embarcadero or DevArt ?
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 37786297
ugh ... sometimes i do get a bug in Toad ... :)
0
 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37786621
:-)

That's what we try to avoid. I'll try a case w/ devart and post back. We are on the devart version, latest version, but i see this in an earlier one too in Delphi 9.

Thanks,
Michael
0
 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37786653
I mean... Delphi *2009*

And the sample is terrible. It's poor code for sure... sometimes unexpected conditions allow such scenarios to exist. :-(
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 37786688
this is just guessing, but could it be a timing issue ?

sample:
set a timer on form1 with a event handler from form2
(only possible in code)
after freeing form1 sometimes the event handler still gets called

procedure TForm1.OnCreate;
begin
  Timer1.OnTimer := Form2OnTimer;
end;

>> Free(Form1);

procedure TForm2.OnTimer;
begin
  Form1.Caption := 'Timer called'; >> Av here
end;
0
 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37787002
I have seen TTimer issues many times in the past doing exactly what you suggest. My solution for that has always been to disable all timers in TForm.OnDestroy handler. I'm not sure that the same issue applies here. Nevertheless I thought perhaps you were on to something so I wrapped my code in a try..except just to see if the open exception dialog in the application while the form had been freed was the cause. No joy.

procedure TForm1.Button1Click(Sender: TObject);
var
  Frm: TForm2;
  MyClass: TMyClass;
begin
  Frm := TForm2.Create(Application);
  try
    try
      Frm.Qry.Session := MyClass.Sess;
    except
    end;
  finally
    Frm.Free;
  end;
end;

Open in new window

0
 
LVL 4

Author Closing Comment

by:MichaelStaszewski
ID: 37787704
Thanks Geert_Gruwez for listening and providing your comments. After some sleep and coffee the problem is more clear. An ODAC control is raising an exception in its destructor due to the buggy code and it's bypassing necessary code in TComponent.Destroy. Ughh. The solution... don't create buggy code. :-) Everything is functioning as designed.

A correction. I saw massive exceptions in Delphi 2009, but it does not hang in that version afterall. I was mistaken. Eventually the application closes. This looks like an XE2 specific thing. I don't have XE to test with. It's a slow day, I'll try to get to the bottom of the hang and send to Embarcadero to see if there's a bug there. Crappy code aside it would be nice if the application could recover and close without CPU pegging.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 37788173
you may also want to look at FreeNotification
Components wanting to be notified of other components being freed use FreeNotification
and RemoveFreeNotification
0
 
LVL 4

Author Comment

by:MichaelStaszewski
ID: 37788638
That was our solution to this particular problem. I was more or less looking to see if anyone had a possible solution to avoid application hang in the event of such an AV.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses
Course of the Month14 days, 4 hours left to enroll

801 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question