Closed
Bug 573737
Opened 14 years ago
Closed 14 years ago
Throw from ctor arg may corrupt GCFinalizedObject
Categories
(Tamarin Graveyard :: Garbage Collection (mmGC), defect, P1)
Tracking
(Not tracked)
RESOLVED
FIXED
flash10.1.x-Crush
People
(Reporter: pnkfelix, Assigned: rulohani)
References
Details
(Whiteboard: WE:2638752)
Attachments
(3 files, 3 obsolete files)
1.54 KB,
patch
|
rulohani
:
feedback+
|
Details | Diff | Splinter Review |
1.02 KB,
patch
|
treilly
:
review+
lhansen
:
superreview+
|
Details | Diff | Splinter Review |
7.29 KB,
patch
|
treilly
:
review+
lhansen
:
superreview+
rulohani
:
feedback+
|
Details | Diff | Splinter Review |
Problem summary (extracted from email dialogue below): (1) XMLObject::operator new is run, allocating a new (zeroed) memory chunk. (2) args to XMLObject::XMLObject are pushed on the stack; in evaluating these, we throw an exception (3) later, we try to clean up the XMLObject that was new'ed (but not ctor'ed), but since it's all zeroed -- including the C++ vtable -- we crash trying to vall the virtual dtor. Pasted below is (most of) an e-mail dialogue between mmgc folks about the problem (ordered with most recent email first). Will be uploading a proposed selftest shortly. On Jun 22, 2010, at 3:52 AM, Lars Hansen wrote: The underlying problem is that the 'finalize' bit, which requires the vtable to be present, is set by the allocator, not when the object has been constructed. We could try to split that up, but the performance implications are uncertain and I'm not sure how we would do it, really (maybe GCFinalizedObject::GCFinalizedObject could set it). The better long-term choice is probably still to remove the requirement for GC'd storage to subclass GC classes, and instead store all this meta-information in a manner we control. --lars On Jun 21, 2010, at 11:03 PM, Steven Johnson wrote: Ignore previous, instead change GCAssert(*(intptr_t*)obj != 0); bits[i] &= ~(kFinalize<<(j*4)); // Clear bits first so we won't get second finalization if finalizer longjmps out obj->~GCFinalizedObject(); to bits[i] &= ~(kFinalize<<(j*4)); // Clear bits first so we won't get second finalization if finalizer longjmps out if (*(intptr_t*)obj != 0) obj->~GCFinalizedObject(); ? On Jun 21, 2010, at 2:00 PM, Steven Johnson wrote: So, in theory, we could fix it with chaning obj->~GCFinalizedObject(); to something like if (((void**)obj)[-1] != NULL) obj->~GCFinalizedObject(); ? On Jun 21, 2010, at 1:58 PM, Ruchi Lohani wrote: I think I confused everything here. My earlier point that the RCObject is first getting reaped in ReapObject and then in GCAlloc::Finalize() is not valid. Actually that wasn’t happening! The problem is exactly what steven said below. From: Steven Johnson Sent: Monday, June 21, 2010 1:56 PM To: Felix Klock II Cc: Ruchi Lohani; Lars Hansen Subject: Re: RC Finalized object dtor I think she's saying that this happens: (1) XMLObject::operator new is run, allocating a new (zeroed) memory chunk. (2) args to XMLObject::XMLObject are pushed on the stack; in evaluating these, we throw an exception (3) later, we try to clean up the XMLObject that was new'ed (but not ctor'ed), but since it's all zeroed -- including the C++ vtable -- we crash trying to vall the virtual dtor. yes? On Jun 21, 2010, at 1:53 PM, Felix Klock II wrote: Ruchi- Just so I understand: You're saying that the stack is overflowing while trying to initialize a string object, and that by chance the memory that it is trying to initialize was previously occupied by an RCObject [which is what led to the hypothesis that an argument to ZCT::ReapObject was later being passed to GCAlloc::Finalize()], and your current hypothesis is that our finalization system does not have safe-guards in place (or at least not sufficiently many) to ensure that partially initialized objects are not eligible for finalization? Is all of the above a correct interpretation? -Felix On Jun 21, 2010, at 4:45 PM, Ruchi Lohani wrote: Including Steven. I think I figured out the problem: From the allocation in XMLClass.cpp : XMLObject *x = new (core->GetGC()) XMLObject(toplevel->xmlClass(),core->string(arg), defaultNamespace); Somehow the call to core->string(arg) is going into handling stack overflow; stackoverflow exception is thrown and the player is aborted but the memory allocation has already happened and the memory is initially memset to 0 but the ctor did not get called. GC crashes when trying to finalize this object which was partially initialized. I have worked around this crash by taking out ‘core->string(arg)’ from the call above. Is there any other better way we probably would want to fix it? Thanks Ruchi From: Ruchi Lohani Sent: Monday, June 21, 2010 10:38 AM To: Ruchi Lohani; Lars Hansen Cc: Felix Klock II Subject: RE: RC Finalized object dtor RCobject finalization: NPSWF32.dll!avmplus::ScriptObject::~ScriptObject() Line 85 C++ NPSWF32.dll!avmplus::XMLObject::~XMLObject() + 0x21 bytes C++ NPSWF32.dll!avmplus::XMLObject::`scalar deleting destructor'() + 0x16 bytes C++ NPSWF32.dll!MMgc::ZCT::ReapObject(MMgc::RCObject * obj=0x072ce688) Line 543 + 0x10 bytes C++ NPSWF32.dll!MMgc::ZCT::Reap(bool scanStack=true) Line 390 C++ NPSWF32.dll!MMgc::ZCT::AddSlow(MMgc::RCObject * obj=0x07349798) Line 255 C++ NPSWF32.dll!MMgc::ZCT::Add(MMgc::RCObject * obj=0x07349798) Line 68 C++ NPSWF32.dll!MMgc::GC::AddToZCT(MMgc::RCObject * obj=0x07349798) Line 596 C++ NPSWF32.dll!MMgc::RCObject::RCObject() Line 213 C++ NPSWF32.dll!avmplus::AvmPlusScriptableObject::AvmPlusScriptableObject(avmplus::SamplerObjectType_ * sot=0x059d83c8) Line 49 + 0x26 bytes C++ NPSWF32.dll!avmplus::ScriptObject::ScriptObject(avmplus::VTable * _vtable=0x059d83c8, avmplus::ScriptObject * _delegate=0x059fdc08) Line 53 + 0x24 bytes C++ NPSWF32.dll!avmplus::PlayerScriptObject::PlayerScriptObject(avmplus::VTable * vtable=0x059d83c8, avmplus::ScriptObject * delegate=0x059fdc08) Line 19 + 0x1e bytes C++ NPSWF32.dll!avmplus::EventDispatcherObject::EventDispatcherObject(avmplus::VTable * ivtable=0x059d83c8, avmplus::ScriptObject * delegate=0x059fdc08) Line 434 + 0x1e bytes C++ NPSWF32.dll!avmplus::DisplayObject::DisplayObject(avmplus::VTable * ivtable=0x059d83c8, avmplus::ScriptObject * delegate=0x059fdc08) Line 67 + 0x2e bytes C++ NPSWF32.dll!avmplus::InteractiveObject::InteractiveObject(avmplus::VTable * ivtable=0x059d83c8, avmplus::ScriptObject * delegate=0x059fdc08) Line 61 + 0x1e bytes C++ NPSWF32.dll!avmplus::ContainerObject::ContainerObject(avmplus::VTable * ivtable=0x059d83c8, avmplus::ScriptObject * delegate=0x059fdc08) Line 54 + 0x1e bytes C++ NPSWF32.dll!avmplus::SpriteObject::SpriteObject(avmplus::VTable * ivtable=0x059d83c8, avmplus::ScriptObject * delegate=0x059fdc08) Line 54 + 0x27 bytes C++ NPSWF32.dll!avmplus::MovieClipObject::MovieClipObject(avmplus::VTable * ivtable=0x059d83c8, avmplus::ScriptObject * delegate=0x059fdc08) Line 43 + 0x1e bytes C++ NPSWF32.dll!avmplus::MovieClipClass::createInstance(avmplus::VTable * ivtable=0x059d83c8, avmplus::ScriptObject * prototype=0x059fdc08) Line 32 + 0x35 bytes C++ NPSWF32.dll!avmplus::ClassClosure::newInstance() Line 101 + 0x1f bytes C++ NPSWF32.dll!avmplus::ClassClosure::construct(int argc=0x00000000, int * argv=0x0009e174) Line 115 + 0x8 bytes C++ NPSWF32.dll!avmplus::InteractiveObjectClassBase::construct(int argc=0x00000000, int * argv=0x0009e174) Line 312 C++ NPSWF32.dll!avmplus::op_construct<avmplus::MethodEnv *>(avmplus::MethodEnv * env=0x0604d130, int ctor=0x05818829, int argc=0x00000000, int * atomv=0x0009e174) Line 149 + 0x26 bytes C++ 0608d6c1() NPSWF32.dll!avmplus::_AvmAssertMsg(int assertion=0x00000000, const char * message=0x00000000) Line 70 + 0x7 bytes C++ 80000101() From: Ruchi Lohani Sent: Monday, June 21, 2010 10:27 AM To: Lars Hansen Cc: Felix Klock II Subject: RE: RC Finalized object dtor Alloc Stack trace in Finalize() (from printAllocStackTrace()) : MMgc::GCHeap::AllocHook(gcheap.cpp:2004) - 0x59ca8d1 MMgc::GCAlloc::AllocFromQuickList(gcalloc.cpp:469) - 0x59e58c8 MMgc::GCAlloc::Alloc(gcalloc.cpp:418) - 0x59e3ea6 MMgc::GC::Alloc(gc.cpp:1377) - 0x59d60e4 MMgc::GC::AllocRCObject(gc-inlines.h:219) - 0x54317ac MMgc::RCObject::operator new(gcobject.h:205) - 0x5431777 avmplus::XMLClass::ToXML(xmlclass.cpp:187) - 0x5ab8785 avmplus::XMLClass::construct(xmlclass.cpp:125) - 0x5ab85a0 avmplus::op_construct<avmplus::MethodEnv *>(instr-inlines.h:149) - 0x5a9a8a5 NPSWF32.dll!MMgc::GCAlloc::Finalize() Line 843 + 0xc bytes C++ NPSWF32.dll!MMgc::GC::Finalize() Line 1531 C++ NPSWF32.dll!MMgc::GC::Sweep() Line 1666 C++ NPSWF32.dll!MMgc::GC::ForceSweepAtShutdown() Line 1598 C++ NPSWF32.dll!MMgc::GC::~GC() Line 1049 C++ NPSWF32.dll!MMgc::GC::`scalar deleting destructor'() + 0x16 bytes C++ NPSWF32.dll!MMgcDestructTaggedScalarChecked<MMgc::GC>(MMgc::GC * mem=0x06343030) Line 291 + 0x10 bytes C++ NPSWF32.dll!CorePlayer::DestroyPlayer() Line 1469 + 0xc bytes C++ NPSWF32.dll!CommonPlayer::DestroyPlayer() Line 375 C++ NPSWF32.dll!PlatformPlayer::DestroyPlayer() Line 737 C++ NPSWF32.dll!PlatformPlayer::~PlatformPlayer() Line 639 C++ NPSWF32.dll!PlatformPlayer::`scalar deleting destructor'() + 0x16 bytes C++ NPSWF32.dll!NPP_Destroy(_NPP * instance=0x01b01c4c, _NPSavedData * * __formal=0x0012fbc0) Line 873 + 0x34 bytes C++ From: Lars Hansen Sent: Monday, June 21, 2010 10:02 AM To: Ruchi Lohani Cc: Felix Klock II Subject: Re: RC Finalized object dtor That's worrisome. Do you have some call stacks? Once an object has been deleted by the ZCT reaper it should not be subject to garbage collection, the only thing I can think of is that the former runs while the latter is active, and that shouldn't happen either. --lars On Jun 21, 2010, at 6:59 PM, Ruchi Lohani wrote: Hi, While helping someone here debug a fuzzed swf crash issue which was in MMgc (GCAssert(*(intptr_t*)obj != 0); being hit in GCAlloc.cpp:838 and then crash while trying to call the dtor) When are the RCFinalizedObject dtor suppose to be called? What I am seeing is RCObject getting finalized in ZCT::ReapObject() and then later on again inGCAlloc::Finalize() where the crash happens as the vtable is 0. I tried getting the allocation trace where the assert was hit and the object reported was the same which got reaped before in ReapObject(). The player is getting aborted (corrupt swf) and the crash is while force sweep at shutdown. Thanks Ruchi
Reporter | ||
Comment 1•14 years ago
|
||
Here's a self-test for the above scenario; note in particular that we cannot in general directly expose the evil order of evaluation that is biting us here, so I had to use some placement new trickery to emulate it.
Attachment #453066 -
Flags: feedback?(lhansen)
Reporter | ||
Comment 2•14 years ago
|
||
Note: If some of d1's in the selftest are inadvertently kept alive via stale stack references, the verify checks will fail (for the wrong reason). :( (Worse yet, if the d2's are kept alive in the same manner, the selftest will succeed (for the wrong reason). So future work (assuming the strategy in this selftest is deemed acceptable) would be to adopt an approach that does not rely on all garbage being reclaimed precisely, but rather use a probabilistic approach. (Better still, design a common framework for many mmgc selftests to share.)
Reporter | ||
Updated•14 years ago
|
Attachment #453066 -
Flags: feedback?(rulohani)
Reporter | ||
Updated•14 years ago
|
Attachment #453066 -
Flags: feedback?(stejohns)
Comment 3•14 years ago
|
||
Comment on attachment 453066 [details]
attempt abort of GCFinalizedObject before fully initialized
All testcases should include a function named "deathString"
Attachment #453066 -
Flags: feedback?(stejohns) → feedback+
Assignee | ||
Comment 4•14 years ago
|
||
(In reply to comment #1) > Created an attachment (id=453066) [details] DWB(Stringp) m_s; should be DRCWB(Stringp) m_s;
Assignee | ||
Comment 5•14 years ago
|
||
This is going to prevent all such insane cases where the object remains in an uninitialized state after allocation. On Mac the behavior is actually different: the arguments to the ctor are evaluated first and the memory gets allocated only after that. Any feedback on adding more comments to the code? I think the bug contains much detailed information on the issue.
Attachment #453242 -
Flags: superreview?(lhansen)
Attachment #453242 -
Flags: review?(fklockii)
Attachment #453242 -
Flags: feedback?(stejohns)
Assignee | ||
Updated•14 years ago
|
Attachment #453066 -
Flags: feedback?(rulohani) → feedback+
Reporter | ||
Comment 6•14 years ago
|
||
(In reply to comment #1) > Created an attachment (id=453066) [details] > attempt abort of GCFinalizedObject before fully initialized > > Here's a self-test for the above scenario; note in particular that we cannot in > general directly expose the evil order of evaluation that is biting us here, so > I had to use some placement new trickery to emulate it. Hmm. On further inspection, I'm not quite sure how even the first verify condition was passing. I'll be uploading a new version of the selftest shortly, as well as an experimental patch to set the kFinalize bit from within the GCFinalizedObject constructor ...
Reporter | ||
Comment 7•14 years ago
|
||
Cleanup of selftest. 1. Incorporated feedback (good catch by Ruchi), 2. switched to statistical verification rather than incorrectly assuming gc will be 100% precise, 3. fixed logical verification errors (D::~D logic was decrementing rather than incrementing the counter..) and 4. got rid of the manual inlining of GCFinalizedObject::operator new (which meant that my later sketchy changes to GCFinalizedObject::operator new were masked in the test, bah) (Left Ruchi and Steven off feedback list, since they chimed in earlier, but really, feel free to look at it if you like...)
Attachment #453066 -
Attachment is obsolete: true
Attachment #453285 -
Flags: feedback?(lhansen)
Attachment #453066 -
Flags: feedback?(lhansen)
Reporter | ||
Comment 8•14 years ago
|
||
Here's a patch that takes the other approach for fixing the bug. It passes my selftest, but I have not tested it otherwise. Most importantly, I have not tested it for speed regression, which I think is what Lars is most concerned about w.r.t. this approach. (There might be a way to make it faster, or to speed up other paths assuming we can get rid of AllocPtrZeroFinalized entirely now...) (So we may want to adopt Ruchi's patch, at least until we discover a case where its detection fails...)
Attachment #453286 -
Flags: feedback?(rulohani)
Reporter | ||
Comment 9•14 years ago
|
||
Comment on attachment 453242 [details] [diff] [review] Call finalizer only if the object is in sane state 1. Nit: you should take out the assert. (I had the same instinct that you did, but Steven pointed out to me yesterday that our policy is: "assertions should only trigger for shouldn't-happen conditions -- we now know this can happen") 2. If everyone else is willing to go along with the vptr-inspection trick, then I am too. (I might rope Tommy into weighing in on the matter too, though.)
Reporter | ||
Comment 10•14 years ago
|
||
(In reply to comment #8) > Created an attachment (id=453286) [details] > set kFinalize bit in ctor rather than via operator new Oh, by the way, there is precedent for this, namely in RegExpObject. (Of course I doubt that is a hot path...)
Comment 11•14 years ago
|
||
Comment on attachment 453242 [details] [diff] [review] Call finalizer only if the object is in sane state (Holding my nose.) As Felix said, the GCAssert needs to be removed. This will be an adequate stopgap solution I expect, we might continue to search for something better.
Attachment #453242 -
Flags: superreview?(lhansen) → superreview+
Comment 12•14 years ago
|
||
Comment on attachment 453286 [details] [diff] [review] set kFinalize bit in ctor rather than via operator new This is probably correct (and better than what we currently have) but it is likely to make most allocation slower, unfortunately: SetFinalize dispatches on size to the appropriate underlying allocator mechanism.
Updated•14 years ago
|
Attachment #453285 -
Flags: feedback?(lhansen) → feedback+
Comment 13•14 years ago
|
||
Comment on attachment 453285 [details] [diff] [review] selftest abort of GCFinalizedObject before fully initialized You write: // (really, not dying is passing.) %%verify (D::finalized_count() > 90) If that's the case then a simple %%verify true would do. Why are you concerned about the finalization fraction anyway? f+ tentatively because I think the test tests what it should test, but there's stuff here I don't understand why is there.
Reporter | ||
Comment 14•14 years ago
|
||
(In reply to comment #13) > (From update of attachment 453285 [details] [diff] [review]) > You write: > > // (really, not dying is passing.) > %%verify (D::finalized_count() > 90) > > If that's the case then a simple > > %%verify true > > would do. > > Why are you concerned about the finalization fraction anyway? Well, really the point was to make sure that the finalizer is actually getting run. %%verify (D::finalized_count() > 0) would also do that job, I guess. But "%%verify true" would not catch the (important) bug of when finalizer invocation is turned into a no-op. Having said that, I think we should settle on our expectation for statistical tests of reclamation, and then use that percentage consistently. For that, I would not be satisfied with ">0%" as our standard across the board. I picked 90% out of a hat, but there was no basis for it.
Comment 15•14 years ago
|
||
Why / under what circumstances would the finalizer invocation be turned into a no-op?
Reporter | ||
Comment 16•14 years ago
|
||
(In reply to comment #15) > Why / under what circumstances would the finalizer invocation be turned into a > no-op? I said it was a bug. It was probably a mistake to call it an "important bug." One of my attempts to fix the bug removed the kFinalize setting from operator new, but screwed up setting kFinalize in the constructor. (I had not yet seen RegExpObject code at the time and was flailing; it was late.) Now, while I could (and do) chalk that up to my own stupidity, it seems to me that when one is fixing a bug like this, a mistake like that is actually likely to pop up, and if the self-test can catch it, why not include the check?
Comment 17•14 years ago
|
||
I absolutely agree that it would be good to check. But is this the test case that should check it?
Assignee | ||
Comment 18•14 years ago
|
||
Adding Tommy on review for the updated patch. Removed the assert and updated comments in code.
Attachment #453242 -
Attachment is obsolete: true
Attachment #453389 -
Flags: superreview?(lhansen)
Attachment #453389 -
Flags: review?(treilly)
Attachment #453242 -
Flags: review?(fklockii)
Attachment #453242 -
Flags: feedback?(stejohns)
Comment 19•14 years ago
|
||
Comment on attachment 453389 [details] [diff] [review] uninitialized finalized object crash fix The only negative thing I can think of is that we might mask a different problem with this if that we would really rather find out about. We have had problems before crashing here with a zero vtable (trying to finalize something twice for instance). Did we dismiss having the ctor sequence flip the finalize bit for some reason?
Attachment #453389 -
Flags: review?(treilly) → review-
Reporter | ||
Comment 20•14 years ago
|
||
(In reply to comment #19) > Did we dismiss having the ctor sequence flip the finalize bit for some reason? I think Lars addressed in in comment 12. I believe I know what he means about the newly introduced conditional branch. I do not yet know of a way to avoid it; e.g. to my knowledge there is not a way to overload constructors based on the size of the whole object being constructed.
Reporter | ||
Comment 21•14 years ago
|
||
(In reply to comment #17) > I absolutely agree that it would be good to check. But is this the test case > that should check it? (I chatted with Lars and now understand what he is getting at; I will refactor the test case code.)
Assignee | ||
Comment 22•14 years ago
|
||
Adding the null vptr check in finalization might reintroduce other problems. Btw, how is finalizing twice possible? We reset the finalize bit before finalizing so is there a chance we will again do finalization? Setting finalize bit in ctor also will cause allocation slower. How about modifying the way allocation is done (no args should throw) that is getting into this trouble? That will of course fix only this instance of problem and there might be several other places ready to behave in the same way.
Comment 23•14 years ago
|
||
(In reply to comment #22) > Btw, how is finalizing twice possible? Old bug, just an example
Reporter | ||
Comment 24•14 years ago
|
||
Refactored self-test as Lars suggested, got rid of cruft from when I was flailing on it, and added general improvements. (Time for me to stop playing with this though.) (Also, there's one selftest with bug id embedded in its filename. do we want to continue that pattern...? I'm inclined not to if a reasonable filename is available.)
Attachment #453285 -
Attachment is obsolete: true
Attachment #453732 -
Flags: superreview?(lhansen)
Attachment #453732 -
Flags: review?(treilly)
Attachment #453732 -
Flags: feedback?(rulohani)
Reporter | ||
Comment 25•14 years ago
|
||
(In reply to comment #22) > Adding the null vptr check in finalization might reintroduce other problems. > Btw, how is finalizing twice possible? We reset the finalize bit before > finalizing so is there a chance we will again do finalization? > Setting finalize bit in ctor also will cause allocation slower. Ruchi: in the above, it sounds like you are presenting independent arguments: one against null_vptr patch, and another against set-kFinalizer-during-ctor patch. (Am I misinterpreting?) (I could try to set aside time to gather concrete data on how much slower allocation gets when setting kFinalizer in ctor. The problem is that I'm likely only to test on my mac, but I suspect we should be worrying about all platforms, especially mobile, right?) > How about modifying the way allocation is done (no args should throw) that is > getting into this trouble? That will of course fix only this instance of > problem and there might be several other places ready to behave in the same > way. The problem is that the requirement "no args should throw" is too hard to verify unless we strengthen the constraint significantly; e.g. I jokingly suggested requiring SSA form when using mmgc's new to Lars yesterday. So it would be yet another mmgc requirement that went unchecked until worst possible moment.
Comment 26•14 years ago
|
||
Comment on attachment 453389 [details] [diff] [review] uninitialized finalized object crash fix We've lived with the assert for a while without it bugging anyone; as a stopgap measure this is likely to be fine.
Attachment #453389 -
Flags: superreview?(lhansen) → superreview+
Updated•14 years ago
|
Attachment #453732 -
Flags: superreview?(lhansen) → superreview+
Comment 27•14 years ago
|
||
(In reply to comment #24) > (Also, there's one selftest with bug id embedded in its filename. do we want > to continue that pattern...? I'm inclined not to if a reasonable filename is > available.) For regressions I'd be much more comfortable if they were in individual files named by the bug number of the regression, like that one file. Currently we're not doing that uniformly, there are regression tests eg in mmgc_basics whose test names are the bug numbers. That more or less works the same way but tends to clutter up the tests. Over time we'll presumably have many, many regression tests, coming up with meaningful names will become increasingly difficult, and finding the test case given the bug will also become harder. Better to just bite the bullet and clean it up imo.
Assignee: nobody → rulohani
Status: NEW → ASSIGNED
Priority: -- → P1
Target Milestone: --- → flash10.1.x-Crush
Comment 28•14 years ago
|
||
does this repro in fp9?
Comment 29•14 years ago
|
||
(In reply to comment #28) > does this repro in fp9? It ought to repro - allocation happens the same way in FP9, with the 'new' operator setting the finalization flag and the constructor setting up the vtable, obviously.
Comment 30•14 years ago
|
||
Has this landed in p4? Is there a watson bug number?
Comment 31•14 years ago
|
||
Comment on attachment 453389 [details] [diff] [review] uninitialized finalized object crash fix +1 for crush, we need to fix the crash this is a good safe fix. But I'm still worried going forward that we could miss some new bug that also manifests as a zero'd vtable
Attachment #453389 -
Flags: review- → review+
Assignee | ||
Comment 32•14 years ago
|
||
(In reply to comment #30) > Has this landed in p4? Is there a watson bug number? Watson bug number: 2638752 The fix has landed in crush with other changes related to this Watson bug. Change list: 686766 (In reply to comment #31) > (From update of attachment 453389 [details] [diff] [review]) > +1 for crush, we need to fix the crash this is a good safe fix. But I'm > still worried going forward that we could miss some new bug that also manifests > as a zero'd vtable Probably we could have left the assert in place? At least could help in those zero'd vtable rare cases. But it will affect debugging on the client side. QE has added a test case to the automated test suite and the assert will interfere in that in debug builds.
Updated•14 years ago
|
Whiteboard: WE:2638752
Comment 33•14 years ago
|
||
There is a problem here that's more complicated than we may have realized, and it might warrant a separate bug because the underlying problem is in some sense a different kind of problem. Right now we're crashing because the 'finalize' flag is set before the vtable is installed; if the constructor is never run then we have an object on the heap that will have a NULL vtable pointer and the destructor call will cause a crash. The proposed fix is to install the 'finalize' flag in the constructor, presumably in the GCFinalizedObject constructor. Doing that would be more correct but it would not actually be fully correct. Consider an object inheritance chain: GCFinalizedObject RCObject AvmPlusScriptableObject ScriptObject MyGlueObject At any point in the construction chain, the vtable that's installed in the object is a vtable that is appropriate for the object, eg, ScriptObject's vtable does not have any pointers to MyGlueObject's virtual functions, only to ScriptObject's functions. Thus if any constructor in this chain aborts the construction process by throwing an exception, we're left with an object on the heap where the vtable points to a destructor that starts with some intermediate object, not the most derived object. (At least this is my understanding - and I believe I've observed that happening.) Thus setting the kFinalizedObject flag in the GCFinalizedObject constructor does not guard against invoking the wrong destructor. On the other hand, setting it in the most derived class's constructor doesn't solve the problem either because it means some objects that need a destructor may not be destroyed (if the construction process throws an exception). The underlying problem is that constructors can throw exceptions at all, ie, that construction is not atomic and guaranteed to succeed, or if you like, that it is possible to observe intermediate, possibly inconsistent, states of an object outside that object's constructor(s). That may be acceptable if you're programming in C++, but what we've done here by choosing to use the C++ vtable mechanism to support garbage collection is to expose this problem to the ActionScript programmer, and to Flash Player developers for that matter. Maybe I'm being overly dramatic, since any careless (partly-completed) update to an object may leave it in an inconsistent state, but it does seem wrong that it's possible to construct objects that are nonsensical from the GC's point of view.
Assignee | ||
Comment 34•14 years ago
|
||
Yes, the object partial initialization can happen if a constructor in the inheritance chain throws. Its also correct that the object's vptr will point to the vtable of the class whose ctor throws. So if the kFinalizedObject flag is set in GCFinalizedObject ctor and ScriptObject ctor in the above mentioned chain throws, the object's vptr will be pointing to the ScriptObject's vtable. While calling dtor, all the dtors up in the chain will be called including ~ScriptObject(). I am not sure whether this is the wrong invocation of dtors you mentioned in the above comment. We dont want the dtor of MyGlueObject to be called as it was not initialized (ctor did not get called). What do we expect the behavior to be in case some intermediate ctor throws?
Comment 35•14 years ago
|
||
The remaining issue raised in comment #33 isn't making crush. Can we mark this crush targeted issue as resolved/fixed and log a new one for the remaining work?
Reporter | ||
Comment 36•14 years ago
|
||
(In reply to comment #35) > The remaining issue raised in comment #33 isn't making crush. Can we mark this > crush targeted issue as resolved/fixed and log a new one for the remaining > work? Opened separate ticket for issues from comment #33 in bug 581016
Comment 37•14 years ago
|
||
Comment on attachment 453389 [details] [diff] [review] uninitialized finalized object crash fix pushed: http://hg.mozilla.org/tamarin-redux/rev/a7d91aa8cb5b
Assignee | ||
Comment 38•14 years ago
|
||
The code patch has been pushed. The selftest is pending review from Tommy. Need to push the selftest before this bug should be marked fixed/resolved.
Updated•14 years ago
|
Attachment #453732 -
Flags: review?(treilly) → review+
Reporter | ||
Comment 39•14 years ago
|
||
Comment on attachment 453732 [details] [diff] [review] selftest abort of GCFinalizedObject before fully initialized Shall we push this then, Tommy? (and by "we" I really mean "you" :)
Assignee | ||
Comment 41•14 years ago
|
||
Both patch and selftest have been pushed. Marking it resolved.
Status: ASSIGNED → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
Comment 42•14 years ago
|
||
Regarding comment #29, yes, it does crash in fp9 crush. It was not originally targeted to fp9 in watson, where the bug originated.
Assignee | ||
Comment 43•14 years ago
|
||
Comment on attachment 453732 [details] [diff] [review] selftest abort of GCFinalizedObject before fully initialized Marking f+. Test has been reviewed and pushed.
Attachment #453732 -
Flags: feedback?(rulohani) → feedback+
Assignee | ||
Comment 44•14 years ago
|
||
Comment on attachment 453286 [details] [diff] [review] set kFinalize bit in ctor rather than via operator new Marking f+. We had discussed about it here and a separate bug was opened: 581016.
Attachment #453286 -
Flags: feedback?(rulohani) → feedback+
You need to log in
before you can comment on or make changes to this bug.
Description
•