如何解决ReleasePrimitiveArrayElements 期间的 LogHeapCorruption
当我们的应用通过 JNI(数百个元素)获得大量流量时,我们似乎遇到了很多堆损坏错误(似乎更大的元素更容易发生这种情况)。
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::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
似乎导致 的行位于此处(我们的代码是开源的)https://github.com/standardnotes/react-native-sodium/blob/367b61a90180fe75ddef5b599e01c47cb4761b1f/android/src/main/cpp/sodium-jni.c#L156。我试图对此进行更多调试,但我的 JNI + CPP 知识有限。对于以更好的方式从 Java 到 C++ 交换数据,您有什么建议吗?
代码片段:
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,(jbyte *) m,0);
return (jint)result;
}
从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.length,adlen,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);
}
}
似乎大部分时间都会发生在较大的元素上,但并非总是如此。 crypto_1aead_1xchacha20poly1305_1ietf_1encrypt
也会发生。
解决方法
ReleasePrimitiveArrayElements
表示 ->ReleaseByteArrayElements()
。
问题很可能是您指的是 JNIEnv*
并且在某些时候它与线程分离(处理时间会很有趣)。您需要以不同的方式获取 JNIEnv*
,例如。类似AttachCurrentThreadIfNeeded()。另请参阅 JNI threads。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。