Open Bug 981639 Opened 10 years ago Updated 2 years ago

segfault when calling nsIFile.initWithPath('foo/') in the Gaia build system

Categories

(Core :: DOM: Core & HTML, defect, P5)

x86_64
Linux
defect

Tracking

()

People

(Reporter: vingtetun, Unassigned)

References

Details

Gaia use xpcshell to run the build system. It used to run xulrunner-26, but in order to get some accurate results on CSS parsing it will be updated to version 30 in bug 981440.

For some reasons there is a segfault in the build system on a:

var localFile = Components.classes["@mozilla.org/file/local;1"]
                .createInstance(Components.interfaces.nsILocalFile);

localFile.initWithPath('foo/');

The crash seems to happens because of the relative nature of the directory. If there is a '/' at the beginning of 'foo/', then it does not crash.

For this reason I opened the bug in the XPCOM component, feel free to change it if that does not makes sense.

Here is the stacktrace I got:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff2a3e950 in nsContentUtils::IsCallerChrome () at /home/vivien/mozilla/code/firefox/mozilla-central/content/base/src/nsContentUtils.cpp:1754
/home/vivien/mozilla/code/firefox/mozilla-central/content/base/src/nsContentUtils.cpp:1754:50512:beg:0x7ffff2a3e950
(gdb) bt
#0  0x00007ffff2a3e950 in nsContentUtils::IsCallerChrome ()
    at /home/vivien/mozilla/code/firefox/mozilla-central/content/base/src/nsContentUtils.cpp:1754
#1  0x00007ffff2a3e9c6 in nsContentUtils::ThreadsafeIsCallerChrome ()
    at /home/vivien/mozilla/code/firefox/mozilla-central/content/base/src/nsContentUtils.cpp:1780
#2  0x00007ffff1d6795b in mozilla::dom::ExceptionBinding::CreateInterfaceObjects (aCx=0x7fffe65e7a80, aGlobal=
    (JSObject * const) 0x7fffe4f406a0 [object Sandbox] delegate, aProtoAndIfaceArray=..., aDefineOnGlobal=true)
    at /home/vivien/mozilla/code/firefox/mozilla-central/obj-x86_64-unknown-linux-gnu/dom/bindings/DOMExceptionBinding.cpp:1194
#3  0x00007ffff1d67b22 in mozilla::dom::ExceptionBinding::GetProtoObject (aCx=0x7fffe65e7a80, aGlobal=
    (JSObject * const) 0x7fffe4f406a0 [object Sandbox] delegate)
    at /home/vivien/mozilla/code/firefox/mozilla-central/obj-x86_64-unknown-linux-gnu/dom/bindings/DOMExceptionBinding.cpp:1213
#4  0x00007ffff1d675d3 in mozilla::dom::ExceptionBinding::Wrap (aCx=0x7fffe65e7a80, aScope=
    (JSObject * const) 0x7fffe4f406a0 [object Sandbox] delegate, aObject=0x7fffe4c62880, aCache=0x7fffe4c62888)
    at /home/vivien/mozilla/code/firefox/mozilla-central/obj-x86_64-unknown-linux-gnu/dom/bindings/DOMExceptionBinding.cpp:1141
#5  0x00007ffff2626382 in mozilla::dom::ExceptionBinding::Wrap<mozilla::dom::Exception> (aCx=0x7fffe65e7a80, aScope=
    (JSObject * const) 0x7fffe4f406a0 [object Sandbox] delegate, aObject=0x7fffe4c62880) at ../../dist/include/mozilla/dom/DOMExceptionBinding.h:87
#6  0x00007ffff260e333 in mozilla::dom::Exception::WrapObject (this=0x7fffe4c62880, cx=0x7fffe65e7a80, scope=
    (JSObject * const) 0x7fffe4f406a0 [object Sandbox] delegate) at /home/vivien/mozilla/code/firefox/mozilla-central/dom/base/DOMException.cpp:478
#7  0x00007ffff22b768e in mozilla::dom::WrapNewBindingObject<mozilla::dom::Exception> (cx=0x7fffe65e7a80, scope=
    (JSObject * const) 0x7fffe4f406a0 [object Sandbox] delegate, value=0x7fffe4c62880, rval=JSVAL_VOID)
    at /home/vivien/mozilla/code/firefox/mozilla-central/dom/bindings/BindingUtils.h:697
