Code Monkey home page Code Monkey logo

jni-sys's Introduction

Build Status Docs Crates.io

JNI Bindings for Rust

Join the chat at https://gitter.im/jni-rs/Lobby

This project provides complete JNI bindings for Rust, allowing to:

  • Implement native Java methods for JVM and Android in Rust
  • Call Java code from Rust
  • Embed JVM in Rust applications and use any Java libraries

See the docs for more details.

Example

cd example
make

Contribution

See the Contribution Guide for details.

License

Licensed under either of

at your option.

jni-sys's People

Contributors

jrobsonchase avatar kud1ing avatar marschall avatar rib avatar robmv avatar sfackler avatar stanislav-tkach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jni-sys's Issues

Considering redefining `jboolean` as either an `bool` or our own `#[repr(u8)]` enum

While looking at jni-rs/jni-rs#400 it was noted that there's a risk that code can easily cause undefined behaviour for the JVM by setting boolean array elements to values other than 0 or 1.

This isn't something that's specific to array elements though; anywhere that Rust returns a jboolean to Java it needs to ensure the byte value is either 0 or 1.

Since jboolean is currently simply an alias for u8 (pub type jboolean = u8;) then it's very easy to return arbitrary invalid boolean values to the JVM.

My initial thought was that we could represent a jboolean as:

#[repr(u8)]
enum jboolean {
    False=0,
    True=1
}

and it was then also noted by @argv-minus-one that this is essentially how the Rust Reference defines bool: https://doc.rust-lang.org/reference/types/boolean.html

My initial reservation with simply defining jboolean as an alias for bool is that Rust doesn't generally guarantee much in terms of stable ABI and I wouldn't like to potentially depending on an implementation detail. e.g. the Rust Reference says "this book is not normative. It may include details that are specific to rustc itself, and should not be taken as a specification for the Rust language."

It looks like historically bool was assumed to be defined in terms of the C _Bool type (and several FFI projects have made that assumption) which wouldn't technically guarantee that bool were one byte on all platforms, ref: https://internals.rust-lang.org/t/rusts-stability-story-should-apply-to-bool-in-ffi/6305/8

Considering the follow up discussion here: rust-lang/rust#46176 it looks like the consensus was that bool is defined to be the same as C's _Bool but it was also noted that that means it's one byte one all platforms supported by Rust.

A bool is also explicitly documented as being one byte here: https://doc.rust-lang.org/std/mem/fn.size_of.html

I think it's fair to conclude that Rust's bool type is basically guaranteed to always be 1 byte and to also use the values 1 and 0 for true and false - which is what we want for jboolean

Alternative implementation

I was toying with my own bindings to jni.h for an Android project, but I'm probably not going to finish it. Maybe it will be useful to you. Everything related to the exported JNI_* functions is missing, because Android doesn't provide them. But they shouldn't be any different than what's in this crate already.

https://gist.github.com/docbrown/2b3ca251cc706975750e9d69a2724328

The main differences are:

  1. The binding follows the C++ API more than the C API, just because it's safer type-wise. In the current jni_sys crate, reference types are just aliases of jobject. This means you can accidentally pass a jstring to a function expecting a jarray, for example, and the compiler won't complain. In my implementation, each reference type gets its own distinct underlying type and conversions must be done explicitly. There's probably a way to get some of the types to coerce to their base types (jarray to jobject, for example) without a cast, as in C++, but I didn't get that far.

  2. #[repr(C)] enum is not exactly C-compatible and it can lead to undefined behavior. So, jobjectRefType is just a C-compatible type alias and its values are module-level consts. This is what the winapi crate does and it more closely matches the original API anyway (you don't have to qualify each value with jobjectRefType::).

  3. A macro is used to generate JNIEnv and JavaVM. It also generates wrapper methods like those in the C++ API. It skips generating wrapper methods for variadic functions, although they are still defined in the v-table. I left out the *V variants because the definition of va_list varies by platform and I didn't think it was worth implementing. Unfortunately, the macro requires quite a bit of recursion and is rather slow. I'm sure there are ways to make it more efficient, though.

  4. The function pointers aren't wrapped in Option<T>. Since this is a -sys crate, favoring zero-overhead versus safety is better, in my opinion. A higher-level API can always check each pointer if it wishes, but otherwise it should be assumed that anyone using a -sys crate already knows what they're doing and won't, for example, call GetObjectRefType in a JNI 1.2 environment.

