diff options
| author | Erik Kundiman <erik@megapahit.org> | 2026-09-01 18:35:23 +0800 |
|---|---|---|
| committer | Erik Kundiman <erik@megapahit.org> | 2026-09-04 21:58:53 +0800 |
| commit | 00bb3bb6f07660bd914d29a1389342bb3060d254 (patch) | |
| tree | 431f574922494d2201718f13085f17bc6bd7fb42 /indra/llcommon/llsdserialize_xml.cpp | |
| parent | a8636720129952c10cf49ab80da21bf8b340b96c (diff) | |
| parent | 4ef9f8f14b35ed388c294d53767a0dca0e890924 (diff) | |
Merge remote-tracking branch 'secondlife/release/26.4' into 26.4
Diffstat (limited to 'indra/llcommon/llsdserialize_xml.cpp')
| -rw-r--r-- | indra/llcommon/llsdserialize_xml.cpp | 77 |
1 files changed, 71 insertions, 6 deletions
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index afe4fd63a6..704e433139 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -63,15 +63,80 @@ S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const { std::streamsize old_precision = ostr.precision(25); + std::ios_base::iostate old_exceptions = ostr.exceptions(); + // Merged exception mask: preserve the caller's bits and add failbit|badbit + // for I/O error detection, so we never drop bits the caller already enabled. + std::ios_base::iostate new_exceptions = + old_exceptions | std::ios_base::badbit | std::ios_base::failbit; + // Bits we are newly adding (not already in the caller's mask). + std::ios_base::iostate added_bits = new_exceptions & ~old_exceptions; - std::string post; - if (options & LLSDFormatter::OPTIONS_PRETTY) + // If the stream already has error-state bits that we would newly add to the + // exception mask, enabling those bits would throw immediately; bail out early. + if (added_bits && (ostr.rdstate() & added_bits)) { - post = "\n"; + LL_WARNS() << "LLSDXMLFormatter::format: Stream already in error state" << LL_ENDL; + ostr.precision(old_precision); + return -1; + } + + S32 rv = 0; + + try + { + // Enable the merged exception mask to detect I/O errors during formatting. + if (added_bits) + { + ostr.exceptions(new_exceptions); + } + + std::string post; + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + post = "\n"; + } + ostr << "<llsd>" << post; + rv = format_impl(data, ostr, options, 1); + ostr << "</llsd>\n"; + } + catch (const std::ios_base::failure& e) + { + LL_WARNS() << "LLSDXMLFormatter::format: Stream I/O exception: " << e.what() + << " - Stream state: good=" << ostr.good() + << " eof=" << ostr.eof() + << " fail=" << ostr.fail() + << " bad=" << ostr.bad() << LL_ENDL; + rv = -1; + } + catch (const std::bad_alloc&) + { + // we might be saving something massive, don't error or crash + LL_WARNS() << "LLSDXMLFormatter::format: Memory allocation failed during formatting" << LL_ENDL; + rv = -1; + } + catch (const std::exception& e) + { + LL_WARNS() << "LLSDXMLFormatter::format: Standard exception: " << e.what() << LL_ENDL; + rv = -1; + } + catch (...) + { + LL_WARNS() << "LLSDXMLFormatter::format: Unknown exception during formatting" << LL_ENDL; + rv = -1; + } + + // Restore original exception mask. First set to goodbit (never throws) so + // the subsequent restore call won't immediately throw if the stream is in + // error state for bits in old_exceptions. + try + { + ostr.exceptions(std::ios_base::goodbit); + ostr.exceptions(old_exceptions); + } + catch (...) + { + LL_WARNS() << "LLSDXMLFormatter::format: failed to restore exceptions" << LL_ENDL; } - ostr << "<llsd>" << post; - S32 rv = format_impl(data, ostr, options, 1); - ostr << "</llsd>\n"; ostr.precision(old_precision); return rv; |
