summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-05-05 23:13:12 +0300
committerAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-05-22 20:40:39 +0300
commit41858caec0ea7badcff670c62b459bf06a74aa03 (patch)
tree63adb0668d906746954a72338b887c1ac0e350c7
parent6b4e3f3288ec1e9917cecd862a7a52945e5b4db2 (diff)
#4802 Handle KDU crashes
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp42
1 files changed, 40 insertions, 2 deletions
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 4330b1e5b1..74aaffbd65 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -158,6 +158,9 @@ public:
kdu_codestream* codestreamp);
~LLKDUDecodeState();
bool processTileDecode(F32 decode_time, bool limit_time = true);
+#ifdef LL_WINDOWS
+ bool processTileDecodeSEH(F32 decode_time, bool limit_time = true);
+#endif
private:
S32 mNumComponents;
@@ -282,10 +285,16 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
try
{
-
S32 data_size = base.getDataSize();
S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
+ // Data sanity checks
+ // 0 data size appears to be valid.
+ if (data_size < 0 || data_size > 128 * 1024 * 1024) // 128MB
+ {
+ LLTHROW(KDUError(STRINGIZE("Invalid data size: " << data_size)));
+ }
+
//
// Initialization
//
@@ -385,7 +394,8 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
catch (std::bad_alloc&)
{
// we are in a thread, can't show an 'out of memory' here,
- // main thread will keep going
+ // as main thread will keep going
+ // Todo: should cause main thread to stop and show an error.
throw;
}
catch (...)
@@ -602,7 +612,11 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
// Do the actual processing
F32 remaining_time = limit_time ? decode_time - decode_timer.getElapsedTimeF32().value() : 0.0f;
// This is where we do the actual decode. If we run out of time, return false.
+#ifdef LL_WINDOWS
+ if (mDecodeState->processTileDecodeSEH(remaining_time, limit_time))
+#else
if (mDecodeState->processTileDecode(remaining_time, limit_time))
+#endif
{
mDecodeState.reset();
}
@@ -1302,6 +1316,11 @@ all necessary level shifting, type conversion, rounding and truncation. */
LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap,
kdu_codestream* codestreamp)
{
+ if (!buf)
+ {
+ LLTHROW(KDUError("Null buffer passed to LLKDUDecodeState"));
+ }
+
S32 c;
mTile = tile;
@@ -1311,6 +1330,11 @@ LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap,
mNumComponents = tile.get_num_components();
llassert(mNumComponents <= 4);
+ if (mNumComponents <= 0 || mNumComponents > 4)
+ {
+ LL_WARNS() << "Invalid component count: " << mNumComponents << ", clamping to valid range" << LL_ENDL;
+ mNumComponents = llclamp(mNumComponents, 1, 4);
+ }
mUseYCC = tile.get_ycc();
for (c = 0; c < 4; ++c)
@@ -1363,6 +1387,20 @@ LLKDUDecodeState::~LLKDUDecodeState()
mTile.close();
}
+#ifdef LL_WINDOWS
+bool LLKDUDecodeState::processTileDecodeSEH(F32 decode_time, bool limit_time)
+{
+ __try
+ {
+ return processTileDecode(decode_time, limit_time);
+ }
+ __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation()))
+ {
+ return false;
+ }
+}
+#endif
+
bool LLKDUDecodeState::processTileDecode(F32 decode_time, bool limit_time)
/* Decompresses a tile, writing the data into the supplied byte buffer.
The buffer contains interleaved image components, if there are any.