tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

java_asserts.md (2879B)


Java Asserts in Chromium

This doc exists to explain how asserts in Java are enabled and disabled by Chromium's build system.

javac Assertion Bytecode

Whenever javac compiles a Java class, assertions are transformed into the following bytecode:

    Code:
       0: getstatic     #2            // Static field $assertionsDisabled
       3: ifne          20            // Conditional jump past assertion throw
      12: new           #3            // Class java/lang/AssertionError
      19: athrow                      // Throwing AssertionError
      20: return

// NOTE: this static block was made just to check the desiredAssertionStatus.
// There was no static block on the class before javac created one.
  static {};
    Code:
       2: invokevirtual #6            // Method java/lang/Class.desiredAssertionStatus()
       5: ifne          12
       8: iconst_1
       9: goto          13
      12: iconst_0
      13: putstatic     #2            // Static field $assertionsDisabled
      16: return

TL;DR - every single assertion is gated behind a assertionDisabled flag check, which is a static field that can be set by the JRE's setDefaultAssertionStatus, setPackageAssertionStatus, and setClassAssertionStatus methods.

Assertion Enabling/Disabling

Our tools which consume javac output, namely R8 and D8, each have flags which the build system uses to enable or disable asserts. We control this with the enable_java_asserts gn arg. It does this by deleting the gating check on assertionsDisabled when enabling, and by eliminating any reference to the assert when disabling.

// Example equivalents of:
a = foo();
assert a != 0;
return a;

// Traditional, unoptimized javac output.
a = foo();
if (!assertionsDisabled && a == 0) {
  throw new AssertionError();
}
return a;

// Optimized with assertions enabled.
a = foo();
if (a == 0) {
  throw new AssertionError();
}
return a;

// Optimized with assertions disabled.
a = foo();
return a;

Assertion Enabling on Canary

Recently we [enabled asserts](https://chromium-review.googlesource.com/c/chromium/src/+/3307087) on Canary. It spiked our crash rate, and it was decided to not do this again, as it's bad user experience to crash the app incessantly for non-fatal issues.

So, we asked the R8 team for a feature which would rewrite the bytecode of these assertions, which they implemented for us. Now, instead of just turning it on and throwing an AssertionError, [R8 would call a provided assertion handler](https://r8.googlesource.com/r8/+/aefe7bc18a7ce19f3e9c6dac0bedf6d182bbe142/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java#124) with the AssertionError. We then wrote a [silent assertion reporter](https://chromium-review.googlesource.com/c/chromium/src/+/3746261) and this reports Java AssertionErrors to our crash server without crashing the browser.