There are a number of places (like the example below) where proper exception handling is missing in the case an exception is thrown in a callback.
extern "C" JNIEXPORT void JNICALL Java_io_pmem_pmemkv_KVEngine_kvengine_1each_1string
(JNIEnv* env, jobject obj, jlong pointer, jobject callback) {
const auto cb = [](void* context, int32_t keybytes, const char* key, int32_t valuebytes, const char* value) {
const auto c = ((CallbackContext*) context);
const auto ckey = c->env->NewStringUTF(key);
const auto cvalue = c->env->NewStringUTF(value);
c->env->CallVoidMethod(c->callback, c->mid, ckey, cvalue); // this could throw an exception
c->env->DeleteLocalRef(ckey); // on exception, this will be skipped
c->env->DeleteLocalRef(cvalue); // on exception, this will be skipped
};
const auto cls = env->GetObjectClass(callback);
const auto mid = env->GetMethodID(cls, "process", "(Ljava/lang/String;Ljava/lang/String;)V");
CallbackContext cxt = {env, callback, mid};
const auto engine = (KVEngine*) pointer;
pmemkv::kvengine_each(engine, &cxt, cb);
}
Obviously this means we also need test cases where mock callbacks are throwing exceptions.