More header bindings?

Could this crate be extended to cover more java headers?

classfile_constants
jawt
jdwp
jmm
jvm
jvmti
jvmticmlr

jboolean as bool

Hello,

It's more a question than an issue but why the jboolean value isn't considered as a bool ?
My concern is that I wanted to convert a Vec via Robusta to ArrayList but u8 are considered Boolean.

Thanks

JNI_GetCreatedJavaVMs

When using this i get linker errors.

The code which i used

        let mut jvm = null_mut();
        let mut found:jsize = 0;
        let mut jvm_worky = jni::sys::JNI_GetCreatedJavaVMs( &mut jvm,1,&mut found);
error

error: linking with link.exe failed: exit code: 1120
|
= note: "E:\Applications\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\bin\HostX64\x64\link.exe" "/DEF:C:\Users\Luna\AppData\Local\Temp\rustc2LoRkl\lib.def" "/NOLOGO" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.1byzs9aaoeboij1f.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.23idsa2h5m4re0n7.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.2u6h2lnoz1tkqhvf.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.3tbrj5df0601ijj4.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.3wjcuz3qbx2gbnyl.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.3x2g0e2hwqmehtp8.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.57k2cudsxfgkp4pr.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.6b40e381e4fagx6.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.az2bwusxx6ld47f.rcgu.o" "X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.3q890reoho8keq5z.rcgu.o" "/LIBPATH:X:\meta\dev\rust\Shimakaze\target\debug\deps" "/LIBPATH:X:\meta\dev\rust\Shimakaze\target\debug\build\libudis86-sys-cf96a0ee695f5f98\out" "/LIBPATH:C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libwinapi-bb0ca2babfa2b4a5.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libjni-1de0fc098823e7b5.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libcesu8-a7f08aae99a2104d.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\liblog-97e4acb7b95be317.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libcfg_if-b01931459ea167fc.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libcombine-cbc02205a55fd8f3.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libmemchr-665d2c8c4b4cfe12.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libbytes-49090a364b4888f6.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libthiserror-500c731b3379430b.rlib" "X:\meta\dev\rust\Shimakaze\target\debug\deps\libjni_sys-dd815645ea921445.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libstd-2915a6598b644f05.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libpanic_unwind-600ba5171389b19e.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libstd_detect-9551a16e5791cc07.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_demangle-9accc95c56c66c72.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libhashbrown-174e0bf43a687c69.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_std_workspace_alloc-c67793bd74cdc09e.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libunwind-f28b8bbd63ca4a61.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcfg_if-4242b0a6ddf9db60.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\liblibc-5c6e234e3431724c.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\liballoc-ef0d43e84d25019c.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_std_workspace_core-665ed95809278e59.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcore-c2100e40c13f915d.rlib" "C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcompiler_builtins-9fa99e8814512f70.rlib" "advapi32.lib" "cfgmgr32.lib" "gdi32.lib" "kernel32.lib" "msimg32.lib" "opengl32.lib" "user32.lib" "winspool.lib" "kernel32.lib" "ws2_32.lib" "bcrypt.lib" "advapi32.lib" "userenv.lib" "kernel32.lib" "msvcrt.lib" "/NXCOMPAT" "/LIBPATH:C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib" "/OUT:X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.dll" "/OPT:REF,NOICF" "/DLL" "/IMPLIB:X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.dll.lib" "/DEBUG" "/NATVIS:C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\etc\intrinsic.natvis" "/NATVIS:C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\etc\liballoc.natvis" "/NATVIS:C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\etc\libcore.natvis" "/NATVIS:C:\Users\Luna\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\etc\libstd.natvis"
= note: Creating library X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.dll.lib and object X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.dll.exp
Shimakaze.23idsa2h5m4re0n7.rcgu.o : error LNK2019: unresolved external symbol JNI_GetCreatedJavaVMs referenced in function _ZN9Shimakaze10dll_attach17h80d4ba29a706405fE
X:\meta\dev\rust\Shimakaze\target\debug\deps\Shimakaze.dll : fatal error LNK1120: 1 unresolved externals

