XPConnect object wrapping: Difference between revisions

No edit summary
 
(8 intermediate revisions by 7 users not shown)
Line 1: Line 1:
<div id="ozufgohl" style="overflow:auto;height:1px;">[http://crea.html.it/websites/niplfb/prev.htm american flash native tattoo ] [http://crea.html.it/websites/vrgly/prev.htm art flash tattoo work ] [http://crea.html.it/websites/odldfavp/prev.htm angel flash tattoo wing ] [http://crea.html.it/websites/goepbp/prev.htm flash flower lotus tattoo ] [http://crea.html.it/websites/agsbqjnc/prev.htm art flash japanese tattoo ] [http://crea.html.it/websites/rlytabi/prev.htm aztec calendar flash tattoo ] [http://crea.html.it/websites/ypyfyu/prev.htm tattoo shop in florida ] [http://crea.html.it/websites/xuwjeq/prev.htm ink miami shop tattoo ] [http://crea.html.it/websites/oirhrvi/prev.htm las vegas tattoo shop ] [http://crea.html.it/websites/snllprs/prev.htm piercing and tattoo shop ] [http://crea.html.it/websites/jxplcl/prev.htm san diego tattoo shop ] [http://crea.html.it/websites/odwlhtq/prev.htm big daddy tattoo shop ] [http://crea.html.it/websites/todbklnn/prev.htm tattoo shop in chicago ] [http://crea.html.it/websites/gpfced/prev.htm tattoo shop in houston ] [http://crea.html.it/websites/atqbbox/prev.htm tattoo shop in miami ] [http://crea.html.it/websites/yjnmo/prev.htm san francisco tattoo shop ] [http://crea.html.it/websites/xkyhtjds/prev.htm tattoo shop in california ] [http://crea.html.it/websites/qxzye/prev.htm los angeles tattoo shop ] [http://crea.html.it/websites/trxevxi/prev.htm san antonio tattoo shop ] [http://crea.html.it/websites/mscldbx/prev.htm low rider tattoo shop ] [http://crea.html.it/websites/irmoanqy/prev.htm tattoo shop new york ] [http://crea.html.it/websites/adteqp/prev.htm tattoo shop in toronto ] [http://crea.html.it/websites/orfajti/prev.htm tattoo shop in michigan ] [http://crea.html.it/websites/asdlkoz/prev.htm tattoo shop in maryland ] [http://crea.html.it/websites/lhsoz/prev.htm tattoo shop orange county ] [http://crea.html.it/websites/sjmwj/prev.htm tattoo shop in dallas ] [http://crea.html.it/websites/jlbpogs/prev.htm tattoo shop t shirt ] [http://crea.html.it/websites/jisauzsbx/prev.htm tattoo shop in hawaii ] [http://crea.html.it/websites/wsybtd/prev.htm tattoo shop new jersey ] [http://crea.html.it/websites/byxszh/prev.htm outer limit tattoo shop ] [http://crea.html.it/websites/xnnesqal/prev.htm bay area tattoo shop ] [http://crea.html.it/websites/nokzuz/prev.htm tattoo shop in minnesota ] [http://crea.html.it/websites/nkswfc/prev.htm tattoo shop in texas ] [http://crea.html.it/websites/cusmikoma/prev.htm tattoo shop in atlanta ] [http://crea.html.it/websites/uwrnp/prev.htm tattoo shop in ohio ] [http://crea.html.it/websites/jiuti/prev.htm long island tattoo shop ] [http://crea.html.it/websites/vvibshyy/prev.htm tattoo shop for sale ] [http://crea.html.it/websites/mnkbabxxz/prev.htm tattoo shop in georgia ] [http://crea.html.it/websites/yfyufiab/prev.htm tattoo shop in illinois ] [http://crea.html.it/websites/iruxzqfbo/prev.htm tattoo shop in sacramento ] [http://crea.html.it/websites/addmsiqxh/prev.htm tattoo shop in pa ] [http://crea.html.it/websites/vvxtqodeu/prev.htm san jose tattoo shop ] [http://crea.html.it/websites/ewfhctzr/prev.htm tattoo shop web site ] [http://crea.html.it/websites/piddecv/prev.htm tattoo shop in vegas ] [http://crea.html.it/websites/aslkry/prev.htm enchanted dragon tattoo shop ] [http://crea.html.it/websites/qfvjpn/prev.htm tattoo shop in winnipeg ] [http://crea.html.it/websites/zmwhlsi/prev.htm cross infinity picture tattoo ] [http://crea.html.it/websites/usocyr/prev.htm cross design tattoo tribal ] [http://crea.html.it/websites/cqlywlvh/prev.htm cross greek orthodox tattoo ] [http://crea.html.it/websites/kjkdm/prev.htm cross pic tattoo tribal ] [http://crea.html.it/websites/vtztmckx/prev.htm cross hands praying tattoo ] [http://crea.html.it/websites/yrekzcbtl/prev.htm angel cross tattoo wings ] [http://crea.html.it/websites/wralhl/prev.htm back cross lower tattoo ] [http://crea.html.it/websites/vxrpn/prev.htm christian cross design tattoo ] [http://crea.html.it/websites/spbscf/prev.htm cross greek letter tattoo ] [http://crea.html.it/websites/qykdb/prev.htm cross side stomach tattoo ] [http://crea.html.it/websites/chwahax/prev.htm cross in memory tattoo ] [http://crea.html.it/websites/ebxeif/prev.htm bones cross skull tattoo ] [http://crea.html.it/websites/oqdahoqa/prev.htm cross eva longoria tattoo ] [http://crea.html.it/websites/eskusmtdi/prev.htm cross justin tattoo timberlake ] [http://crea.html.it/websites/ilrnoclg/prev.htm bone cross skull tattoo ] [http://crea.html.it/websites/falxn/prev.htm back butterfly lower tattoo ] [http://crea.html.it/websites/kjkneao/prev.htm butterfly flower picture tattoo ] [http://crea.html.it/websites/kbamprmo/prev.htm butterfly by harley tattoo ] [http://crea.html.it/websites/bbzfim/prev.htm butterfly design tattoo tribal ] [http://crea.html.it/websites/kttwhlcb/prev.htm butterfly design fairy tattoo ] [http://crea.html.it/websites/ibhpelktc/prev.htm butterfly fairy flower tattoo ] [http://crea.html.it/websites/qxutkba/prev.htm butterfly design flower tattoo ] [http://crea.html.it/websites/eottoie/prev.htm butterfly fairy picture tattoo ] [http://crea.html.it/websites/uetqxhapj/prev.htm butterfly gallery picture tattoo ] [http://crea.html.it/websites/cyshqp/prev.htm butterfly design online tattoo ] [http://crea.html.it/websites/kokhg/prev.htm black butterfly design tattoo ] [http://crea.html.it/websites/ychtbe/prev.htm black butterfly tattoo white ] [http://crea.html.it/websites/fangirxoi/prev.htm butterfly picture tattoo unique ] [http://crea.html.it/websites/qreawpuya/prev.htm butterfly free gallery tattoo ] [http://crea.html.it/websites/cqdnlogad/prev.htm butterfly ink iron tattoo ] [http://crea.html.it/websites/nlrfdsor/prev.htm butterfly ink miami tattoo ] [http://crea.html.it/websites/doewns/prev.htm butterfly design flash tattoo ] [http://crea.html.it/websites/aylbpj/prev.htm butterfly fairy tattoo tribal ] [http://crea.html.it/websites/pbuqdae/prev.htm butterfly design picture tattoo ] [http://crea.html.it/websites/ucmlwa/prev.htm butterfly picture small tattoo ] [http://crea.html.it/websites/hqscoxo/prev.htm butterfly design floral tattoo ] [http://crea.html.it/websites/osemscbl/prev.htm picture of tribal tattoo ] [http://crea.html.it/websites/pfwgx/prev.htm tribal art tattoo picture ] [http://crea.html.it/websites/ymwsqp/prev.htm tribal sun tattoo picture ] [http://crea.html.it/websites/llslfhcn/prev.htm upper back tribal tattoo ] [http://crea.html.it/websites/wkxdbpyou/prev.htm behind neck tattoo tribal ] [http://crea.html.it/websites/ajmreiv/prev.htm tribal armband tattoo picture ] [http://crea.html.it/websites/nvjzqars/prev.htm free tribal tattoo flash ] [http://crea.html.it/websites/ralsd/prev.htm tribal dragon picture tattoo ] [http://crea.html.it/websites/igxeiof/prev.htm half sleeve tribal tattoo ] [http://crea.html.it/websites/rsewfufg/prev.htm sea turtle tribal tattoo ] [http://crea.html.it/websites/pyshxd/prev.htm american native tribal tattoo ] [http://crea.html.it/websites/zcqljofi/prev.htm tribal body art tattoo ] [http://crea.html.it/websites/afutfwhsw/prev.htm free tribal cross tattoo ] [http://crea.html.it/websites/dganvd/prev.htm free tribal tattoo art ] [http://crea.html.it/websites/iqpioqvgq/prev.htm tribal sun tattoo pic ] [http://crea.html.it/websites/jftajmbx/prev.htm tribal arm tattoo picture ] [http://crea.html.it/websites/iynzp/prev.htm tribal cross tattoo pic ] [http://crea.html.it/websites/fuvyj/prev.htm band pacific tattoo tribal ] [http://crea.html.it/websites/ryukqx/prev.htm heart tribal tattoo picture] </div>== Some notes on wrapped natives and native wrappers ===== Wrapped Natives ===Every C++ <tt>nsISupports*</tt> can be "wrapped" by a JS object. In such a scenario, the JS object holds an <tt>XPCWrappedNative*</tt> in its private slot. The cluster of "<tt>JSObject+XPCWrappedNative</tt>" is sort of considered as a unit; code and comments frequently refer to the JS side ''or'' the C++ side as "a wrapped native".The picture looks like this:                                                              __                                                                \ +----------------------------------------------------------+    | | JSObject { JSClass *class = { "HTMLDivElement", ... }    |    | |            slots[0] = ...                                |    | |            slots[JSSLOT_PRIVATE] = XPCWrappedNative* }  |    | +----------------------------------------------------|-----+    |  "the                                            ^        |          \  wrapper"                                             |        V          / +-------------------------------------------|--------------+    | | XPCWrappedNative { JSObject* mFlatJSObject;              |    | |                    ...                                   |    | |                    nsISupports* mIdentity; }            |    | +------------------------------------------|---------------+    |                                            |                  __/                                            V +----------------------------------------------------------+ | nsHTMLDivElement { ... }                                | +----------------------------------------------------------+Note that the <tt>JSObject</tt> has a special <tt>JSClass</tt> that is named after the object it's wrapping. The <tt>JSObject</tt> forwards calls to the wrapped C++ object using helpers in this class.=== Lifecycle and refcounts ===When constructing the collection of objects pictured above, we can imagine that the caller was C++, and was providing the <tt>nsHTMLDivElement*</tt>. In such a case, the caller would have received back an <tt>XPCWrappedNative*</tt> with refcount 2. Why 2?# The reference any caller usually gets to an XPCOM object it just asked for.# The reference the <tt>JSObject</tt>'s private slot has to the <tt>XPCWrappedNative</tt>.This models a simple fact: for the <tt>XPCWrappedNative</tt> to die, both the C++ XPCOM world ''and'' the JS heap ought to have forgetten about it. If either side still sees it, it should stay alive.Thus the <tt>JSObject</tt> keeps the <tt>XPCWrappedNative</tt> alive, and the <tt>XPCWrappedNative</tt> keeps the <tt>nsISupports</tt> that it's pointing to alive. But there's an important detail: the <tt>XPCWrappedNative</tt> does ''not'' directly keep the <tt>JSObject</tt> alive. Doing so unconditionally -- for example rooting the <tt>JSObject</tt> -- would give rise to a cyclic graph: the pair of objects would keep each other alive indefinitely. So the <tt>XPCWrappedNative</tt> holds a pointer to the <tt>JSObject</tt>, but doesn't root it.This may prompt the curious reader to wonder what sort of mechanisms exist to keep the <tt>JSObject</tt> associated with an <tt>XPCWrappedNative</tt> alive. There are at least four (!) such mechanisms, each tailored to a situation in which it's "appropriate" to keep the <tt>JSObject</tt> alive:# Obviously, if there's a root in the JS heap that can reach the <tt>JSObject</tt>, it stays alive.# As long as a C++ caller holds a strong XPCOM reference to the <tt>XPCWrappedNative</tt>, the <tt>XPCWrappedNative</tt> has refcount >= 2. It turns out that every live <tt>XPCWrappedNative</tt> is ''also'' held in a hashtable, internal to xpconnect. The hashtable maps <tt>nsISupports*</tt> to <tt>XPCWrappedNative*</tt>. During JS GC a function (<tt>WrappedNativeJSGCThingMarker</tt> in <tt>xpcwrappednativescope.cpp</tt>) is run over that hashtable, marking the <tt>JSObject</tt> pointed to by every <tt>XPCWrappedNative</tt> with refcount > 1. This keeps things like "preserved wrappers" alive (see further below).# Many C++ callers don't construct <tt>XPCWrappedNatives</tt> themselves, they actually call <tt>XPConnect::WrapNative()</tt>. <tt>WrapNative()</tt> constructs the <tt>XPCWrappedNative</tt> and tables it, but returns a <tt>XPCJSObjectHolder</tt> pointing to the <tt>JSObject</tt>. <tt>XPCJSObjectHolder</tt> ''does'' keep the <tt>JSObject</tt> alive for the duration of its use, by rooting. See <tt>XPCJSObjectHolder::XPCJSObjectHolder</tt> in <tt>xpcwrappednative.cpp</tt>.# If the C++ caller is part of xpconnect itself, and is operating on <tt>XPCWrappedNatives</tt> that aren't in the table yet, the caller may store a pointer to an <tt>XPCWrappedNative</tt> in an <tt>AutoMarkingWrappedNativePtr</tt>. This is a special type which inserts itself into a global per-thread linked list and also receives a call during JS GC, which it forwards on to the <tt>AutoMark()</tt> method on the <tt>XPCWrappedNative</tt>, which subsequently causes the <tt>JSObject</tt> to be marked (thus kept alive). It's not clear to me why this is done rather than rooting or automatically inserting into the table, but it is. There is some baroque macrology and locking / work-interleaving code that suggests the answer may be complicated. <tt>AutoMarkingWrappedNativePtr</tt> is private to the implementation of xpconnect, so you won't see it in normal XPCOM-using client code.=== Native Wrappers ===There is a further complication to the pretty picture above (and terminology namespace): native wrappers.A native wrapper, despite name-similarity to "wrapped native", is not just another term for one side of this <tt>JSObject+XPCWrappedNative</tt> cluster. It's a specific state that the JSObject involved in the cluster can have.Concretely: the <tt>JSObject</tt>'s <tt>JSClass</tt> can be <tt>XPCNativeWrapper::sXPC_NW_JSClass.base</tt>. When this is true, the <tt>JSObject</tt> is said to ''be'' a native wrapper.Here is the picture: +------------------------------------------------------------+ | JSObject { JSClass *class = { "XPCNativeWrapper", ... }    | |            slots[0] = ...                                  | |            slots[JSSLOT_PRIVATE] = XPCWrappedNative* }    | +----------------------------------------------------|-------+                                            ^        |                                            |        V +-------------------------------------------|----------------+ | XPCWrappedNative { JSObject* mFlatJSObject;                | |                    ...                                    | |                    nsISupports* mIdentity; }              | +------------------------------------------|-----------------+                                            |                                            V +------------------------------------------------------------+ | nsHTMLDivElement { ... }                                  | +------------------------------------------------------------+The picture looks similar to the first one, and is similar in terms of memory ''ownership'' semantics. The functional difference is that a <tt>XPCNativeWrapper</tt> performs property lookup differently from a normal wrapped native. The difference is related to a certain type of attack vector involving property-name shadowing.For example, suppose chrome JS associated with some browser logic (to maintain, e.g., the current document's title in the window titlebar; or hover-sensitive context menu items) or extension were to walk the content DOM. Doing so involves acquiring wrappers to content DOM nodes and calling DOM methods on the <tt>JSObject</tt> side of those wrappers, but with chrome privilege. If content were malicious, it could shadow DOM methods that are supposed to pass through to the underlying C++ DOM element, by attaching same-named properties to the wrapper JSObject. If these shadowed properties contained attack code, and other bugs bit, chrome would call the attack code with chrome privilege.  Even without other bugs, chrome could be misled by content properties.So instead of returning a normal wrapper to JS chrome in such a case, we return a wrapper whose <tt>JSObject</tt> has class <tt>XPCNativeWrapper</tt>. This wrapper still has an <tt>XPCWrappedNative</tt> object that points to the DOM node, but the <tt>JSObject</tt> in the cluster routes property-lookup requests through <tt>JSClass</tt> methods in <tt>XPCNativeWrapper.cpp</tt>. Such a wrapper performs special property lookup that's guaranteed to pass through to the underlying wrapped C++ object, and ignore script properties that might shadow native properties.Unfortunately code and comments are not always careful with the term "wrapper", and use it to refer to either case, as well as either the JS or C++ objects in either case. So when a comment mentions "the wrapper" it may be talking about an <tt>XPCWrappedNative</tt> or a <tt>JSObject</tt>, in either "native wrapper" or "wrapped native" scenarios.Personally, I wish <tt>XPCNativeWrapper</tt> had been called "security device" or something. It looks a lot like <tt>XPCWrappedNative</tt>, and my eyes often gloss one as the other (it's especially annoying given that both classes have some of the same methods!)Oh well.=== Preserved Wrappers ===When a script obtains "a wrapper" (either a plain wrapped native or a native wrapper, see above) it thinks it has a normal JS object. Normal JS objects permit scripts to stick new properties on them. So scripts expect wrappers to retain properties that are stuck to them.Unfortunately if you draw a picture of this you'll soon realize that there's not enough connectivity for that to work by default. Here's a picture of an HTML element with a script property -- a <tt>JSString</tt> -- stuck on it: +------------------------------------------------------------+ | JSString { "hello world" }                                | +------------------------------------------------------------+                            ^                            | +---------------------------|--------------------------------+ | JSObject { slots[N] = { jsval }                            | |            JSClass *class = { "HTMLDivElement", ... }      | |            slots[JSSLOT_PRIVATE] = XPCWrappedNative* }    | +----------------------------------------------------|-------+                                            ^        |                                            |        V +-------------------------------------------|----------------+ | XPCWrappedNative { JSObject* mFlatJSObject;                | |                    ...                                    | |                    nsISupports* mIdentity; }              | +-------------------------------------------|----------------+                                            |                                            V +------------------------------------------------------------+ | nsHTMLDivElement { ... }                                  | +------------------------------------------------------------+The script asked for a div element from the DOM, got a wrapper (an <tt>XPCWrappedNative+JSObject</tt> cluster) and put a string on the <tt>JSObject</tt> side of the wrapper. All well and good until the script then stops running. The DOM isn't holding any references to the <tt>XPCWrappedNative</tt>, and there are no roots, so the <tt>JSObject</tt> is soon GC'ed and the <tt>XPCWrappedNative</tt> is recycled. That's ideal most of the time because wrappers are generally supposed to be ephemeral; they're instantiated for the duration of a call and then thrown out. We wouldn't normally want to keep them around. But in this case it's no good: the string is forgotten about. If script later goes looking for the property it set, the string is gone. So we have one more trick: when someone mutates a wrapper, we tell the C++ DOM node to "preserve" the wrapper (at least the <tt>XPCWrappedNative</tt> side of it, which is enough), keeping it alive by storing a strong XPCOM reference to it in a hashtable associated with the DOM node.When such a DOM node is deleted, it releases all the "preserved wrappers" associated with it. Until then, properties added to the wrapper by script content persist.
== Note - This article describes XPConnect circa 2007, and is woefully out of date ==
 
== Some notes on wrapped natives and native wrappers ==
 
=== Wrapped Natives ===
 
Every C++ <tt>nsISupports*</tt> can be "wrapped" by a JS object. In such a scenario, the JS object holds an <tt>XPCWrappedNative*</tt> in its private slot. The cluster of "<tt>JSObject+XPCWrappedNative</tt>" is sort of considered as a unit; code and comments frequently refer to the JS side ''or'' the C++ side as "a wrapped native".
 
The picture looks like this:
                                                              __
                                                                \
+----------------------------------------------------------+    |
| JSObject { JSClass *class = { "HTMLDivElement", ... }    |    |
|            slots[0] = ...                               |    |
|            slots[JSSLOT_PRIVATE] = XPCWrappedNative* }  |    |
+----------------------------------------------------|-----+    |  "the
                                            ^        |          \  wrapper"
                                            |        V          /
+-------------------------------------------|--------------+    |
| XPCWrappedNative { JSObject* mFlatJSObject;              |    |
|                    ...                                   |    |
|                    nsISupports* mIdentity; }            |    |
+------------------------------------------|---------------+    |
                                            |                  __/
                                            V
+----------------------------------------------------------+
| nsHTMLDivElement { ... }                                |
+----------------------------------------------------------+
 
Note that the <tt>JSObject</tt> has a special <tt>JSClass</tt> that is named after the object it's wrapping. The <tt>JSObject</tt> forwards calls to the wrapped C++ object using helpers in this class.
 
 
=== Lifecycle and refcounts ===
 
When constructing the collection of objects pictured above, we can imagine that the caller was C++, and was providing the <tt>nsHTMLDivElement*</tt>. In such a case, the caller would have received back an <tt>XPCWrappedNative*</tt> with refcount 2. Why 2?
 
# The reference any caller usually gets to an XPCOM object it just asked for.
# The reference the <tt>JSObject</tt>'s private slot has to the <tt>XPCWrappedNative</tt>.
 
This models a simple fact: for the <tt>XPCWrappedNative</tt> to die, both the C++ XPCOM world ''and'' the JS heap ought to have forgotten about it. If either side still sees it, it should stay alive.
 
Thus the <tt>JSObject</tt> keeps the <tt>XPCWrappedNative</tt> alive, and the <tt>XPCWrappedNative</tt> keeps the <tt>nsISupports</tt> that it's pointing to alive. But there's an important detail: the <tt>XPCWrappedNative</tt> does ''not'' directly keep the <tt>JSObject</tt> alive. Doing so unconditionally -- for example rooting the <tt>JSObject</tt> -- would give rise to a cyclic graph: the pair of objects would keep each other alive indefinitely. So the <tt>XPCWrappedNative</tt> holds a pointer to the <tt>JSObject</tt>, but doesn't root it.
 
This may prompt the curious reader to wonder what sort of mechanisms exist to keep the <tt>JSObject</tt> associated with an <tt>XPCWrappedNative</tt> alive. There are at least four (!) such mechanisms, each tailored to a situation in which it's "appropriate" to keep the <tt>JSObject</tt> alive:
 
# Obviously, if there's a root in the JS heap that can reach the <tt>JSObject</tt>, it stays alive.
# As long as a C++ caller holds a strong XPCOM reference to the <tt>XPCWrappedNative</tt>, the <tt>XPCWrappedNative</tt> has refcount >= 2. It turns out that every live <tt>XPCWrappedNative</tt> is ''also'' held in a hashtable, internal to xpconnect. The hashtable maps <tt>nsISupports*</tt> to <tt>XPCWrappedNative*</tt>. During JS GC a function (<tt>WrappedNativeJSGCThingMarker</tt> in <tt>xpcwrappednativescope.cpp</tt>) is run over that hashtable, marking the <tt>JSObject</tt> pointed to by every <tt>XPCWrappedNative</tt> with refcount > 1. This keeps things like "preserved wrappers" alive (see further below).
# Many C++ callers don't construct <tt>XPCWrappedNatives</tt> themselves, they actually call <tt>XPConnect::WrapNative()</tt>. <tt>WrapNative()</tt> constructs the <tt>XPCWrappedNative</tt> and tables it, but returns a <tt>XPCJSObjectHolder</tt> pointing to the <tt>JSObject</tt>. <tt>XPCJSObjectHolder</tt> ''does'' keep the <tt>JSObject</tt> alive for the duration of its use, by rooting. See <tt>XPCJSObjectHolder::XPCJSObjectHolder</tt> in <tt>xpcwrappednative.cpp</tt>.
# If the C++ caller is part of xpconnect itself, and is operating on <tt>XPCWrappedNatives</tt> that aren't in the table yet, the caller may store a pointer to an <tt>XPCWrappedNative</tt> in an <tt>AutoMarkingWrappedNativePtr</tt>. This is a special type which inserts itself into a global per-thread linked list and also receives a call during JS GC, which it forwards on to the <tt>AutoMark()</tt> method on the <tt>XPCWrappedNative</tt>, which subsequently causes the <tt>JSObject</tt> to be marked (thus kept alive). It's not clear to me why this is done rather than rooting or automatically inserting into the table, but it is. There is some baroque macrology and locking / work-interleaving code that suggests the answer may be complicated. <tt>AutoMarkingWrappedNativePtr</tt> is private to the implementation of xpconnect, so you won't see it in normal XPCOM-using client code.
 
=== Native Wrappers ===
 
There is a further complication to the pretty picture above (and terminology namespace): native wrappers.
 
A native wrapper, despite name-similarity to "wrapped native", is not just another term for one side of this <tt>JSObject+XPCWrappedNative</tt> cluster. It's a specific state that the JSObject involved in the cluster can have.
 
Concretely: the <tt>JSObject</tt>'s <tt>JSClass</tt> can be <tt>XPCNativeWrapper::sXPC_NW_JSClass.base</tt>. When this is true, the <tt>JSObject</tt> is said to ''be'' a native wrapper.
 
Here is the picture:
 
+------------------------------------------------------------+
| JSObject { JSClass *class = { "XPCNativeWrapper", ... }    |
|            slots[0] = ...                                 |
|            slots[JSSLOT_PRIVATE] = XPCWrappedNative* }    |
+----------------------------------------------------|-------+
                                            ^        |
                                            |        V
+-------------------------------------------|----------------+
| XPCWrappedNative { JSObject* mFlatJSObject;                |
|                    ...                                     |
|                    nsISupports* mIdentity; }              |
+------------------------------------------|-----------------+
                                            |
                                            V
+------------------------------------------------------------+
| nsHTMLDivElement { ... }                                  |
+------------------------------------------------------------+
 
The picture looks similar to the first one, and is similar in terms of memory ''ownership'' semantics. The functional difference is that a <tt>XPCNativeWrapper</tt> performs property lookup differently from a normal wrapped native. The difference is related to a certain type of attack vector involving property-name shadowing. (See [[mdc:Safely accessing content DOM from chrome]] and [[mdc:XPCNativeWrapper]].)
 
For example, suppose chrome JS associated with some browser logic (to maintain, e.g., the current document's title in the window titlebar; or hover-sensitive context menu items) or extension were to walk the content DOM. Doing so involves acquiring wrappers to content DOM nodes and calling DOM methods on the <tt>JSObject</tt> side of those wrappers, but with chrome privilege. If content were malicious, it could shadow DOM methods that are supposed to pass through to the underlying C++ DOM element, by attaching same-named properties to the wrapper JSObject. If these shadowed properties contained attack code, and other bugs bit, chrome would call the attack code with chrome privilege. Even without other bugs, chrome could be misled by content properties.
 
So instead of returning a normal wrapper to JS chrome in such a case, we return a wrapper whose <tt>JSObject</tt> has class <tt>XPCNativeWrapper</tt>. This wrapper still has an <tt>XPCWrappedNative</tt> object that points to the DOM node, but the <tt>JSObject</tt> in the cluster routes property-lookup requests through <tt>JSClass</tt> methods in <tt>XPCNativeWrapper.cpp</tt>. Such a wrapper performs special property lookup that's guaranteed to pass through to the underlying wrapped C++ object, and ignore script properties that might shadow native properties.
 
Unfortunately code and comments are not always careful with the term "wrapper", and use it to refer to either case, as well as either the JS or C++ objects in either case. So when a comment mentions "the wrapper" it may be talking about an <tt>XPCWrappedNative</tt> or a <tt>JSObject</tt>, in either "native wrapper" or "wrapped native" scenarios.
 
Personally, I wish <tt>XPCNativeWrapper</tt> had been called "security device" or something. It looks a lot like <tt>XPCWrappedNative</tt>, and my eyes often gloss one as the other (it's especially annoying given that both classes have some of the same methods!)
 
Oh well.
 
=== Preserved Wrappers ===
 
When a script obtains "a wrapper" (either a plain wrapped native or a native wrapper, see above) it thinks it has a normal JS object. Normal JS objects permit scripts to stick new properties on them. So scripts expect wrappers to retain properties that are stuck to them.
 
Unfortunately if you draw a picture of this you'll soon realize that there's not enough connectivity for that to work by default. Here's a picture of an HTML element with a script property -- a <tt>JSString</tt> -- stuck on it:
 
+------------------------------------------------------------+
| JSString { "hello world" }                                |
+------------------------------------------------------------+
                            ^
                            |
+---------------------------|--------------------------------+
| JSObject { slots[N] = { jsval }                            |
|            JSClass *class = { "HTMLDivElement", ... }      |
|            slots[JSSLOT_PRIVATE] = XPCWrappedNative* }    |
+----------------------------------------------------|-------+
                                            ^        |
                                            |        V
+-------------------------------------------|----------------+
| XPCWrappedNative { JSObject* mFlatJSObject;                |
|                    ...                                     |
|                    nsISupports* mIdentity; }              |
+-------------------------------------------|----------------+
                                            |
                                            V
+------------------------------------------------------------+
| nsHTMLDivElement { ... }                                  |
+------------------------------------------------------------+
 
The script asked for a div element from the DOM, got a wrapper (an <tt>XPCWrappedNative+JSObject</tt> cluster) and put a string on the <tt>JSObject</tt> side of the wrapper. All well and good until the script then stops running. The DOM isn't holding any references to the <tt>XPCWrappedNative</tt>, and there are no roots, so the <tt>JSObject</tt> is soon GC'ed and the <tt>XPCWrappedNative</tt> is recycled. That's ideal most of the time because wrappers are generally supposed to be ephemeral; they're instantiated for the duration of a call and then thrown out. We wouldn't normally want to keep them around.  
 
But in this case it's no good: the string is forgotten about. If script later goes looking for the property it set, the string is gone. So we have one more trick: when someone mutates a wrapper, we tell the C++ DOM node to "preserve" the wrapper (at least the <tt>XPCWrappedNative</tt> side of it, which is enough), keeping it alive by storing a strong XPCOM reference to it in a hashtable associated with the DOM node.
 
When such a DOM node is deleted, it releases all the "preserved wrappers" associated with it. Until then, properties added to the wrapper by script content persist.
 
=== Tearoffs ===
 
There are two uses of the term "tearoff" in XPCOM.
 
The first use describes a space optimization in objects that nominally support quite a lot of interfaces, but in reality only ever have a smaller number of those interfaces used. In such cases it pays to move the less-often-used parts of the interface into auxiliary objects that are constructed on demand. These auxiliary objects are called "tearoffs". A tearoff "pretends" to share its identity with the base object it was "torn off" of, by maintaining a pointer to the base object. Any time someone attempts to QI the tearoff to its base type, the tearoff addref's the base object and returns the pointer to the base object it holds. Any time someone attempts to QI the base object for the tearoff type, the base object manufactures a tearoff (that points back to the base object) and returns it. A tearoff typically keeps its base object alive. The base object may also cache its tearoff, if it expects to reuse it, but this will typically create an ownership cycle.
 
The second use describes a particular class in XPConnect called XPCWrappedNativeTearOff. Objects of this type are a speed optimization. They are manufactured by XPConnect in order to cache the results of a QI performed by script code manipulating a wrapped native. Suppose a script has a wrapped native base object: XPConnect thinks this base object is an nsISupports. Every time a script accesses it as an nsIFoo, XPConnect is obliged to QI the nsISupports to nsIFoo. This takes time. To avoid doing this on every call, XPConnect builds a an XPCWrappedNativeTearOff after the first QI and stores an XPCNativeInterface, a reflected JSObject, and the nsISupports returned from the QI (which may itself be a normal XPCOM tearoff, so is not necessarily the base nsISupports). The reflected JSObject in the tearoff is returned to the script, so that future calls through it will use the cached XPCNativeInterface in the XPCWrappedNativeTearOff, and not perform any new QI.
Confirmed users
156

edits