Skip to content

Commit

Permalink
Make java UTF-8 decode more lenient (#26886)
Browse files Browse the repository at this point in the history
* Start asking for replace in the java UTF logic

* Fix exception reporting: make sure exception is cleared, print out a nice stack trace

* Restyle

* Fix for compilation

* Fix signature for repolace action field

* Restyled by clang-format

---------

Co-authored-by: Andrei Litvin <[email protected]>
Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
3 people authored May 27, 2023
1 parent b3adaa6 commit f223899
Showing 1 changed file with 32 additions and 1 deletion.
33 changes: 32 additions & 1 deletion src/lib/support/JniReferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,14 +402,45 @@ CHIP_ERROR JniReferences::CharToStringUTF(const chip::CharSpan & charSpan, jobje
jmethodID newDocoderMethod = env->GetMethodID(charSetClass, "newDecoder", "()Ljava/nio/charset/CharsetDecoder;");
jobject decoderObject = env->CallObjectMethod(charsetObject, newDocoderMethod);

// Even though spec requires UTF-8 strings, we have seen instances in the field of certified devices sending
// invalid strings like "startup?" (0x73 0x74 0x61 0x72 0x74 0x75 0x70 <0x91>) and we want to actually
// be lenient on those rather than failing an entire decode (which may fail an entire report for one invalid string,
// like in a very common 'subscribe *')
//
// As a result call:
// onMalformedInput(CodingErrorAction.REPLACE)
// onUnmappableCharacter(CodingErrorAction.REPLACE)
jclass codingErrorActionClass = env->FindClass("java/nio/charset/CodingErrorAction");
jobject replaceAction = env->GetStaticObjectField(
codingErrorActionClass, env->GetStaticFieldID(codingErrorActionClass, "REPLACE", "Ljava/nio/charset/CodingErrorAction;"));
{
jmethodID onMalformedInput = env->GetMethodID(charSetDocoderClass, "onMalformedInput",
"(Ljava/nio/charset/CodingErrorAction;)Ljava/nio/charset/CharsetDecoder;");
decoderObject = env->CallObjectMethod(decoderObject, onMalformedInput, replaceAction);
}
{
jmethodID onUnmappableCharacter =
env->GetMethodID(charSetDocoderClass, "onUnmappableCharacter",
"(Ljava/nio/charset/CodingErrorAction;)Ljava/nio/charset/CharsetDecoder;");
decoderObject = env->CallObjectMethod(decoderObject, onUnmappableCharacter, replaceAction);
}

jmethodID charSetDecodeMethod = env->GetMethodID(charSetDocoderClass, "decode", "(Ljava/nio/ByteBuffer;)Ljava/nio/CharBuffer;");
jobject decodeObject = env->CallObjectMethod(decoderObject, charSetDecodeMethod, jbyteBuffer);
env->DeleteLocalRef(jbyteBuffer);

// If decode exception occur, outStr will be set null.
outStr = nullptr;

VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN);
if (env->ExceptionCheck())
{
// If there is an exception, decode will not fail. Instead just
// an error will be reported.
ChipLogError(Support, "Exception encountered trying to decode a UTF string.");
env->ExceptionDescribe();
env->ExceptionClear();
return CHIP_JNI_ERROR_EXCEPTION_THROWN;
}

jclass charBufferClass = env->FindClass("java/nio/CharBuffer");
jmethodID charBufferToString = env->GetMethodID(charBufferClass, "toString", "()Ljava/lang/String;");
Expand Down

0 comments on commit f223899

Please sign in to comment.