From 0eac1f41f68bd2cd3b7e73db9eb96c690507b448 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 17 Aug 2016 16:42:10 -0400 Subject: MAINT-5011: Catch kdu_exception (aka int) in case it leaks out. KDU internally throws kdu_exception, which is a typedef for int. It's possible that such an exception might leak out. Our usual strategy for unknown exceptions is to catch (...) and let boost::current_exception_diagnostic_information() handle them. However, for int (or a class not derived from std::exception), that function will only shrug and report no information available. Besides, we want to format kdu_exception specially anyway. First, the KDU #defines are in hex, so we should report the value in hex. But on inspection, certain of those hex values are actually multibyte ASCII literals in disguise -- so also report the byte string value. --- indra/llkdu/llimagej2ckdu.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 4c2eac9eea..9e1dfc7213 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -1,4 +1,4 @@ - /** +/** * @file llimagej2ckdu.cpp * @brief This is an implementation of JPEG2000 encode/decode using Kakadu * @@ -36,6 +36,8 @@ #include "llexception.h" #include +#include +#include namespace { // Failure to load an image shouldn't crash the whole viewer. @@ -43,6 +45,40 @@ struct KDUError: public LLContinueError { KDUError(const std::string& msg): LLContinueError(msg) {} }; + +// KDU defines int error codes as hex values, so we should log them in hex +// so we can grep KDU headers for the hex. However those hex values +// generally "happen" to encode big-endian multibyte character sequences, +// e.g. KDU_ERROR_EXCEPTION is 0x6b647545: 'kduE' +// But beware because KDU_NULL_EXCEPTION is simply 0 -- which doesn't +// preclude somebody from throwing it. +std::string report_kdu_exception(kdu_exception mb) +{ + std::ostringstream out; + // always report mb in hex + out << "kdu_exception " << std::hex << mb; + + // Also display as many chars as are encoded in the kdu_exception + // value. Make a char array; reserve 1 extra byte for nul terminator. + char bytes[sizeof(kdu_exception) + 1]; + // Back up through 'bytes' + char *bptr = bytes + sizeof(bytes); + *(--bptr) = '\0'; + while (mb) + { + // store low-order byte of mb in next-left char + *(--bptr) = char(mb & 0xFF); + // then shift mb right by one byte + mb >>= 8; + } + // did that produce any characters? + if (*bptr) + { + out << " (" << bptr << ')'; + } + + return out.str(); +} } // anonymous namespace class kdc_flow_control { @@ -400,6 +436,15 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch (...) { base.setLastError("Unknown J2C error: " + @@ -499,6 +544,17 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco cleanupCodeStream(); return true; // done } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + base.decodeFailed(); + cleanupCodeStream(); + return true; // done + } catch (...) { base.setLastError("Unknown J2C error: " + @@ -691,6 +747,15 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch( ... ) { base.setLastError("Unknown J2C error: " + @@ -716,6 +781,15 @@ bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base) base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch (...) { base.setLastError("Unknown J2C error: " + -- cgit v1.2.3