Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native Library loading rework #12

Merged
merged 7 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions ffi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,25 @@ compileJava {

task buildFfiBridge(type: Exec) {
workingDir projectDir
if (file("./ffi_build.sh").isFile()) {
commandLine 'sh', '-c', './ffi_build.sh'
if (file("./ffi_build.sh").isFile()) {
commandLine 'sh', '-c', './ffi_build.sh'
}
else {
// Enter the swig directory and make the 'build' target
commandLine 'make', '-C', 'swig', 'build'
}
}
compileJava.dependsOn buildFfiBridge

task cleanFfiBridge(type: Exec) {
workingDir projectDir
if (!file("./ffi_build.sh").isFile()) {
// Enter the swig directory and make the 'clean' target
commandLine 'make', '-C', 'swig', 'clean'
}
}
clean.dependsOn cleanFfiBridge

jar {
archiveClassifier = ''
archiveAppendix = 'ffi'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.antithesis.ffi.internal;

public interface CoverageHandler {

public long initializeModuleCoverage(long edgeCount, String symbolFilePath);

public void notifyModuleEdge(long edgePlusModule);
}
15 changes: 4 additions & 11 deletions ffi/src/main/java/com/antithesis/ffi/internal/FfiHandler.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package com.antithesis.ffi.internal;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.logging.Logger;

public class FfiHandler implements OutputHandler {
public class FfiHandler implements OutputHandler, CoverageHandler {

private static long offset = -1;

public static Optional<OutputHandler> get() {
try {
FfiWrapperJNI.loadLibrary();
if(FfiWrapperJNI.LOAD_LIBRARY_MARKER) {
return Optional.of(new FfiHandler());
} catch (Throwable e) {
return Optional.empty();
}
return Optional.empty();
}

@Override
Expand All @@ -39,15 +35,12 @@ public long initializeModuleCoverage(long edgeCount, String symbolFilePath) {
}
offset = FfiWrapperJNI.init_coverage_module(edgeCount, symbolFilePath);
String msg = String.format("Initialized Java module at offset 0x%016x with %d edges; symbol file %s", offset, edgeCount, symbolFilePath);
// TODO: (@shomik) logger.info(msg);
System.out.println(msg);
return offset;
}

@Override
public void notifyModuleEdge(long edgePlusModule) {
// Right now, the Java implementation defers completely to the native library.
// See instrumentation.h to understand the logic here. The shim (i.e. StaticModule.java)
// is responsible for handling the return value.
FfiWrapperJNI.notify_coverage(edgePlusModule);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,5 @@ public interface OutputHandler {
void output(String value);

long random();

long initializeModuleCoverage(long edgeCount, String symbolFilePath);

void notifyModuleEdge(long edgePlusModule);
}

27 changes: 17 additions & 10 deletions ffi/swig/FfiWrapper.i
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,19 @@ import java.nio.file.StandardCopyOption;
%}

%pragma(java) jniclasscode=%{


private static final String NATIVE_LIBRARY_PATH = "/usr/lib/libvoidstar.so";

public static boolean hasNativeLibrary() {
return Files.exists(Paths.get(NATIVE_LIBRARY_PATH));
}

public static void loadLibrary() throws IOException {
try {
if (hasNativeLibrary()) {
// Static variables initialization is guaranteed to execute by the Java Language Spec
public static boolean LOAD_LIBRARY_MARKER = loadLibrary();

private static boolean loadLibrary() {
boolean nativeLibraryFound = hasNativeLibrary();
if (nativeLibraryFound) {
try {
System.load(NATIVE_LIBRARY_PATH);
File file = File.createTempFile("libFfiWrapper", ".so");
try (InputStream link = (Thread.currentThread().getContextClassLoader().getResourceAsStream("libFfiWrapper.so"))){
Expand All @@ -50,13 +52,18 @@ import java.nio.file.StandardCopyOption;
StandardCopyOption.REPLACE_EXISTING);
System.load(file.getAbsoluteFile().toString());
}
} else {
throw new RuntimeException("Native code library failed to load");
} catch (UnsatisfiedLinkError e) {
System.err.println("Failed to load a native library:" + e);
return false;
} catch (IOException e) {
System.err.println("Failed to load FFI wrapper from resources:" + e);
return false;
} catch (Exception e) {
System.err.println("Unexpected error: " + e);
return false;
}
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
throw e;
}
return nativeLibraryFound;
}
%}

Expand Down
4 changes: 2 additions & 2 deletions ffi/swig/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
build:
build:
# Generate java and .c files needed for JNI
swig -java -package com.antithesis.ffi.internal FfiWrapper.i

Expand All @@ -12,7 +12,7 @@ build:
# ldd will fail to resolve this outside of the Antithesis runtime environment
# libFfiWrapper is only loaded if libvoidstar is successfully
# loaded first.
patchelf --add-needed libvoidstar.so ./libFfiWrapper.so
patchelf --add-needed /usr/lib/libvoidstar.so ./libFfiWrapper.so

# Move the wrapper into a folder so it can be added into the target jar
mkdir -p ../src/main/resources
Expand Down
2 changes: 1 addition & 1 deletion sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ dependencies {
if (file("libs/antithesis-ffi-${project.version}.jar").isFile()) {
implementation(files("libs/antithesis-ffi-${project.version}.jar"))
} else {
implementation(project(":ffi"))
implementation(project(":ffi"))
}

// Use JUnit Jupiter for testing.
Expand Down
17 changes: 0 additions & 17 deletions sdk/src/main/java/com/antithesis/sdk/internal/HandlerFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,6 @@ public long random() {
return new Random().nextLong();
}

@Override
public long initializeModuleCoverage(long edgeCount, String symbolFilePath) {
return edgeCount;
}

@Override
public void notifyModuleEdge(long edgePlusModule) {
}
}

private static class LocalHandler implements OutputHandler {
Expand Down Expand Up @@ -102,7 +94,6 @@ public void output(final String value) {
writer.write("\n");
writer.flush();
} catch (IOException ignored) {
// TODO (@shomik) logging
}
}

Expand All @@ -111,14 +102,6 @@ public long random() {
return new Random().nextLong();
}

@Override
public long initializeModuleCoverage(long edgeCount, String symbolFilePath) {
return 0;
}

@Override
public void notifyModuleEdge(long edgePlusModule) {
}
}

}
7 changes: 0 additions & 7 deletions sdk/src/main/java/com/antithesis/sdk/internal/Internal.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,4 @@ public static void dispatchOutput(final ObjectNode s) {
}
}

public static long dispatchInitializeModuleCoverage(long edgeCount, String symbolFilePath) {
return HandlerFactory.get().initializeModuleCoverage(edgeCount, symbolFilePath);
}

public static void dispatchNotifyModuleEdge(long edgePlusModule) {
HandlerFactory.get().notifyModuleEdge(edgePlusModule);
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,29 @@
package com.antithesis.sdk.internal;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import com.antithesis.ffi.internal.FfiWrapperJNI;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.Test;

import com.antithesis.ffi.internal.FfiWrapperJNI;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

public class InstrumentationTest {
@Test
void testRandom() {
assumeTrue(FfiWrapperJNI.hasNativeLibrary());
try {
FfiWrapperJNI.loadLibrary();
} catch (Throwable e) {
fail("Unable to load native library");
}
assumeTrue(FfiWrapperJNI.LOAD_LIBRARY_MARKER);
FfiWrapperJNI.fuzz_get_random();
}

@Test
void testJsonData() {
assumeTrue(FfiWrapperJNI.hasNativeLibrary());
assumeTrue(FfiWrapperJNI.LOAD_LIBRARY_MARKER);

ObjectMapper mapper = new ObjectMapper();
ObjectNode jsonNode = mapper.createObjectNode();
jsonNode.put("hello", "world");

try {
FfiWrapperJNI.loadLibrary();
} catch (Throwable e) {
fail("Unable to load native library");
}
String theString = "";
try {
theString = mapper.writeValueAsString(jsonNode);
Expand All @@ -45,12 +35,7 @@ void testJsonData() {

@Test
void testFlush() {
assumeTrue(FfiWrapperJNI.hasNativeLibrary());
try {
FfiWrapperJNI.loadLibrary();
} catch (Throwable e) {
fail("Unable to load native library");
}
assumeTrue(FfiWrapperJNI.LOAD_LIBRARY_MARKER);
FfiWrapperJNI.fuzz_flush();
}
}
Loading