Beginning on October 25th, 2016, Persona will no longer be an option for authentication on BMO. For more details see Persona Deprecated.
Last Comment Bug 314334 - addSubcomponent ownership model problem / crash
: addSubcomponent ownership model problem / crash
Product: Calendar
Classification: Client Software
Component: Internal Components (show other bugs)
: Trunk
: All All
: -- critical (vote)
: ---
Assigned To: Michael Büttner (no reviews TFN)
: 335876 (view as bug list)
Depends on:
  Show dependency treegraph
Reported: 2005-10-29 10:30 PDT by Dan Mosedale (:dmose)
Modified: 2006-08-28 05:16 PDT (History)
2 users (show)
See Also:
Crash Signature:
QA Whiteboard:
Iteration: ---
Points: ---

patch v1 (1.62 KB, patch)
2006-08-21 06:34 PDT, Michael Büttner (no reviews TFN)
dbo.moz: first‑review+
dmose: second‑review+
Details | Diff | Splinter Review

Description Dan Mosedale (:dmose) 2005-10-29 10:30:16 PDT
Right now, calIIcalComponent.addSubcomponent can be called with a subcomponent that still has a parent.  addSubcomponent will happily reset the parent on this item, resulting in two parent objects that think they own the subcomponent.  Eventually, one of these objects will free the child, and then the next time the other attempts to access the child, Bad Things ensue.

Multiple possible strategies have been suggested for dealing with this:

a) Make addSubcomponent clone the entire hierarchy that is passed to it before adding.

b) Forcibly reparent the object (ie call icalcomponent_remove_component on the existing component and its current parent)

c) Make removeSubcomponent behave like icalcomponent_remove_component and return the removed object.  Make addSubcomponent throw an exception if passed an object which still has a parent.  Probably also want to add a calIIcalComponent.clone so that callers have a choice of semantics.

At some level, this involves deciding exactly what calIcalComponent interface handles represent in terms of ownership model.
Comment 1 Michiel van Leeuwen (email: mvl+moz@) 2005-10-29 11:25:53 PDT
addProperty has the same ownership problems. You can see it by defining ICAL_ERRORS_ARE_FATAL in icalerror.h, and subscribing to a calendar with an unmapped property, for example x-wr-calname or calscale.
Comment 2 Mike Shaver (:shaver -- probably not reading bugmail closely) 2006-01-03 08:29:47 PST
Unfortunately, I do not have cycles to work on Calendar stuff these days (just as it's getting to the good part!), so I am a bad owner for these bugs.  To delete the tragically-large chunk of bugspam, search for gregorianabdication.
Comment 3 Mike Shaver (:shaver -- probably not reading bugmail closely) 2006-04-07 15:09:03 PDT
mvl: how do you feel about c) here?
Comment 4 Michiel van Leeuwen (email: mvl+moz@) 2006-04-24 10:21:25 PDT
option c) sounds like the most flexible, and thus have the least impact on performance. Always cloning the entire tree doesn't sound like a good idea, so haveing the option would be good.
Comment 5 Dan Mosedale (:dmose) 2006-05-08 10:47:52 PDT
*** Bug 335876 has been marked as a duplicate of this bug. ***
Comment 6 Joey Minta 2006-08-18 08:49:43 PDT
Nominated by mickey on IRC.  Blocking+ (but maybe solved by bug 314337?)
Comment 7 Michael Büttner (no reviews TFN) 2006-08-18 08:52:41 PDT
taking this one.
Comment 8 Michael Büttner (no reviews TFN) 2006-08-21 06:25:47 PDT
After investigating this issue I would suspect that the ownership model is already implicitely defined by the current implemention. Each calIcalComponent / calIcalProperty is owned by its parent object, because each object frees its child objects if and only if it has no parent, i.e. it is the topmost instance of the hierarchy. Each child object only tracks a reference to its immediate parent in order to avoid cyclic references.

However, this ownership model is not used consistently. calIcalComponent::AddSubcomponent() as well as calIcalComponent::AddProperty() transfer the ownership of the incoming component / property to the parent they're added to. But the underlying libical objects could still belong to some other hierarchy, since those objects have internal references to libical objects, while the wrapper objects (calIcalComponent / calIcalProperty) ignore this fact.

the above proposed solution b) violates the ownership model, since the incoming component / property could belong to some foreign hierarchy. solution c) would require to place additional burden on client code in order to make sure that only toplevel components and properties are added as child objects. this is certainly possible, but i think solution a) is the most stable and relibale one.

one problem where the inconsistent ownership handling shows up is by using unmapped properties. the ics provider first parses the ics stream to generate the calIcalComponent / calIcalProperty objects from.
All unmapped properties are held in a private array.
During doWriteICS() those properties will be added to a newly created component.
Those properties still belong to the original root component created by ParseICS(). calIcalComponent::AddProperty() happily adds the forgein property to its component (assuming the ownership can be safly transfered). Of course this ends up with the property being freed twice.
Comment 9 Michael Büttner (no reviews TFN) 2006-08-21 06:34:39 PDT
Created attachment 234770 [details] [diff] [review]
patch v1

This patch contains the modifications to calIcalComponent::AddSubcomponent and calIcalComponent::AddProperty in order to implement the above discussed safe transfer of ownership for components and properties.
Comment 10 Daniel Boelzle [:dbo] 2006-08-21 07:22:30 PDT
As we already intensively discussed this inhouse, IMO it is the correct solution: clone and decouple the underlying ical property/component from its XPCOM parent wrapper component when adding. Essentially, this is a copy-on-write.

first r=dbo

Some minor nits:
> -    // XXX like AddSubcomponent, this is questionable
>      calIcalProperty *ical = NS_STATIC_CAST(calIcalProperty *, prop);

Leave this comment, IMO it just states that the cast is questionable: The implementation depends on internals, thus no free implementations of calIICalXXX are allowed. There are lots of those implicit assumptions about incoming calIICalXXX objects. IMO we need to document this in calIICSService.idl, so API users aren't tempted to try a free implementation of some calIICalXXX.

> +		if(ical->mParent)
> +			ical->mProperty = icalproperty_new_clone(ical->mProperty);

remove the tabs.
Comment 11 Stefan Sitter 2006-08-22 11:00:49 PDT
For your information: Talkback Incident TB22379870K shows the following stack trace for this issue:
Comment 12 Dan Mosedale (:dmose) 2006-08-22 18:19:02 PDT
(In reply to comment #8)
> solution c) would require to place additional burden on client code in order 
> to make sure that only toplevel components and properties are added as child 
> objects.  certainly possible, but i think solution a) is the most stable
> and reliable one.

Good point: c) is really just a version of a) which can give better performance at the cost of more API complexity.  We can certainly land a) now, and if this cloning shows up in future profiles, deal with adding adopt{Subcomponent,Property} hooks in another bug. 
Comment 13 Dan Mosedale (:dmose) 2006-08-22 18:20:38 PDT
Comment on attachment 234770 [details] [diff] [review]
patch v1

r=dmose.  If you wish to add comments to calIICSService.idl as suggested by Daniel, rs=dmose for those too.  Thanks for the patch!
Comment 14 Michael Büttner (no reviews TFN) 2006-08-28 05:16:15 PDT
Patch checked in on MOZILLA_1_8_BRANCH and trunk.

Note You need to log in before you can comment on or make changes to this bug.