Closed Bug 298201 Opened 20 years ago Closed 19 years ago

[10.4] Tiger: Crash at [NSQuickDrawView dealloc]

Categories

(Camino Graveyard :: General, defect, P1)

PowerPC
macOS
defect

Tracking

(Not tracked)

RESOLVED FIXED
Camino0.9

People

(Reporter: avi, Assigned: sfraser_bugs)

References

Details

(Keywords: crash)

Attachments

(3 files, 1 obsolete file)

Version 2005061608 (0.9a1)

I'm getting fairly constant crashes that look like:

0   com.apple.QD                   	0x916acc28 SetGWorld + 64
1   com.apple.AppKit               	0x939cf030 -[NSQuickDrawView dealloc] + 36
2   org.mozilla.navigator          	0x00604b38 -[ChildView dealloc] + 44
3   com.apple.AppKit               	0x9362dacc -[NSView release] + 200
4   com.apple.Foundation           	0x92886f1c __delayedPerformCleanup + 48
5   com.apple.CoreFoundation       	0x90771470 CFRunLoopTimerInvalidate + 400
6   com.apple.CoreFoundation       	0x9075df08 __CFRunLoopDoTimer + 272

This has happened several times now on different sites; see talkbacks TB6754097G
and TB6816094M.

The stack traces seem very similar to those from bug 198101 which was closed
quite a while back.
Oh, yeah. Tiger, 10.4.1.
If this bug needed to be confirmed, I would do so. It looks like I've gotten it
as well, see TB6818265Y. I'm using OS X 10.4.1 and 2005061708.
Back in bug 198101, it was noted that [NSQuickDrawView dealloc] restored the
previously-active port, and that Camino, in its subclass, immediately called
SetPort(NULL) after, to make sure that no bad port stayed set. It seems now that
you crash as soon as you SetPort (or the equivalent here, SetGWorld) a bad port.
Perhaps this is new in Tiger? Should we cc Joseph Maurer, who's Mr. QuickDraw at
Apple, to see if this is indeed the case?
Priority: -- → P1
Summary: Crash at [NSQuickDrawView dealloc] → [10.4] Tiger: Crash at [NSQuickDrawView dealloc]
Target Milestone: --- → Camino0.9
*** Bug 297613 has been marked as a duplicate of this bug. ***
I get this crash a lot too. I'm attaching a Crash Log from the 0.9a1 alpha
release.
whee i saw this today as well.
Assignee: pinkerton → sfraser_bugs
Forgive me if I am doing this incorrectly but I am new to this.... I cannot use
Camino 0.9 because of frequent crashes, and, if I understand this system, it
might be helpful to squashing the bug if I post a crash log here. I've returned
to 0.8.4 since the alpha is so unstable. How does one learn when this bug has
been fixed? Thank you for your patience with me as a newbie!
In dealloc for ChildView:

[super dealloc];    // this sets the current port to _savePort
SetPort(NULL);      // this is safe on OS X; it will set the port to
                            // an empty fallback port.

