android - 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::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
似乎导致的行位于此处(我们的代码是开源的)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, j_m, (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, 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);
}
}
似乎大多数时候它发生在更大的元素上,但并非总是如此。也发生在crypto_1aead_1xchacha20poly1305_1ietf_1encrypt
.
解决方案
ReleasePrimitiveArrayElements
意味着->ReleaseByteArrayElements()
。
这个问题很可能是您所指的,JNIEnv*
并且在某些时候它与线程分离(处理时间会相当有趣)。你需要以JNIEnv*
不同的方式获得,例如。类似AttachCurrentThreadIfNeeded()。另请参阅 JNI线程。
推荐阅读
- android - TimerTasks 似乎在按下“返回”按钮后恢复应用程序后被取消
- python - 如何使用网格方法对齐 Tkinter 中的单选按钮?
- python - 尝试使用辅助函数清理我的代码,而不是使用重复的代码
- r - 如何使 Box 内的 bs4Dash Box 显示为内联且宽度相等
- node.js - 将 JSON 字符串转换为对象 nodejs
- javascript - 如何在 VSC 中调试 React Native Expo 应用程序
- delphi - Firemonkey 忽略在运行时创建标签时指示的 Font.Size
- python - 带有初始化文件的 ModuleNotFoundError python
- junit - 我可以使用什么工具通过 cypress 自动化截屏?
- html - 如何在子元素的背景上呈现插入框阴影?