#8  0x00007ffff22b347e in mozilla::dom::ThrowExceptionObject (aCx=0x7fffe65e7a80, aException=0x7fffe4c62880)
    at /home/vivien/mozilla/code/firefox/mozilla-central/dom/bindings/Exceptions.cpp:96
#9  0x00007ffff22b377b in mozilla::dom::Throw (aCx=0x7fffe65e7a80, aRv=2152857601, aMessage=
    0x7fffe3a15a90 "Component returned failure code: 0x80520001 (NS_ERROR_FILE_UNRECOGNIZED_PATH) [nsILocalFile.initWithPath]")
    at /home/vivien/mozilla/code/firefox/mozilla-central/dom/bindings/Exceptions.cpp:156
#10 0x00007ffff24b29cc in XPCThrower::ThrowBadResult (rv=2153185284, result=2152857601, ccx=...)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/xpconnect/src/XPCThrower.cpp:122
#11 0x00007ffff24db6e1 in ThrowBadResult (result=2152857601, ccx=...)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/xpconnect/src/XPCInlines.h:576
#12 0x00007ffff24dcb35 in CallMethodHelper::Call (this=0x7fffffff4440)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/xpconnect/src/XPCWrappedNative.cpp:1754
#13 0x00007ffff24c3d20 in XPCWrappedNative::CallMethod (ccx=..., mode=XPCWrappedNative::CALL_METHOD)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/xpconnect/src/XPCWrappedNative.cpp:1714
#14 0x00007ffff24ccb6c in XPC_WN_CallMethod (cx=0x7fffe65e7a80, argc=1, vp=0x7fffffff4d18)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/xpconnect/src/XPCWrappedNativeJSOps.cpp:1285
#15 0x00007ffff4d7f8c0 in js::CallJSNative (cx=0x7fffe65e7a80, native=0x7ffff24cc878 <XPC_WN_CallMethod(JSContext*, unsigned int, JS::Value*)>, args=
    ...) at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/jscntxtinlines.h:239
#16 0x00007ffff4d38968 in js::Invoke (cx=0x7fffe65e7a80, args=..., construct=js::NO_CONSTRUCT)
---Type <return> to continue, or q <return> to quit---
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/vm/Interpreter.cpp:476
#17 0x00007ffff4d38e13 in js::Invoke (cx=0x7fffe65e7a80, thisv=..., fval=..., argc=1, argv=0x7fffffff5668, rval=JSVAL_VOID)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/vm/Interpreter.cpp:532
#18 0x00007ffff4b623d5 in JS_CallFunctionValue (cx=0x7fffe65e7a80, obj=(JSObject * const) 0x7fffe38a3190 [object XPCWrappedNative_NoHelper], fval=
    $jsval((JSObject *) 0x7fffe38353a0 [object Function "initWithPath"]), args=..., rval=JSVAL_VOID)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/jsapi.cpp:4935
#19 0x00007ffff243024f in nsXPCConstructor::CallOrConstruct (this=0x7fffe3aafb80, wrapper=0x7fffe391c920, cx=0x7fffe65e7a80, obj=
    (JSObject * const) 0x7fffe4f41100 [object nsXPCConstructor], args=..., _retval=0x7fffffff52ff)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/xpconnect/src/XPCComponents.cpp:2181
#20 0x00007ffff242fb31 in nsXPCConstructor::Construct (this=0x7fffe3aafb80, wrapper=0x7fffe391c920, cx=0x7fffe65e7a80, objArg=
    (JSObject *) 0x7fffe4f41100 [object nsXPCConstructor], args=..., _retval=0x7fffffff52ff)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/xpconnect/src/XPCComponents.cpp:2130
#21 0x00007ffff24cb4f6 in XPC_WN_Helper_Construct (cx=0x7fffe65e7a80, argc=1, vp=0x7fffffff5658)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/xpconnect/src/XPCWrappedNativeJSOps.cpp:858
#22 0x00007ffff4d7f8c0 in js::CallJSNative (cx=0x7fffe65e7a80, native=0x7ffff24cb1e1 <XPC_WN_Helper_Construct(JSContext*, unsigned int, jsval*)>, 
    args=...) at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/jscntxtinlines.h:239
#23 0x00007ffff4d7fa20 in js::CallJSNativeConstructor (cx=0x7fffe65e7a80, native=
    0x7ffff24cb1e1 <XPC_WN_Helper_Construct(JSContext*, unsigned int, jsval*)>, args=...)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/jscntxtinlines.h:272
#24 0x00007ffff4d391cb in js::InvokeConstructor (cx=0x7fffe65e7a80, args=...)
    at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/vm/Interpreter.cpp:573
#25 0x00007ffff4d392da in js::InvokeConstructor (cx=0x7fffe65e7a80, fval=$jsval((JSObject *) 0x7fffe4f41100 [object nsXPCConstructor]), argc=1, argv=
    0x7fffffff5948, rval=0x7fffffff58f0) at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/vm/Interpreter.cpp:587
#26 0x00007ffff4903a15 in js::jit::DoCallFallback (cx=0x7fffe65e7a80, frame=0x7fffffff59b0, stub=0x7fffe3903420, argc=1, vp=0x7fffffff5938, res=
    JSVAL_VOID) at /home/vivien/mozilla/code/firefox/mozilla-central/js/src/jit/BaselineIC.cpp:8085
#27 0x00007ffff7feaabb in ?? ()
#28 0x00007fffffff59b2 in ?? ()
#29 0x00007fffffff58f0 in ?? ()
#30 0xfff9000000000000 in ?? ()
#31 0x00007ffff7ae74a0 in js::jit::DoCallNativeSetterInfo ()
   from /home/vivien/mozilla/code/firefox/mozilla-central/obj-x86_64-unknown-linux-gnu/dist/bin/libxul.so
#32 0x00007fffe4f3bca0 in ?? ()
#33 0x00007ffff7dfe327 in ?? ()
#34 0x0000000000000482 in ?? ()
#35 0x00007fffffff59b0 in ?? ()
#36 0x00007fffe3903420 in ?? ()
#37 0x0000000000000001 in ?? ()
#38 0x00007fffffff5938 in ?? ()



In order to get the stacktrace I had to run the above command from the $GAIA directory:

LD_LIBRARY_PATH=/home/vivien/mozilla/code/firefox/mozilla-central/obj-x86_64-unknown-linux-gnu/dist/bin gdb /home/vivien/mozilla/code/firefox/mozilla-central/obj-x86_64-unknown-linux-gnu/dist/bin/xpcshell 

gdb shell:

run -e "const GAIA_BUILD_DIR='file:///home/vivien/mozilla/code/firefoxos/gaia/build/'" -f build/xpcshell-commonjs.js -e 'try { require("settings").execute({GAIA_DIR : "/home/vivien/mozilla/code/firefoxos/gaia", PROFILE_DIR : "/home/vivien/mozilla/code/firefoxos/gaia/profile-test", PROFILE_FOLDER : "profile-test", GAIA_SCHEME : "app://", GAIA_DOMAIN : "gaiamobile.org", DEBUG : 0, LOCAL_DOMAINS : 1, DESKTOP : 0, DEVICE_DEBUG : 0, NO_LOCK_SCREEN : 0, HOMESCREEN : "app://system.gaiamobile.org", GAIA_PORT : "", GAIA_LOCALES_PATH : "locales", GAIA_INSTALL_PARENT : "/system/b2g", LOCALES_FILE : "shared/resources/languages.json", GAIA_KEYBOARD_LAYOUTS : ["en","pt-BR","es","de","fr","pl","zh-Hans-Pinyin"], LOCALE_BASEDIR : "", BUILD_APP_NAME : "*", PRODUCTION : 0, GAIA_OPTIMIZE : 0, GAIA_DEV_PIXELS_PER_PX : 1, DOGFOOD : 0, OFFICIAL : 0, GAIA_DEFAULT_LOCALE : "en-US", GAIA_INLINE_LOCALES : 1, GAIA_CONCAT_LOCALES : 1, GAIA_ENGINE : "xpcshell", GAIA_DISTRIBUTION_DIR : "/home/vivien/mozilla/code/firefoxos/gaia/distribution", GAIA_APPDIRS : "/home/vivien/mozilla/code/firefoxos/gaia/apps/wappush", NOFTU : 0, REMOTE_DEBUGGER : 0, ROCKETBAR : "none", TARGET_BUILD_VARIANT : "", SETTINGS_PATH : "build/config/custom-settings.json", VARIANT_PATH : "" }); quit(0); } catch(e) { dump("Exception: " + e + "\n" + e.stack + "\n"); throw(e); }'

Obviously all the /home/vivien/mozilla/code path should be replaced.

I tried to just load a |test.js| file loading a nsILocalFile with a relative path but it does not crash.
This is a DOM/XPConnect issue, not an XPCOM one.  The only reason XPCOM is involved is that initWithPath("foo/") will throw an exception, as it should: initWithPath only accepts absolute paths.  The crash happens when trying to create the exception object.

