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

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...