Build issues on macOS on Java 9+

I have trouble building the project on macOS on Java 9+.

The issue is that libjvm.dylib has been moved from ${JAVA_HOME}/jre/lib/server to ${JAVA_HOME}/lib/server

On my system it looks like this:

/Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/lib/server/libjvm.dylib
/Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home/lib/server/libjvm.dylib
/Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/lib/server/libjvm.dylib
/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/server/libjvm.dylib
/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/server/libjvm.dylib

/Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/include/jni.h
/Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home/include/jni.h
/Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/include/jni.h
/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/include/jni.h
/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/include/jni.h

No comments

I noticed none of the functions have any comments. I wonder wether that is because you simply didn't get around to do it or because of licensing concerns over the specification.

The only comments for JNI functions I could find are https://docs.oracle.com/en/java/javase/11/docs/specs/jni/index.html where on the bottom it says

Copyright © 1993, 2017, Oracle and/or its affiliates. All rights reserved.

Can we consider moving this into the `jni-rs` repo

Hi @sfackler,

I was hoping we might be able to discuss this issue: jni-rs/jni-rs#407

While working on the jni crate there have been few things recently where I've wanted to be able consider jni-sys changes and I think it would also be easier / helpful if jni-sys were actually integrated in the same repo as the jni crate so any changes could be synchronized too.

Two recent issues / discussions that come to mind here are:

  1. jni-rs/jni-rs#360 (wanting to ensure all jni types implement the Debug trait)
  2. #19 (wanting to update the definition of jboolean to ensure we can only store the values 1 or 0 for true and false.)

Although the jni-sys crate doesn't generally need much attention since the JNI spec is pretty stable there are probably other small housekeeping things like migrating from Travis CI to github actions that could also be beneficial for the project.

If you have a moment, I wonder if you could say whether you'd be ok with jni-sys being merged into a common repo with the jni crate?

This would also imply enabling me and other jni-rs maintainers to be able to make releases of the jni-sys crate, if you'd be ok with that.

I'd be happy to add you as a member to the jni-rs org too.

Making co-existing jni-sys wrappers as safe as possible

While building duchess we found a data race in the OpenJDK implementation of JNI_GetCreatedJavaVMs. When called concurrently with JNI_CreateJavaVM, JNI_GetCreatedJavaVMs might return pointers to partially-initialized JVMs (OpenJDK bug), which then causes segmentation faults.

The naive fix for duchess and any other library that aims to provide a safe Rust API around jni-sys is to use a mutex to synchronize calls to JNI_CreateJavaVM and JNI_GetCreatedJavaVMs. However, if each library has its own mutex, the overall Rust API is still technically unsound because one application might depend on multiple such libraries (or different versions of the same library), each making calls to JNI_CreateJavaVM and JNI_GetCreatedJavaVMs that are effectively unsynchronized.

We were discussing how to make co-existing JNI libraries (e.g. jni, j4rs, duchess) as safe as possible. Adding something to jni-sys seems a good approach, because jni-sys is used by all such libraries. Two options are:

  • Option A: Add a "start the JVM safely" mechanism to jni-sys.
  • Option B: Add a global Mutex<()> to jni-sys, leaving to the safe JNI libraries the duty of properly syncronizing the JNI calls that are (due to bugs or by design) thread-unsafe.

Option A requires more code in jni-sys; option B requires less code in jni-sys but more in the safe JNI libraries. Both options assume that all safe JNI libraries will use the same jni-sys version. I don't know if there is a way to enforce that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.