Exception objects have chromeonly properties, so we have to check whether we're running in a chrome context.  We call nsContentUtils::ThreadsafeIsCallerChrome(), which detects we're on the main thread and calls IsCallerChrome(), which tries to use sSecurityManager.

Vivien, is sSecurityManager null for you when you crash?

Also, this does not crash for me:

xpcshell -e "var localFile = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile); localFile.initWithPath('foo/');"

Vivien, your steps to reproduce don't seem to have any localfile bits.  Where do those actually live?  It looks like it's running in a sandbox?
Component: XPCOM → DOM
Flags: needinfo?(21)
(In reply to Boris Zbarsky [:bz] from comment #1)
> 
> Exception objects have chromeonly properties, so we have to check whether
> we're running in a chrome context.  We call
> nsContentUtils::ThreadsafeIsCallerChrome(), which detects we're on the main
> thread and calls IsCallerChrome(), which tries to use sSecurityManager.
> 
> Vivien, is sSecurityManager null for you when you crash?

Here is what gdb told me:

Program received signal SIGSEGV, Segmentation fault.
(gdb) print sSecurityManager
$1 = (nsIScriptSecurityManager *) 0x0

> 
> Also, this does not crash for me:
> 
> xpcshell -e "var localFile =
> Components.classes['@mozilla.org/file/local;1'].createInstance(Components.
> interfaces.nsILocalFile); localFile.initWithPath('foo/');"
> 

That what I mentioned at the end of my description. I tried to use this code into a |test.js| file to see if it crash, and it does not and performsn normally.

> Vivien, your steps to reproduce don't seem to have any localfile bits. 
> Where do those actually live?  It looks like it's running in a sandbox?

Those files are on my local machine, sitting next to the build scripts. I'm not doing any kind of sandboxing by myself, but I'm trying to create a xpcshell script testcase to make it easier to debug.
Flags: needinfo?(21)
OK.  I _can_ reproduce with the steps from comment 0, and I also see a null sSecurityManager.

The reason it's null is that the stack (the parts of it comment 0 does _not_ show) starts off like so:

#59 0x000000010003f958 in NS_ProcessNextEvent (thread=0x10f3351e0, mayWait=true) at nsThreadUtils.cpp:263
#60 0x000000010013e3ad in nsThread::Shutdown (this=0x10f335480) at nsThread.cpp:487
#61 0x00000001001f28e1 in nsSocketTransportService::Shutdown (this=0x10f36e600) at nsSocketTransportService2.cpp:517
#62 0x000000010024a43d in nsIOService::SetOffline (this=0x10f3e8200, offline=true) at nsIOService.cpp:748
#63 0x000000010024caf7 in nsIOService::Observe (this=0x10f3e8200, subject=0x10f34c338, topic=0x10488b298 "xpcom-shutdown", data=0x0) at nsIOService.cpp:949
#64 0x000000010024cbff in _ZThn8_N11nsIOService7ObserveEP11nsISupportsPKcPKDs () at nsIOService.cpp:960
#65 0x00000001000bf1c9 in nsObserverList::NotifyObservers (this=0x10f31f950, aSubject=0x10f34c338, aTopic=0x10488b298 "xpcom-shutdown", someData=0x0) at nsObserverList.cpp:96
#66 0x00000001000c0f11 in nsObserverService::NotifyObservers (this=0x10f326560, aSubject=0x10f34c338, aTopic=0x10488b298 "xpcom-shutdown", someData=0x0) at nsObserverService.cpp:302
#67 0x000000010004caca in mozilla::ShutdownXPCOM (servMgr=0x0) at nsXPComInit.cpp:700
#68 0x000000010004c8c5 in NS_ShutdownXPCOM (servMgr=0x0) at nsXPComInit.cpp:645

The JS stack to the relevant callsite is:

0 getFile(arguments = "build/config/custom-settings.json") ["resource://gre/modules/commonjs/toolkit/loader.js -> file:///Users/bzbarsky/mozilla/gaia/build/utils-xpc.js":98]
    this = [object Sandbox]
1 resolve(path = "build/config/custom-settings.json", gaiaDir = "/Users/bzbarsky/mozilla/gaia") ["resource://gre/modules/commonjs/toolkit/loader.js -> file:///Users/bzbarsky/mozilla/gaia/build/utils-xpc.js":339]
    <failed to get 'this' value>
2 overrideSettings(settings = [object Object], config = [object Object]) ["resource://gre/modules/commonjs/toolkit/loader.js -> file:///Users/bzbarsky/mozilla/gaia/build/settings.js":57]
3 anonymous(undefined) ["resource://gre/modules/commonjs/toolkit/loader.js -> file:///Users/bzbarsky/mozilla/gaia/build/settings.js":147]
    this = [object Object]
4 anonymous() ["resource://gre/modules/Promise.jsm":782]
    this = [object Object]
5 anonymous() ["resource://gre/modules/Promise.jsm":661]
    this = [object Object]

Line 661 in resource://gre/modules/Promise.jsm is in walkerLoop, which is Promise.jsm does use as a runnable.

So what's happening is that we start shutting down the process.  We shut down nsContentUtils, which nulls out sSecurityManager (?).  Then we send "xpcom-shutdown" notifications, which causes nsSocketTransportService::Shutdown to run, which spins the event loop, which runs Promise.jsm code that calls back into random other code which tries to create a DOM exception, which tries to use nsContentUtils and crashes.
Oh, and the thing that nulls out sSecurityManager is also an "xpcom-shutdown" observer.  Specifically, this stack:

#0  0x000000010241fffd in nsContentUtils::Shutdown () at nsContentUtils.cpp:1460
#1  0x0000000101c3530b in nsLayoutStatics::Shutdown () at nsLayoutStatics.cpp:348
#2  0x0000000101c3d993 in nsLayoutStatics::Release () at nsLayoutStatics.h:46
#3  0x0000000101c34a8e in Shutdown () at mozalloc.h:225
#4  0x0000000101c34a1b in LayoutShutdownObserver::Observe (this=0x10fcbf9c0, aSubject=0x10f34c338, aTopic=0x10488b298 "xpcom-shutdown", someData=0x0) at nsLayoutModule.cpp:376
#5  0x00000001000bf1c9 in nsObserverList::NotifyObservers (this=0x10f31e950, aSubject=0x10f34c338, aTopic=0x10488b298 "xpcom-shutdown", someData=0x0) at nsObserverList.cpp:96

Bobby, Benjamin, it seems pretty daft to me to be shutting down basic DOM machinery before xpcom-shudown notifications finish.  Should that machinery move out of nsContentUtils to something that gets shut down later, or should we be addrefing/releasing nsLayoutStatics around xpcom-shutdown notifications?
Flags: needinfo?(bobbyholley)
Flags: needinfo?(benjamin)
This sounds like bug 913138, which I tried to fix by moving nsLayoutStatics shutdown to the layout module dtor, and got caught in the rats' nest of shutdown touchiness.
Flags: needinfo?(bobbyholley)
hmmm. I wonder if this is not that the code hits nsContentUtils during the shutdown phase.

So basically and in order to reproduce I have to do:

1. Get gaia from https://github.com/vingtetun/gaia/tree/bug981440
2. cd into the Gaia folder
3.  LD_LIBRARY_PATH=xulrunner-sdk-30/xulrunner-sdk/bin/ xulrunner-sdk-30/xulrunner-sdk/bin/xpcshell -e "const GAIA_BUILD_DIR='file:///home/vivien/mozilla/code/firefoxos/gaia/build/'" -f build/xpcshell-commonjs.js -e "require('test')"

Where test is a js file in the build directory containing:

----

const { Cc, Ci, Cr, Cu, CC } = require('chrome');

Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/FileUtils.jsm');
Cu.import('resource://gre/modules/Promise.jsm');

var queue = Promise.defer();
queue.resolve();

queue.promise.then(function() {
  new FileUtils.File('foo/');
})

/*
  let thread = Services.tm.currentThread;
  while (thread.hasPendingEvents()) {
    thread.processNextEvent(false);
  };
*/

----

I can reproduce the sefgaut If I do not use the require(...) mechanism. But basically it seems like the Promise callback is executing too late. If I uncomment the last bits of the test.js file then it finishes to work.
(Sorry for the comment that arrives a bit late as we mid-air collision-ed)
See also bug 976181.  This is probably a dupe.
See Also: → 976181
bholley is right; this is a mess that's going to be hard to untangle but eventually we're going to have to pay off this massive debt.

I expect where we want to end up is explicitly starting up and shutting down various modules in order.
Flags: needinfo?(benjamin)
Priority: -- → P5
Component: DOM → DOM: Core & HTML
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.