Skip to content
Snippets Groups Projects
Unverified Commit 7000ea2f authored by Tiago Quelhas's avatar Tiago Quelhas Committed by GitHub
Browse files

[7.1.0] Treat the inability to load the Windows filesystem JNI as an error. (#21090)

Unlike on Unix, we can't fall back to an alternative implementation.
Failure to emit an early error would cause later native method calls to
produce a less informative error message.

See https://github.com/bazelbuild/bazel/issues/20677 for a recent
example where this would have been helpful.

Also note some minor changes:
* Since we attempt to load the JNI in two different ways, make sure to
propagate both exceptions (one suppressed by the other).
* The default switch case is unnecessary, as errorprone already enforces
exhaustiveness.

PiperOrigin-RevId: 595206761
Change-Id: I4b6258d59d9a4fcc9f83418375acc51a32d7f4a4
parent b10e3c25
No related merge requests found
......@@ -75,6 +75,17 @@ public class BazelFileSystemModule extends BlazeModule {
FileSystem fs;
if (OS.getCurrent() == OS.WINDOWS) {
if (!JniLoader.isJniAvailable()) {
Throwable e = checkNotNull(JniLoader.getJniLoadError());
throw new AbruptExitException(
DetailedExitCode.of(
FailureDetail.newBuilder()
.setMessage(Strings.nullToEmpty(e.getMessage()))
.setFilesystem(
Filesystem.newBuilder().setCode(Code.FILESYSTEM_JNI_NOT_AVAILABLE))
.build()),
e);
}
fs = new WindowsFileSystem(digestHashFunction, options.enableWindowsSymlinks);
} else {
if (JniLoader.isJniAvailable()) {
......
......@@ -30,5 +30,6 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/util:os",
"//third_party:flogger",
"//third_party:guava",
"//third_party:jsr305",
],
)
......@@ -25,16 +25,17 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.annotation.Nullable;
/** Generic code to interact with the platform-specific JNI code bundle. */
public final class JniLoader {
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
private static final boolean JNI_AVAILABLE;
@Nullable private static final Throwable JNI_LOAD_ERROR;
static {
boolean jniAvailable;
Throwable jniLoadError;
try {
switch (OS.getCurrent()) {
case LINUX:
......@@ -59,21 +60,18 @@ public final class JniLoader {
try {
loadLibrary("main/native/windows/windows_jni.dll");
} catch (IOException e2) {
logger.atWarning().withCause(e2).log("Failed to load JNI library from resource");
throw e;
e2.addSuppressed(e);
throw e2;
}
}
break;
default:
throw new AssertionError("switch statement out of sync with OS values");
}
jniAvailable = true;
jniLoadError = null;
} catch (IOException | UnsatisfiedLinkError e) {
logger.atWarning().withCause(e).log("Failed to load JNI library");
jniAvailable = false;
jniLoadError = e;
}
JNI_AVAILABLE = jniAvailable;
JNI_LOAD_ERROR = jniLoadError;
}
/**
......@@ -131,22 +129,28 @@ public final class JniLoader {
}
}
protected JniLoader() {}
private JniLoader() {}
/**
* Triggers the load of the JNI bundle in a platform-independent basis.
*
* <p>This does <b>not</b> fail if the JNI bundle cannot be loaded because there are scenarios in
* which we want to run Bazel without JNI (e.g. during bootstrapping). We rely on the fact that
* any calls to native code will fail anyway and with a more descriptive error message if we
* failed to load the JNI bundle.
* which we want to run Bazel without JNI (e.g. during bootstrapping) or are able to fall back to
* an alternative implementation (e.g. in some filesystem implementations).
*
* <p>Callers can check if the JNI bundle load succeeded by calling {@link #isJniAvailable()}.
* <p>Callers can check if the JNI bundle was successfully loaded via {@link #isJniAvailable()}
* and obtain the load error via {@link #getJniLoadError()}.
*/
public static void loadJni() {}
/** Checks whether the JNI bundle was successfully loaded or not. */
/** Returns whether the JNI bundle was successfully loaded. */
public static boolean isJniAvailable() {
return JNI_AVAILABLE;
return JNI_LOAD_ERROR == null;
}
/** Returns the exception thrown while loading the JNI bundle, if it failed. */
@Nullable
public static Throwable getJniLoadError() {
return JNI_LOAD_ERROR;
}
}
......@@ -502,6 +502,7 @@ message Filesystem {
SERVER_FILE_WRITE_FAILURE = 5 [(metadata) = { exit_code: 36 }];
DEFAULT_DIGEST_HASH_FUNCTION_INVALID_VALUE = 6
[(metadata) = { exit_code: 2 }];
FILESYSTEM_JNI_NOT_AVAILABLE = 8 [(metadata) = { exit_code: 36 }];
reserved 7; // For internal use
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment