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

Essential fixes for EVMC Java bindings #532

Closed
wants to merge 2 commits into from

Conversation

atoulme
Copy link
Collaborator

@atoulme atoulme commented Aug 3, 2020

A set of critical fixes for the Java bindings, removing the cruft of other fixes I added elsewhere.

@atoulme atoulme force-pushed the evmc_java_fixes branch 4 times, most recently from 35150cb to 0c9eb8e Compare August 3, 2020 06:10
@atoulme atoulme requested a review from jrhea August 3, 2020 06:25
bindings/java/c/host.c Outdated Show resolved Hide resolved
@atoulme atoulme mentioned this pull request Aug 3, 2020
bindings/java/c/host.c Outdated Show resolved Hide resolved
bindings/java/c/host.c Outdated Show resolved Hide resolved
bindings/java/c/host.c Outdated Show resolved Hide resolved
bindings/java/c/host.c Outdated Show resolved Hide resolved
bindings/java/c/host.c Outdated Show resolved Hide resolved
bindings/java/c/host.c Outdated Show resolved Hide resolved
bindings/java/c/host.c Outdated Show resolved Hide resolved
bindings/java/c/host.c Outdated Show resolved Hide resolved
bindings/java/c/evmc-vm.c Outdated Show resolved Hide resolved
bindings/java/c/host.c Outdated Show resolved Hide resolved
Copy link
Collaborator

@jrhea jrhea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job. A few comments:

  • you found that the call to ReleaseByteArrayElements() in get_balance_fn() segfaults. I would think that get_code_hash_fn() and copy_code_fn() would have a similar problem.

  • wdyt about opening an issue for better code coverage? if my initial unit tests were more complete, then 👆 would have been caught sooner, right?

  • small nit about removing DEBUG printouts (not really my call though)

@atoulme
Copy link
Collaborator Author

atoulme commented Aug 4, 2020

you found that the call to ReleaseByteArrayElements() in get_balance_fn() segfaults. I would think that get_code_hash_fn() and copy_code_fn() would have a similar problem.

Somehow that doesn't affect that code. Not sure why.

wdyt about opening an issue for better code coverage? if my initial unit tests were more complete, then 👆 would have been caught sooner, right?

I have a second PR with all EVM reference tests.

small nit about removing DEBUG printouts (not really my call though)

I can remove.

@atoulme
Copy link
Collaborator Author

atoulme commented Aug 4, 2020

debug prints are removed.

In the next PR I run all VM tests and remove other ReleaseByteArrayElements calls - speeding up the tests. No memory problems seen.

@atoulme atoulme requested a review from chfast August 4, 2020 08:08
Copy link
Collaborator

@jrhea jrhea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm

@axic
Copy link
Member

axic commented Aug 10, 2020

I'm sorry folks it will take a bit longer for us to do a review, a bit busy on a different project.

@chfast chfast changed the title Essential fixes for EVMc Java bindings Essential fixes for EVMC Java bindings Sep 23, 2020
@@ -77,7 +77,7 @@ static ByteBuffer copy_code(int context_index, byte[] address, int code_offset)
"HostContext does not exist for context_index: " + context_index);
byte[] code = context.getCode(address).array();

if (code != null && code_offset > 0 && code_offset < code.length) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change still relevant? It seems to have been missed in #535.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right - I can't remember if that change is required. I left it out. It doesn't hurt to check for those.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I remember now. The code can never be null, since it's a byte array extracted from a ByteBuffer object. The code_offset > 0 should be removed imo since none of the other host impls check for that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code_offset can be 0.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this entire copy_code_fn and it's Java counterpart is broken. It never copies anything back, that's also why the FIXME for buffer_size is there.

I suggest this is fixed independently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest this is left to be done in #545.

// load so containing the jni bindings to evmc
System.load(System.getProperty("user.dir") + "/../c/build/lib/libevmc-java.so");
EvmcVm.isEvmcLibraryLoaded = true;
} catch (UnsatisfiedLinkError e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't System.load still emit this exception? Shouldn't create specify throws Exception?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

System.load does not throw this exception explicitly, so it doesn't have to be caught there. It can be caught by the code creating the EVM to try different paths in succession. The current code would run System.exit(1) if the lib was not found, which is a big problem if you're trying different paths.

Note also System.load is idempotent, so there's no need to check if it's loaded or not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exceptions are documented in the Javadoc but not in the signature of the method.

@atoulme
Copy link
Collaborator Author

atoulme commented Sep 30, 2020

Ready for another look.

@axic axic force-pushed the evmc_java_fixes branch 2 times, most recently from b4b447b to a2bb261 Compare September 30, 2020 09:33
evmcVm = new EvmcVm(filename);
}
return evmcVm;
public static EvmcVm create(String evmcPath, String filename) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we following the old pattern of calling load once statically?

public final class EvmcVm {
   static {
      System.loadLibrary("libevmc.so");
   }

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Say you do this - this means the static block runs at the time the class is loaded.
That means less control as to when you perform the load. If the static block throws, the class can never be loaded.
A behavior I have seen in Java is this:
https://www.adamh.cz/blog/2012/12/how-to-load-native-jni-library-from-jar/
Basically, your java jar ships with the so/dylib/dll file embedded. On startup, it copies the file out to a temp directory. Then it loads from it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly that seems to be the best approach. libemvc-java.so is not something the user should supply or load multiple times, it is the binding.

@@ -146,7 +146,8 @@ static synchronized int addContext(HostContext context) {
}

static void removeContext(int index) {
contextList.remove(index);
HostContext context = contextList.remove(index);
context.close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not mark HostContext as AutoCloseable and then this is a given?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AutoCloseable allows you to write syntactic sugar in java with the try-with-resources approach:
https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

Doesn't really apply here. Also that close method of AutoCloseable throws an Exception in its signature, so you'd have to deal with a try/catch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually after #548 this is not needed.

}
return evmcVm;
public static EvmcVm create(String evmcPath, String filename) {
System.load(evmcPath);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is a bad idea to keep reloading this. I'd imagine that messes up the bound addresses and may result in a crash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants