Closed
Bug 53268
Opened 25 years ago
Closed 25 years ago
unexpected sideeffect with proto and scopeprops
Categories
(Core :: JavaScript Engine, defect, P1)
Core
JavaScript Engine
Tracking
()
VERIFIED
FIXED
M18
People
(Reporter: jband_mozilla, Assigned: brendan)
References
Details
(Keywords: js1.5)
Attachments
(3 files)
2.28 KB,
patch
|
Details | Diff | Splinter Review | |
2.73 KB,
patch
|
Details | Diff | Splinter Review | |
2.79 KB,
text/plain
|
Details |
Sorry I don't know what to call this. It will take a while to explain...
When xpconnect wraps a native object it creates a JSObject to reflect the
object into JS. That object is created in
nsXPCWrappedNativeClass::NewInstanceJSObject...
http://lxr.mozilla.org/seamonkey/source/js/src/xpconnect/src/xpcwrappednativecla
ss.cpp#1267
See the comment there where it calls JS_NewObject with the global object as the
proto and then calls JS_SetPrototype(cx, jsobj, nsnull). It does this to avoid a
lookup.
I've discovered a situation where this dance does not have the same effect as if
we'd called JS_NewObject with a null proto in the first place.
The patch attached to bug 52936 includes a fix for bug 52591. This fix sets up a
new Components object for each JS Component Loader global object.
What I've discovered is that with that patch applied then I see a case where a
JS Component gets: Components.interfaces.nsIFactory = undefined.
I traced this to the code in nsXPCComponents_Interfaces::GetProperty where we
try to dynamically cache properies of Components.interfaces...
http://lxr.mozilla.org/seamonkey/source/js/src/xpconnect/src/xpccomponents.cpp#1
59
The thing that is failing is the underlying js_SetProperty.
http://lxr.mozilla.org/seamonkey/source/js/src/jsobj.c#2180
It gets into the block:
if (!sprop || (proto = scope->object) != obj)
if (sprop)
if (attrs & JSPROP_READONLY)
But the object in question is supposed to not have a proto. It is just a plain
JSObject (using the xpc ops and jsclass) constructed as above. It implements
nsIXPCScriptable to allow getproperty, but should not be hitting this code.
The attr we find is 0x7 which happens to be the same used when the Components
object is added to the global in nsXPCComponents::AttachNewComponentsObject:
http://lxr.mozilla.org/seamonkey/source/js/src/xpconnect/src/xpccomponents.cpp#1
949
Let me say something about how the global objects work in the JS Component
Loader (based on my patch bug 52936)...
The SuperGlobal is a plain JSObject made using the jsclass in the component
loader. We attach an xpconnect Components object to it. A Components object is a
wrapped native that is attached as linked above. This is done in
mozJSComponentLoader::ReallyInit
For each .js file we want to read we make a global object. This global is a
wrapped native. After creation and wrapping, its parent is the super global. We
then manually use the jsapi to set its parent to null and and its proto to the
superglobal. We then attach a Components object to this global using
xpc->InitClasses. This is all in mozJSComponentLoader::ModuleForLocation
So, what we should have is:
super_global: parent = null, proto = null
super_global.Components: parent = super_global, proto = null
global : parent = null, proto = super_global
global.Components: parent = global, proto = null
OK. Here is the test case...
I go to tinderbox and click on the "Add tinderbox to your sidebar" link. This is
supposed to use the JS component in nsSidebar.js. It fails in
sidebarModule.getClassObject. By sticking in some dump statements I determined
it is failing because Components.interfaces.nsIFactory = undefined.
By tracing I see that nsXPCComponents_Interfaces::GetProperty's call to
CacheDynaProp succeeds in constructing the nsIJSIID object but fails in
js_SetProperty because it(apparently) thinks this is a readonly property on a
prototype.
Two work arounds will keep this from happening:
1) don't do the dance in nsXPCWrappedNativeClass::NewInstanceJSObject of
creating the JSObject using a prototype and then switching to null.
OR
2) don't create a Components object for each global in the JS component loader.
I think there is a deeper engine problem here. Number '1' above shows that the
assumption behind the proto switching dance is either broken or tripping over
broken code.
Help!
Assignee | ||
Comment 1•25 years ago
|
||
I can't keep up. What is the name of the sprop with the JSPROP_READONLY bit set
in its attributes, and what is the class of the object it was found in (proto in
that js_SetProperty code, at the point you quote)?
*(JSString*)(sprop->id - 4) should give you the ucs2 string for the name of the
property.
*(JSClass *)(proto->slots[2]-1) is the class.
/be
Summary: unexpected sideeffect with proto and scopeprops → unexpected sideeffect with proto and scopeprops
Reporter | ||
Comment 2•25 years ago
|
||
The sprops name is "nsIFactory" as expected.
The classname of both proto and obj is XPCWrappedNativeWithCall.
I have additional interesting info...
The file we are loading is:
http://lxr.mozilla.org/seamonkey/source/xpfe/components/sidebar/src/nsSidebar.js
That file sets const globals like (most interestingly):
const nsIFactory = Components.interfaces.nsIFactory;
So when the Components.interfaces object gets first created with JS_NewObject
and with proto set to the global object, it really *does* have a proto with a
readonly, permanent, and enumerable "nsIFactory" prop. The surprise is that
JS_SetPrototype(cx, jsobj, nsnull) does not fully undo this. jsobj.slot[0]
certainly ends up being 0. And, though this pseudo-proto property is not
setable, it is certainly not readable either.
Starting to smell like a fixable bug? It may be that an all JS test case is
constructable.
Reporter | ||
Comment 3•25 years ago
|
||
js> const foo = 5
js> foo
5
js> bar = {}
[object Object]
js> bar.__proto__ = this
[object global]
js> bar.foo
5
js> bar.__proto__ = null
null
js> bar.foo
js> bar.foo = 1
1
js> bar.foo
js> bar.baz = 2
2
js> bar.baz
2
js>
Assignee | ||
Comment 4•25 years ago
|
||
Thanks, you found the big bad hole in my fix for the bug XBL found in JS scope
sharing. An empty JS object, when changing prototypes, needs to share the new
proto's scope, and drop the old one. But what if the new proto is null? D'oh!
Patch coming up, looking to get this in today. Thanks again.
/be
Assignee | ||
Comment 5•25 years ago
|
||
Assignee | ||
Updated•25 years ago
|
Assignee | ||
Comment 6•25 years ago
|
||
Adding retroactive dependency for historical purposes.
/be
Depends on: 41126
Reporter | ||
Comment 7•25 years ago
|
||
r=jband
I'll attach a patch to make xpconnect do the right thing during proto and parent
set. a= please?
Reporter | ||
Comment 8•25 years ago
|
||
Assignee | ||
Comment 9•25 years ago
|
||
trade you a= for r= on my patch, and we're done. Right?
/be
Reporter | ||
Comment 10•25 years ago
|
||
checked in xpconnect patch. thanks.
Status: ASSIGNED → RESOLVED
Closed: 25 years ago
Resolution: --- → FIXED
Comment 11•25 years ago
|
||
Comment 12•25 years ago
|
||
Marking Verified - the above testcase passes on WinNT, Linux, and Mac.
Using JS shell built from CVS source 2000-09-21 8PM Pacific Time.
(Note: the testcase has a dependency on js/tests/ecma_3/shell.js.)
I will add the testcase to the ecma_3 directory on Monday, in a subdirectory
called "Scope". If that is the wrong subject heading, please let me know -
Status: RESOLVED → VERIFIED
Comment 13•25 years ago
|
||
Testcase has been added to suite as follows:
js/tests/js1_5/Scope/scope-001.js
You need to log in
before you can comment on or make changes to this bug.
Description
•