Bug 1594998 - Make standalone SpiderMonkey use libxul-like panic. r=froydnj,jandem
☠☠ backed out by cb4ea31e8593 ☠ ☠
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 13 Nov 2019 22:07:08 +0000
changeset 501850 4cf8f3f89042f4622a349e2fd75a849155ffa75b
parent 501849 7ace5357440ad37e7608a301bf37b6c2b53dd6b4
child 501851 a01e42ada2cdf66cae108e9ef16f3ed2890142e9
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj, jandem
bugs1594998
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1594998 - Make standalone SpiderMonkey use libxul-like panic. r=froydnj,jandem This moves the parts of toolkit/library/rust/shared/lib.rs related to panic hooking to a new mozglue subdirectory, which will be used for things that can be statically linked to e.g. libxul, rather than in a "shared library". The panic hook is disabled when building spidermonkey via the mozjs_sys crate. Differential Revision: https://phabricator.services.mozilla.com/D52793
Cargo.lock
js/moz.configure
js/src/build.rs
js/src/make-source-package.sh
js/src/rust/shared/Cargo.toml
js/src/rust/shared/lib.rs
js/src/vm/Initialization.cpp
mozglue/static/README
mozglue/static/rust/Cargo.toml
mozglue/static/rust/build.rs
mozglue/static/rust/lib.rs
mozglue/static/rust/wrappers.cpp
testing/mozbase/mozcrash/mozcrash/mozcrash.py
toolkit/library/rust/shared/Cargo.toml
toolkit/library/rust/shared/lib.rs
toolkit/xre/nsAppRunner.cpp
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1236,17 +1236,16 @@ dependencies = [
  "nsstring-gtest 0.1.0",
  "xpcom-gtest 0.1.0",
 ]
 
 [[package]]
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
- "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "audioipc-client 0.4.0",
  "audioipc-server 0.2.3",
  "authenticator 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitsdownload 0.1.0",
  "bookmark_sync 0.1.0",
  "cert_storage 0.0.1",
  "cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1532,16 +1531,17 @@ dependencies = [
 
 [[package]]
 name = "jsrust_shared"
 version = "0.1.0"
 dependencies = [
  "baldrdash 0.1.0",
  "encoding_c 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_c_mem 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mozglue-static 0.1.0",
  "mozilla-central-workspace-hack 0.1.0",
 ]
 
 [[package]]
 name = "kernel32-sys"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1981,16 +1981,24 @@ version = "0.1.0"
 dependencies = [
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "mozglue-static"
+version = "0.1.0"
+dependencies = [
+ "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "mozilla-central-workspace-hack"
 version = "0.1.0"
 dependencies = [
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -83,16 +83,22 @@ set_define('STATIC_JS_API', static_js_ap
 @depends(shared_js)
 def static_js(value):
     if not value:
         return True
 
 set_define('MOZ_STATIC_JS', static_js)
 
 
+js_option(env='NO_RUST_PANIC_HOOK', when=js_standalone,
+          help='Disable rust panic hook')
+
+set_define('NO_RUST_PANIC_HOOK', True, when='NO_RUST_PANIC_HOOK')
+
+
 # JIT support
 # =======================================================
 @depends(target)
 def ion_default(target):
     if target.cpu in ('x86', 'x86_64', 'arm', 'aarch64', 'mips32', 'mips64'):
         return True
     return False
 
--- a/js/src/build.rs
+++ b/js/src/build.rs
@@ -42,16 +42,17 @@ fn main() {
                // good.
                "--no-jemalloc",
                // Don't try to clobber the output directory. Without
                // this option, the build will fail because the directory
                // already exists but wasn't created by autospider.
                "--dep",
                "--objdir", &out_dir,
                &variant])
+        .env("NO_RUST_PANIC_HOOK", "1")
         .env("SOURCE", &js_src)
         .env("PWD", &js_src)
         .stdout(Stdio::inherit())
         .stderr(Stdio::inherit());
     println!("Running command: {:?}", cmd);
     let result = cmd
         .status()
         .expect("Should spawn autospider OK");
--- a/js/src/make-source-package.sh
+++ b/js/src/make-source-package.sh
@@ -104,16 +104,17 @@ case $cmd in
         ${tgtpath}/modules/
 
     ${MKDIR} -p ${tgtpath}/mozglue
     cp -pPR \
         ${TOPSRCDIR}/mozglue/baseprofiler \
         ${TOPSRCDIR}/mozglue/build \
         ${TOPSRCDIR}/mozglue/misc \
         ${TOPSRCDIR}/mozglue/moz.build \
+        ${TOPSRCDIR}/mozglue/static \
         ${tgtpath}/mozglue/
 
     ${MKDIR} -p ${tgtpath}/tools/fuzzing
     cp -pPR \
         ${TOPSRCDIR}/tools/fuzzing/moz.build \
         ${TOPSRCDIR}/tools/fuzzing/interface \
         ${TOPSRCDIR}/tools/fuzzing/registry \
         ${TOPSRCDIR}/tools/fuzzing/libfuzzer \
--- a/js/src/rust/shared/Cargo.toml
+++ b/js/src/rust/shared/Cargo.toml
@@ -8,16 +8,17 @@ crate-type = ["rlib"]
 name = "jsrust_shared"
 path = "lib.rs"
 
 [dependencies]
 baldrdash = { path = "../../wasm/cranelift", optional = true }
 encoding_c = "0.9.5"
 encoding_c_mem = "0.2.4"
 mozilla-central-workspace-hack = { path = "../../../../build/workspace-hack" }
+mozglue-static = { path = "../../../../mozglue/static/rust" }
 
 [features]
 cranelift_x86 = ['baldrdash/cranelift_x86']
 cranelift_arm32 = ['baldrdash/cranelift_arm32']
 cranelift_arm64 = ['baldrdash/cranelift_arm64']
 cranelift_none = ['baldrdash/cranelift_none']
 simd-accel = ['encoding_c/simd-accel']
 
--- a/js/src/rust/shared/lib.rs
+++ b/js/src/rust/shared/lib.rs
@@ -12,8 +12,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 #[cfg(feature = "baldrdash")]
 extern crate baldrdash;
 
 extern crate encoding_c;
 extern crate encoding_c_mem;
+extern crate mozglue_static;
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -87,16 +87,18 @@ static void CheckCanonicalNaN() {
 #endif
 }
 
 #define RETURN_IF_FAIL(code)           \
   do {                                 \
     if (!code) return #code " failed"; \
   } while (0)
 
+extern "C" void install_rust_panic_hook();
+
 JS_PUBLIC_API const char* JS::detail::InitWithFailureDiagnostic(
     bool isDebugBuild) {
   // Verify that our DEBUG setting matches the caller's.
 #ifdef DEBUG
   MOZ_RELEASE_ASSERT(isDebugBuild);
 #else
   MOZ_RELEASE_ASSERT(!isDebugBuild);
 #endif
@@ -104,16 +106,20 @@ JS_PUBLIC_API const char* JS::detail::In
   MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
              "must call JS_Init once before any JSAPI operation except "
              "JS_SetICUMemoryFunctions");
   MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
              "how do we have live runtimes before JS_Init?");
 
   libraryInitState = InitState::Initializing;
 
+#ifndef NO_RUST_PANIC_HOOK
+  install_rust_panic_hook();
+#endif
+
   PRMJ_NowInit();
 
   js::SliceBudget::Init();
 
   // The first invocation of `ProcessCreation` creates a temporary thread
   // and crashes if that fails, i.e. because we're out of memory. To prevent
   // that from happening at some later time, get it out of the way during
   // startup.
new file mode 100644
--- /dev/null
+++ b/mozglue/static/README
@@ -0,0 +1,2 @@
+mozglue/static contains parts of the mozglue library that can/should be
+statically linked to e.g. js/Gecko.
new file mode 100644
--- /dev/null
+++ b/mozglue/static/rust/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "mozglue-static"
+version = "0.1.0"
+edition = "2018"
+license = "MPL"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+arrayvec = "0.4"
+
+[build-dependencies]
+cc = "1"
new file mode 100644
--- /dev/null
+++ b/mozglue/static/rust/build.rs
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::env;
+use std::path::PathBuf;
+
+fn main() {
+    let dist_path = {
+        let path = PathBuf::from(env::var_os("MOZ_DIST").unwrap());
+        if !path.is_absolute() || !path.is_dir() {
+            panic!("MOZ_DIST must be an absolute directory, was: {}", path.display());
+        }
+        path
+    };
+    let mut build = cc::Build::new();
+    build.cpp(true);
+    build.include(dist_path.join("include"));
+    build.file("wrappers.cpp");
+    build.compile("wrappers");
+    println!("cargo:rerun-if-changed=wrappers.cpp");
+}
new file mode 100644
--- /dev/null
+++ b/mozglue/static/rust/lib.rs
@@ -0,0 +1,98 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::os::raw::c_char;
+use std::os::raw::c_int;
+use std::cmp;
+use std::panic;
+use std::ops::Deref;
+use arrayvec::{Array, ArrayString};
+
+#[link(name="wrappers")]
+extern "C" {
+    // We can't use MOZ_Crash directly because it may be weakly linked
+    // and rust can't handle that.
+    fn RustMozCrash(filename: *const c_char, line: c_int, reason: *const c_char) -> !;
+}
+
+/// Truncate a string at the closest unicode character boundary
+/// ```
+/// assert_eq!(str_truncate_valid("éà", 3), "é");
+/// assert_eq!(str_truncate_valid("éà", 4), "éè");
+/// ```
+fn str_truncate_valid(s: &str, mut mid: usize) -> &str {
+    loop {
+        if let Some(res) = s.get(..mid) {
+            return res;
+        }
+        mid -= 1;
+    }
+}
+
+/// Similar to ArrayString, but with terminating nul character.
+#[derive(Debug, PartialEq)]
+struct ArrayCString<A: Array<Item = u8>> {
+    inner: ArrayString<A>,
+}
+
+impl<S: AsRef<str>, A: Array<Item = u8>> From<S> for ArrayCString<A> {
+    /// Contrary to ArrayString::from, truncates at the closest unicode
+    /// character boundary.
+    /// ```
+    /// assert_eq!(ArrayCString::<[_; 4]>::from("éà"),
+    ///            ArrayCString::<[_; 4]>::from("é"));
+    /// assert_eq!(&*ArrayCString::<[_; 4]>::from("éà"), "é\0");
+    /// ```
+    fn from(s: S) -> Self {
+        let s = s.as_ref();
+        let len = cmp::min(s.len(), A::capacity() - 1);
+        let mut result = Self {
+            inner: ArrayString::from(str_truncate_valid(s, len)).unwrap(),
+        };
+        result.inner.push('\0');
+        result
+    }
+}
+
+impl<A: Array<Item = u8>> Deref for ArrayCString<A> {
+    type Target = str;
+
+    fn deref(&self) -> &str {
+        self.inner.as_str()
+    }
+}
+
+fn panic_hook(info: &panic::PanicInfo) {
+    // Try to handle &str/String payloads, which should handle 99% of cases.
+    let payload = info.payload();
+    let message = if let Some(s) = payload.downcast_ref::<&str>() {
+        s
+    } else if let Some(s) = payload.downcast_ref::<String>() {
+        s.as_str()
+    } else {
+        // Not the most helpful thing, but seems unlikely to happen
+        // in practice.
+        "Unhandled rust panic payload!"
+    };
+    let (filename, line) = if let Some(loc) = info.location() {
+        (loc.file(), loc.line())
+    } else {
+        ("unknown.rs", 0)
+    };
+    // Copy the message and filename to the stack in order to safely add
+    // a terminating nul character (since rust strings don't come with one
+    // and RustMozCrash wants one).
+    let message = ArrayCString::<[_; 512]>::from(message);
+    let filename = ArrayCString::<[_; 512]>::from(filename);
+    unsafe {
+        RustMozCrash(filename.as_ptr() as *const c_char, line as c_int,
+                 message.as_ptr() as *const c_char);
+    }
+}
+
+/// Configure a panic hook to redirect rust panics to MFBT's MOZ_Crash.
+#[no_mangle]
+pub extern "C" fn install_rust_panic_hook() {
+    panic::set_hook(Box::new(panic_hook));
+}
new file mode 100644
--- /dev/null
+++ b/mozglue/static/rust/wrappers.cpp
@@ -0,0 +1,13 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Types.h"
+
+// MOZ_Crash wrapper for use by rust, since MOZ_Crash is an inline function.
+extern "C" void RustMozCrash(const char* aFilename, int aLine,
+                             const char* aReason) {
+  MOZ_Crash(aFilename, aLine, aReason);
+}
--- a/testing/mozbase/mozcrash/mozcrash/mozcrash.py
+++ b/testing/mozbase/mozcrash/mozcrash/mozcrash.py
@@ -135,17 +135,17 @@ def log_crashes(logger,
         logger.crash(process=process, test=test, **kwargs)
     return crash_count
 
 
 # Function signatures of abort functions which should be ignored when
 # determining the appropriate frame for the crash signature.
 ABORT_SIGNATURES = (
     "Abort(char const*)",
-    "GeckoCrash",
+    "RustMozCrash",
     "NS_DebugBreak",
     # This signature is part of Rust panic stacks on some platforms. On
     # others, it includes a template parameter containing "core::panic::" and
     # is automatically filtered out by that pattern.
     "core::ops::function::Fn::call",
     "gkrust_shared::panic_hook",
     "intentional_panic",
     "mozalloc_abort",
--- a/toolkit/library/rust/shared/Cargo.toml
+++ b/toolkit/library/rust/shared/Cargo.toml
@@ -29,17 +29,16 @@ authenticator = "0.2.6"
 gkrust_utils = { path = "../../../../xpcom/rust/gkrust_utils" }
 rsdparsa_capi = { path = "../../../../media/webrtc/signaling/src/sdp/rsdparsa_capi" }
 xulstore = { path = "../../../components/xulstore", optional = true }
 # We have these to enforce common feature sets for said crates.
 log = {version = "0.4", features = ["release_max_level_info"]}
 env_logger = {version = "0.6", default-features = false} # disable `regex` to reduce code size
 cose-c = { version = "0.1.5" }
 jsrust_shared = { path = "../../../../js/src/rust/shared" }
-arrayvec = "0.4"
 cert_storage = { path = "../../../../security/manager/ssl/cert_storage", optional = true }
 bitsdownload = { path = "../../../components/bitsdownload", optional = true }
 storage = { path = "../../../../storage/rust" }
 bookmark_sync = { path = "../../../components/places/bookmark_sync", optional = true }
 shift_or_euc_c = "0.1.0"
 audio_thread_priority = "0.20.2"
 mdns_service = { path="../../../../media/mtransport/mdns_service", optional = true }
 neqo_glue = { path = "../../../../netwerk/socket/neqo_glue" }
--- a/toolkit/library/rust/shared/lib.rs
+++ b/toolkit/library/rust/shared/lib.rs
@@ -42,40 +42,35 @@ extern crate xulstore;
 extern crate jsrust_shared;
 #[cfg(feature = "bitsdownload")]
 extern crate bitsdownload;
 extern crate storage;
 #[cfg(feature = "moz_places")]
 extern crate bookmark_sync;
 extern crate shift_or_euc_c;
 
-extern crate arrayvec;
-
 extern crate audio_thread_priority;
 
 #[cfg(feature = "webrtc")]
 extern crate mdns_service;
 extern crate neqo_glue;
 
 #[cfg(feature = "wasm_library_sandboxing")]
 extern crate rlbox_lucet_sandbox;
 
 use std::boxed::Box;
 use std::env;
 use std::ffi::{CStr, CString};
 use std::os::raw::c_char;
+#[cfg(target_os = "android")]
 use std::os::raw::c_int;
 #[cfg(target_os = "android")]
 use log::Level;
 #[cfg(not(target_os = "android"))]
 use log::Log;
-use std::cmp;
-use std::panic;
-use std::ops::Deref;
-use arrayvec::{Array, ArrayString};
 
 extern "C" {
     fn gfx_critical_note(msg: *const c_char);
     #[cfg(target_os = "android")]
     fn __android_log_write(prio: c_int, tag: *const c_char, text: *const c_char) -> c_int;
 }
 
 struct GeckoLogger {
@@ -170,103 +165,16 @@ pub extern "C" fn GkRust_Shutdown() {
 }
 
 /// Used to implement `nsIDebug2::RustPanic` for testing purposes.
 #[no_mangle]
 pub extern "C" fn intentional_panic(message: *const c_char) {
     panic!("{}", unsafe { CStr::from_ptr(message) }.to_string_lossy());
 }
 
-extern "C" {
-    // We can't use MOZ_Crash directly because it may be weakly linked
-    // to libxul, and rust can't handle that.
-    fn GeckoCrash(filename: *const c_char, line: c_int, reason: *const c_char) -> !;
-}
-
-/// Truncate a string at the closest unicode character boundary
-/// ```
-/// assert_eq!(str_truncate_valid("éà", 3), "é");
-/// assert_eq!(str_truncate_valid("éà", 4), "éè");
-/// ```
-fn str_truncate_valid(s: &str, mut mid: usize) -> &str {
-    loop {
-        if let Some(res) = s.get(..mid) {
-            return res;
-        }
-        mid -= 1;
-    }
-}
-
-/// Similar to ArrayString, but with terminating nul character.
-#[derive(Debug, PartialEq)]
-struct ArrayCString<A: Array<Item = u8>> {
-    inner: ArrayString<A>,
-}
-
-impl<S: AsRef<str>, A: Array<Item = u8>> From<S> for ArrayCString<A> {
-    /// Contrary to ArrayString::from, truncates at the closest unicode
-    /// character boundary.
-    /// ```
-    /// assert_eq!(ArrayCString::<[_; 4]>::from("éà"),
-    ///            ArrayCString::<[_; 4]>::from("é"));
-    /// assert_eq!(&*ArrayCString::<[_; 4]>::from("éà"), "é\0");
-    /// ```
-    fn from(s: S) -> Self {
-        let s = s.as_ref();
-        let len = cmp::min(s.len(), A::capacity() - 1);
-        let mut result = Self {
-            inner: ArrayString::from(str_truncate_valid(s, len)).unwrap(),
-        };
-        result.inner.push('\0');
-        result
-    }
-}
-
-impl<A: Array<Item = u8>> Deref for ArrayCString<A> {
-    type Target = str;
-
-    fn deref(&self) -> &str {
-        self.inner.as_str()
-    }
-}
-
-fn panic_hook(info: &panic::PanicInfo) {
-    // Try to handle &str/String payloads, which should handle 99% of cases.
-    let payload = info.payload();
-    let message = if let Some(s) = payload.downcast_ref::<&str>() {
-        s
-    } else if let Some(s) = payload.downcast_ref::<String>() {
-        s.as_str()
-    } else {
-        // Not the most helpful thing, but seems unlikely to happen
-        // in practice.
-        "Unhandled rust panic payload!"
-    };
-    let (filename, line) = if let Some(loc) = info.location() {
-        (loc.file(), loc.line())
-    } else {
-        ("unknown.rs", 0)
-    };
-    // Copy the message and filename to the stack in order to safely add
-    // a terminating nul character (since rust strings don't come with one
-    // and GeckoCrash wants one).
-    let message = ArrayCString::<[_; 512]>::from(message);
-    let filename = ArrayCString::<[_; 512]>::from(filename);
-    unsafe {
-        GeckoCrash(filename.as_ptr() as *const c_char, line as c_int,
-                   message.as_ptr() as *const c_char);
-    }
-}
-
-/// Configure a panic hook to redirect rust panics to Gecko's MOZ_Crash.
-#[no_mangle]
-pub extern "C" fn install_rust_panic_hook() {
-    panic::set_hook(Box::new(panic_hook));
-}
-
 #[cfg(feature = "oom_with_hook")]
 mod oom_hook {
     use std::alloc::{Layout, set_alloc_error_hook};
 
     extern "C" {
         fn GeckoHandleOOM(size: usize) -> !;
     }
 
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -5092,22 +5092,16 @@ mozilla::BinPathType XRE_GetChildProcBin
       return BinPathType::PluginContainer;
   }
 }
 
 // Because rust doesn't handle weak symbols, this function wraps the weak
 // malloc_handle_oom for it.
 extern "C" void GeckoHandleOOM(size_t size) { mozalloc_handle_oom(size); }
 
-// Similarly, this wraps MOZ_Crash
-extern "C" void GeckoCrash(const char* aFilename, int aLine,
-                           const char* aReason) {
-  MOZ_Crash(aFilename, aLine, aReason);
-}
-
 // From toolkit/library/rust/shared/lib.rs
 extern "C" void install_rust_panic_hook();
 extern "C" void install_rust_oom_hook();
 
 struct InstallRustHooks {
   InstallRustHooks() {
     install_rust_panic_hook();
     install_rust_oom_hook();