When our app is getting a lot of traffic trough JNI (hundreds of elements) seems like we are getting a lot of heap corruption errors (seems like it happens more for bigger elements).
abort 0x0000007e32cdf360
art::Runtime::Abort(char const*) 0x0000007daf4c22ac
android::base::LogMessage::~LogMessage() 0x0000007e33a6a654
art::gc::Verification::LogHeapCorruption(art::ObjPtr<art::mirror::Object>, art::MemberOffset, art::mirror::Object*, bool) const 0x0000007daf298318
art::gc::collector::ConcurrentCopying::MarkNonMoving(art::Thread*, art::mirror::Object*, art::mirror::Object*, art::MemberOffset) 0x0000007daf226b98
art::gc::collector::ConcurrentCopying::ThreadFlipVisitor::VisitRoots(art::mirror::CompressedReference<art::mirror::Object>**, unsigned long, art::RootInfo const&) 0x0000007daf22909c
art::Thread::HandleScopeVisitRoots(art::RootVisitor*, int) 0x0000007daf50af7c
void art::Thread::VisitRoots<false>(art::RootVisitor*) 0x0000007daf50e840
art::gc::collector::ConcurrentCopying::ThreadFlipVisitor::Run(art::Thread*) 0x0000007daf22870c
art::(anonymous namespace)::CheckJNI::ReleasePrimitiveArrayElements(char const*, art::Primitive::Type, _JNIEnv*, _jarray*, void*, int) 0x0000007daf37c680
Java_org_libsodium_jni_SodiumJNI_crypto_1aead_1xchacha20poly1305_1ietf_1decrypt sodium-jni.c:156
art_quick_generic_jni_trampoline 0x0000007daf148354
<unknown> 0x000000009d05bbe8
Seems like the line causing the is located here (our code is open source) https://github.com/standardnotes/react-native-sodium/blob/367b61a90180fe75ddef5b599e01c47cb4761b1f/android/src/main/cpp/sodium-jni.c#L156. I've tried to debug this more but my JNI + cpp knowledge is limited. Do you have any tips for exchanging data from Java to C++ in a better way?
Code snippet:
JNIEXPORT jint JNICALL
Java_org_libsodium_jni_SodiumJNI_crypto_1aead_1xchacha20poly1305_1ietf_1decrypt(JNIEnv *jenv,
jclass clazz,
jbyteArray j_m,
jintArray j_mlen_p,
jbyteArray j_nsec,
jbyteArray j_c,
jint j_clen,
jbyteArray j_ad,
jint j_adlen,
jbyteArray j_npub,
jbyteArray j_k) {
unsigned char *c = as_unsigned_char_array(jenv, j_c);
unsigned char *m = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_m, 0);
unsigned char *npub = as_unsigned_char_array(jenv, j_npub);
unsigned char *ad = as_unsigned_char_array(jenv, j_ad);
unsigned char *nsec = as_unsigned_char_array(jenv, j_nsec);
unsigned char *k = as_unsigned_char_array(jenv, j_k);
int result = crypto_aead_xchacha20poly1305_ietf_decrypt(m, j_mlen_p, nsec, c, j_clen, ad, j_adlen, npub, k);
(*jenv)->ReleaseByteArrayElements(jenv, j_m, (jbyte *) m, 0);
return (jint)result;
}
Calling from java:
@ReactMethod
public void crypto_aead_xchacha20poly1305_ietf_decrypt(final String cipherText, final String public_nonce, final String key, final String additionalData, final Promise p) {
try {
byte[] c = this.base64ToBin(cipherText, Sodium.base64_variant_ORIGINAL());
byte[] npub = this.hexToBin(public_nonce);
byte[] k = this.hexToBin(key);
if (c == null || c.length <= 0)
p.reject(ESODIUM,ERR_FAILURE);
else if (npub.length != Sodium.crypto_aead_xchacha20poly1305_IETF_NPUBBYTES())
p.reject(ESODIUM,ERR_BAD_NONCE);
else if (k.length != Sodium.crypto_aead_xchacha20poly1305_IETF_KEYBYTES())
p.reject(ESODIUM,ERR_BAD_KEY);
else {
byte[] ad = additionalData != null ? additionalData.getBytes(StandardCharsets.UTF_8) : null;
int adlen = additionalData != null ? ad.length : 0;
int[] decrypted_len = new int[1];
byte[] decrypted = new byte[c.length - Sodium.crypto_aead_chacha20poly1305_IETF_ABYTES()];
int result = Sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(decrypted, decrypted_len, null, c, c.length, ad, adlen, npub, k);
if (result != 0)
p.reject(ESODIUM,ERR_FAILURE);
else
p.resolve(new String(decrypted, StandardCharsets.UTF_8));
}
}
catch (Throwable t) {
p.reject(ESODIUM,ERR_FAILURE,t);
}
}
Seems like it happens for bigger elements most of the time, but not always. Also happens for crypto_1aead_1xchacha20poly1305_1ietf_1encrypt
.
from LogHeapCorruption during ReleasePrimitiveArrayElements
No comments:
Post a Comment