mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-20 12:02:18 +02:00
bridge: Add support for arrays as arguments and return values
Specifically, adding support for *references to fixed-sized arrays* as arguments (pointer-to-fixed-size-array in C, byte[] in Java, Buffer in Node), and fixed-sized array values as results (out-pointer-to-fixed- sized-array in C, byte[] in Java, Buffer in Node). This will be used for some zkgroup primitive values.
This commit is contained in:
parent
f1da238532
commit
c5ba4ecf48
@ -39,7 +39,8 @@ ignore_this_warning = re.compile(
|
||||
"("
|
||||
r"WARN: Can't find .*\. This usually means that this type was incompatible or not found\.|"
|
||||
r"WARN: Missing `\[defines\]` entry for `feature = \".*\"` in cbindgen config\.|"
|
||||
r"WARN: Skip libsignal-bridge::_ - \(not `pub`\)\."
|
||||
r"WARN: Skip libsignal-bridge::_ - \(not `pub`\)\.|"
|
||||
r"WARN: Couldn't find path for Array\(Path\(GenericPath \{ .+ \}\), Name\(\"LEN\"\)\), skipping associated constants"
|
||||
")")
|
||||
|
||||
unknown_warning = False
|
||||
|
@ -39,6 +39,9 @@ def translate_to_ts(typ):
|
||||
if typ in type_map:
|
||||
return type_map[typ]
|
||||
|
||||
if typ.startswith('[u8;') or typ.startswith('&[u8;'):
|
||||
return 'Buffer'
|
||||
|
||||
if typ.startswith('&mutdyn'):
|
||||
return typ[7:]
|
||||
|
||||
|
@ -253,6 +253,21 @@ impl ResultTypeInfo for uuid::Uuid {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> SimpleArgTypeInfo for &'_ [u8; LEN] {
|
||||
type ArgType = *const [u8; LEN];
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
fn convert_from(arg: *const [u8; LEN]) -> SignalFfiResult<Self> {
|
||||
unsafe { arg.as_ref() }.ok_or(SignalFfiError::NullPointer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> ResultTypeInfo for [u8; LEN] {
|
||||
type ResultType = [u8; LEN];
|
||||
fn convert_into(self) -> SignalFfiResult<Self::ResultType> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! store {
|
||||
($name:ident) => {
|
||||
paste! {
|
||||
@ -519,6 +534,7 @@ macro_rules! ffi_arg_type {
|
||||
(Context) => (*mut libc::c_void);
|
||||
(Timestamp) => (u64);
|
||||
(Uuid) => (*const [u8; 16]);
|
||||
(&[u8; $len:expr]) => (*const [u8; $len]);
|
||||
(&[& $typ:ty]) => (*const *const $typ);
|
||||
(&mut dyn $typ:ty) => (*const paste!(ffi::[<Ffi $typ Struct>]));
|
||||
(& $typ:ty) => (*const $typ);
|
||||
@ -554,5 +570,6 @@ macro_rules! ffi_result_type {
|
||||
(Option<$typ:ty>) => (*mut $typ);
|
||||
(Timestamp) => (u64);
|
||||
(Uuid) => ([u8; 16]);
|
||||
([u8; $len:expr]) => ([u8; $len]);
|
||||
( $typ:ty ) => (*mut $typ);
|
||||
}
|
||||
|
@ -552,6 +552,36 @@ impl ResultTypeInfo for Option<Vec<u8>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'storage, 'context: 'storage, const LEN: usize> ArgTypeInfo<'storage, 'context>
|
||||
for &'storage [u8; LEN]
|
||||
{
|
||||
type ArgType = jbyteArray;
|
||||
type StoredType = AutoArray<'context, 'context, jbyte>;
|
||||
fn borrow(env: &'context JNIEnv, foreign: Self::ArgType) -> SignalJniResult<Self::StoredType> {
|
||||
Ok(env.get_byte_array_elements(foreign, ReleaseMode::NoCopyBack)?)
|
||||
}
|
||||
fn load_from(
|
||||
_env: &JNIEnv,
|
||||
stored: &'storage mut Self::StoredType,
|
||||
) -> SignalJniResult<&'storage [u8; LEN]> {
|
||||
unsafe { std::slice::from_raw_parts(stored.as_ptr() as *const u8, stored.size()? as usize) }
|
||||
.try_into()
|
||||
.map_err(|_| SignalJniError::DeserializationFailed(std::any::type_name::<[u8; LEN]>()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> ResultTypeInfo for [u8; LEN] {
|
||||
type ResultType = jbyteArray;
|
||||
fn convert_into(self, env: &JNIEnv) -> SignalJniResult<Self::ResultType> {
|
||||
self.as_ref().convert_into(env)
|
||||
}
|
||||
fn convert_into_jobject(signal_jni_result: &SignalJniResult<Self::ResultType>) -> JObject {
|
||||
signal_jni_result
|
||||
.as_ref()
|
||||
.map_or(JObject::null(), |&jobj| JObject::from(jobj))
|
||||
}
|
||||
}
|
||||
|
||||
impl ResultTypeInfo for uuid::Uuid {
|
||||
type ResultType = jobject;
|
||||
fn convert_into(self, env: &JNIEnv) -> SignalJniResult<Self::ResultType> {
|
||||
@ -864,6 +894,9 @@ macro_rules! jni_arg_type {
|
||||
(&mut [u8]) => {
|
||||
jni::jbyteArray
|
||||
};
|
||||
(&[u8; $len:expr]) => {
|
||||
jni::jbyteArray
|
||||
};
|
||||
(Context) => {
|
||||
jni::JObject
|
||||
};
|
||||
@ -953,6 +986,9 @@ macro_rules! jni_result_type {
|
||||
(Vec<u8>) => {
|
||||
jni::jbyteArray
|
||||
};
|
||||
([u8; $len:expr]) => {
|
||||
jni::jbyteArray
|
||||
};
|
||||
(Option<$typ:tt>) => {
|
||||
jni_result_type!($typ)
|
||||
};
|
||||
|
@ -24,6 +24,7 @@ pub enum SignalJniError {
|
||||
SignalCrypto(SignalCryptoError),
|
||||
Jni(jni::errors::Error),
|
||||
BadJniParameter(&'static str),
|
||||
DeserializationFailed(&'static str),
|
||||
UnexpectedJniResultType(&'static str, &'static str),
|
||||
NullHandle,
|
||||
IntegerOverflow(String),
|
||||
@ -46,6 +47,9 @@ impl fmt::Display for SignalJniError {
|
||||
SignalJniError::IntegerOverflow(m) => {
|
||||
write!(f, "integer overflow during conversion of {}", m)
|
||||
}
|
||||
SignalJniError::DeserializationFailed(ty) => {
|
||||
write!(f, "failed to deserialize {}", ty)
|
||||
}
|
||||
SignalJniError::HsmEnclave(e) => {
|
||||
write!(f, "{}", e)
|
||||
}
|
||||
|
@ -220,9 +220,8 @@ fn throw_error(env: &JNIEnv, error: SignalJniError) {
|
||||
SignalJniError::Signal(SignalProtocolError::InvalidArgument(_))
|
||||
| SignalJniError::SignalCrypto(SignalCryptoError::UnknownAlgorithm(_, _))
|
||||
| SignalJniError::SignalCrypto(SignalCryptoError::InvalidInputSize)
|
||||
| SignalJniError::SignalCrypto(SignalCryptoError::InvalidNonceSize) => {
|
||||
"java/lang/IllegalArgumentException"
|
||||
}
|
||||
| SignalJniError::SignalCrypto(SignalCryptoError::InvalidNonceSize)
|
||||
| SignalJniError::DeserializationFailed(_) => "java/lang/IllegalArgumentException",
|
||||
|
||||
SignalJniError::IntegerOverflow(_)
|
||||
| SignalJniError::Jni(_)
|
||||
|
@ -608,6 +608,39 @@ impl<'a> ResultTypeInfo<'a> for Vec<u8> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads from a JsBuffer, assuming it won't be mutated while in use.
|
||||
/// See [`AssumedImmutableBuffer`].
|
||||
impl<'storage, 'context: 'storage, const LEN: usize> ArgTypeInfo<'storage, 'context>
|
||||
for &'storage [u8; LEN]
|
||||
{
|
||||
type ArgType = JsBuffer;
|
||||
type StoredType = AssumedImmutableBuffer<'context>;
|
||||
fn borrow(
|
||||
cx: &mut FunctionContext,
|
||||
foreign: Handle<'context, Self::ArgType>,
|
||||
) -> NeonResult<Self::StoredType> {
|
||||
let result = AssumedImmutableBuffer::new(cx, foreign);
|
||||
if result.buffer.len() != LEN {
|
||||
cx.throw_error(format!(
|
||||
"buffer has incorrect length {} (expected {})",
|
||||
result.buffer.len(),
|
||||
LEN
|
||||
))?;
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
fn load_from(stored: &'storage mut Self::StoredType) -> Self {
|
||||
stored.buffer.try_into().expect("checked length already")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const LEN: usize> ResultTypeInfo<'a> for [u8; LEN] {
|
||||
type ResultType = JsBuffer;
|
||||
fn convert_into(self, cx: &mut impl Context<'a>) -> NeonResult<Handle<'a, Self::ResultType>> {
|
||||
self.as_ref().convert_into(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ResultTypeInfo<'a>> ResultTypeInfo<'a> for NeonResult<T> {
|
||||
type ResultType = T::ResultType;
|
||||
fn convert_into(self, cx: &mut impl Context<'a>) -> NeonResult<Handle<'a, Self::ResultType>> {
|
||||
|
Loading…
Reference in New Issue
Block a user