Looks like this isn't safe any more...
I think(In reply to comment #8)
> Looks like this isn't safe any more...

I think that's unlikely; I doubt they'd change such a behaviour.

If you look at the stack, it's crashing in SetGWorld() called from
-[NSQuickDrawView dealloc], not -[ChildView dealloc], so that SetPort(NULL) is
not the one that crashes.

It's notable that CFRunLoopTimerInvalidate() is on the stack. I wonder if my adding
  [mView performSelector:@selector(setNeedsDisplayWithValue:) withObject:nil
afterDelay:0];
caused this.
Status: NEW → ASSIGNED
my gf is running a build (on tiger) from a couple months ago and hasn't seen
this problem at all. i think it's a "recent" regresion.
(In reply to comment #10)
> my gf is running a build (on tiger) from a couple months ago and hasn't seen
> this problem at all. i think it's a "recent" regresion.

Like from 6/16, when bug 294415 was checked in?
(In reply to comments #8, #9 and  #10)

The problem seems to be that [NSQuickDrawView dealloc] restores (via SetGWorld) whatever the current 
GWorld/GDevice was (some instance variable "savedPort") when the QuickdrawView was created, and that 
this previously current GWorld/GDevice either already was invalid (deallocated), or has been deallocated in 
the meantime.
The crash occurs or not, depending on whether the memory occupied by the now deallocated GWorld has 
been overwritten or not. Because of a change in the allocation patterns from one system revision to 
another, it may appear as a regression, but probably is not (I don't know what has changed in 
NSQuickdrawView, if anything).
SetPort(NULL) is always safe; but it just doesn't address the real problem. 
(In reply to comment #12)
> (In reply to comments #8, #9 and  #10)
> 
> The problem seems to be that [NSQuickDrawView dealloc] restores (via
> SetGWorld) whatever the current GWorld/GDevice was (some instance
> variable "savedPort") when the QuickdrawView was created, and that
> this previously current GWorld/GDevice either already was invalid
> (deallocated), or has been deallocated in the meantime.

Right. In other words, NSQuickDrawView expects to be used in a very constrained,
"nested" way with a well-specified lifetime. With autoreleasing and such, I
don't see how this can be expected in any Cocoa app, let alone one as complex as
a web browser.

> The crash occurs or not, depending on whether the memory occupied by
> the now deallocated GWorld has been overwritten or not. Because of a
> change in the allocation patterns from one system revision to
> another, it may appear as a regression, but probably is not (I don't
> know what has changed in NSQuickdrawView, if anything). SetPort(NULL)
> is always safe; but it just doesn't address the real problem. 

So would it be sensible to do a SetPort(NULL) just *before* our NSQuickDrawView
subclass calls -[NSQuickDrawView init], so that NSQuickDrawView stashes a "known
good" GWorld?
(In reply to comment #13)

Yes. (Should have suggested it myself :-).
Attached patch Patch (obsolete) — Splinter Review
This patch adds a call to SetPort(NULL) before the initialization of
ChildView's NSQuickDrawView superclass. It also changes the code to call the
designated initializer (-initWithFrame:) of NSQuickDrawView by passing in the
frame.

Can someone test this on Tiger?
Attachment #187612 - Flags: review?(pinkerton)
Comment on attachment 187612 [details] [diff] [review]
Patch

-  [mView setFrame:r];
+  //[mView setFrame:r];

shouldn't we just take this out?

looks good r=pink.
Attachment #187612 - Flags: review?(pinkerton) → review+
landed on trunk
Status: ASSIGNED → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
I'm still getting this crash with the 20050703 build. Twice within 30 minutes.
Same here. One of the Talkback IDs is TB7244415G.
Joseph: can you tell us anything about the "safe" port that is used when
SetPort() is called with NULL? Is it tied to a WindowPtr? Maybe we should be
making our own little GWorld to use as a "safe" port?
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
(In reply to comment #20)

No, it's not tied to any window. It's what you get back from CreateNewPort(), but the with an empty 
bounds rectangle in the portPixMap. - It's definitely not worth trying to use your own fallback GWorld 
instead.
Given that the crash persists, something else must be going on. 
Attached patch PatchSplinter Review
This patch essentially moves the SetPort(NULL) from -initWithFrame to
-lockFocus.

I determined with a bunch of printfs() and calls to IsValidPort() that
NSQuickDrawView doesn't actually assign to _savePort until -lockFocus is
called, so the previous patch wasn't doing much at all.

This patch also adds calls to |super| on a few methods that should have them
(just in case NSQuickDrawView implementes them), and adds an assertion that
should fire in the case where we may crash.
Attachment #187612 - Attachment is obsolete: true
Attachment #188401 - Flags: review?(pinkerton)
+- (void)lockFocus
+{
...
+  SetPort(NULL);
+  [super lockFocus];

Do we want to do this every time, or only the first time we draw/lockFocus?
Seems like it might cause other hidden issues to always be changing the port. Or
maybe we just want to be uber-safe.
(In reply to comment #23)
> +- (void)lockFocus
> +{
> ...
> +  SetPort(NULL);
> +  [super lockFocus];
> 
> Do we want to do this every time, or only the first time we draw/lockFocus?
> Seems like it might cause other hidden issues to always be changing the port. Or
> maybe we just want to be uber-safe.

We have to do it every time, because NSQDView stashes the current port in
_savePort every time.
Status: REOPENED → ASSIGNED
Comment on attachment 188401 [details] [diff] [review]
Patch

r=pink
Attachment #188401 - Flags: review?(pinkerton) → review+
Checked in. Please keep an eye out for this crash to see if we really nailed it
this time. Fix will be in 20050707 and later.
Status: ASSIGNED → RESOLVED
Closed: 20 years ago19 years ago
Resolution: --- → FIXED
Hmm, I'm seeing bad port assertions when running on Tiger. I see that in our
lockFocus override, where we do:

- (void)lockFocus
{
  SetPort(NULL);
  [super lockFocus];
}

_savePort is being set with an invalid port.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: