{"record":{"id":"fd7b24b01ad8fcc1","repo":"java-native-access/jna","slug":"jna-likely-memory-leak-here","errorCode":null,"errorMessage":"JNA: Likely memory leak here\n","messagePattern":"JNA: Likely memory leak here\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"native/callback.c","lineNumber":505,"sourceCode":"    else switch(cb->rflag) {\n    case CVT_INTEGER_TYPE:\n      if (cb->cif.rtype->size > sizeof(ffi_arg)) {\n        *(jlong *)oldresp = getIntegerTypeValue(env, *(void **)resp);\n      }\n      else {\n        *(ffi_arg *)oldresp = (ffi_arg)getIntegerTypeValue(env, *(void **)resp);\n      }\n      break;\n    case CVT_POINTER_TYPE:\n      *(void **)resp = getPointerTypeAddress(env, *(void **)resp);\n      break;\n    case CVT_NATIVE_MAPPED:\n      toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE, cb->encoding);\n      break;\n    case CVT_NATIVE_MAPPED_STRING:\n    case CVT_NATIVE_MAPPED_WSTRING:\n      // TODO: getNativeString rather than allocated memory\n      fprintf(stderr, \"JNA: Likely memory leak here\\n\");\n      toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE, cb->encoding);\n      break;\n    case CVT_POINTER:\n      *(void **)resp = getNativeAddress(env, *(void **)resp);\n      break;\n    case CVT_STRING: \n      *(void **)resp = getNativeString(env, *(void **)resp, JNI_FALSE);\n      break;\n    case CVT_WSTRING: \n      *(void **)resp = getNativeString(env, *(void **)resp, JNI_TRUE);\n      break;\n    case CVT_STRUCTURE:\n      writeStructure(env, *(void **)resp);\n      *(void **)resp = getStructureAddress(env, *(void **)resp);\n      break;\n    case CVT_STRUCTURE_BYVAL:\n      writeStructure(env, *(void **)resp);\n      memcpy(oldresp, getStructureAddress(env, *(void **)resp), cb->cif.rtype->size);","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/native/callback.c#L487-L523","documentation":"When converting a callback's return value flagged as CVT_NATIVE_MAPPED_STRING or CVT_NATIVE_MAPPED_WSTRING, JNA prints this warning because the native string buffer allocated by getNativeString-style retrieval is not freed before toNative copies it, leaking memory per callback invocation. It is a known internal TODO, not a failure of the call itself.","triggerScenarios":"A callback whose return type is a NativeMapped mapping to String/WString (e.g. a NativeMapped class whose native type is a wide/narrow string) returning to native code via invoke_callback.","commonSituations":"Long-running applications invoking such string-returning callbacks at high frequency, gradually leaking native memory; custom NativeMapped return types wrapping strings.","solutions":["Avoid NativeMapped types that map to native strings as callback return types; return Pointer/byte[]/char[] or a primitive instead.","Return a Java String/WString directly (CVT_STRING/CVT_WSTRING path) so JNA handles allocation/frees properly.","Upgrade JNA — newer versions may address this TODO; monitor native memory usage in the interim."],"exampleFix":"// before\npublic MyStringMappedType call() { ... } // NativeMapped over string -> leak\n// after\npublic String call() { ... } // handled by native string conversion path","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid NativeMapped-over-string types as callback return types","Return String/WString, byte[], char[], Pointer, or primitives from callbacks","Upgrade JNA to pick up fixes for the string-conversion TODO","Profile native memory if string-returning callbacks run at high frequency"],"tags":["jna","native","callback","memory-leak"],"backgroundTag":"native-memory-leak","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}