summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llcoros.cpp74
-rw-r--r--indra/llcommon/llcoros.h6
-rw-r--r--indra/llcommon/llerror.cpp2
-rw-r--r--indra/llcommon/llsdserialize.cpp121
-rw-r--r--indra/llcommon/llsdserialize.h6
-rw-r--r--indra/llcommon/lluuid.cpp42
-rw-r--r--indra/llcommon/lluuid.h8
-rw-r--r--indra/llcommon/threadsafeschedule.h2
8 files changed, 114 insertions, 147 deletions
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 14bfb98629..70d8dfc8b9 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -288,25 +288,15 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl
return name;
}
+namespace
+{
+
#if LL_WINDOWS
static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
-U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, const std::string& name)
+U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
{
- // C++ exceptions were logged in toplevelTryWrapper, but not SEH
- // log SEH exceptions here, to make sure it gets into bugsplat's
- // report and because __try won't allow std::string operations
- if (code != STATUS_MSC_EXCEPTION)
- {
- LL_WARNS() << "SEH crash in " << name << ", code: " << code << LL_ENDL;
- }
- // Handle bugsplat here, since GetExceptionInformation() can only be
- // called from within filter for __except(filter), not from __except's {}
- // Bugsplat should get all exceptions, C++ and SEH
- LLApp::instance()->reportCrashToBugsplat(exception_infop);
-
- // Only convert non C++ exceptions.
if (code == STATUS_MSC_EXCEPTION)
{
// C++ exception, go on
@@ -319,28 +309,38 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop,
}
}
-void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable)
+void sehandle(const LLCoros::callable_t& callable)
{
__try
{
- LLCoros::toplevelTryWrapper(name, callable);
+ callable();
}
- __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name))
+ __except (exception_filter(GetExceptionCode(), GetExceptionInformation()))
{
- // convert to C++ styled exception for handlers other than bugsplat
+ // convert to C++ styled exception
// Note: it might be better to use _se_set_translator
// if you want exception to inherit full callstack
- //
- // in case of bugsplat this will get to exceptionTerminateHandler and
- // looks like fiber will terminate application after that
char integer_string[512];
- sprintf(integer_string, "SEH crash in %s, code: %lu\n", name.c_str(), GetExceptionCode());
+ sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());
throw std::exception(integer_string);
}
}
-#endif
-void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable)
+#else // ! LL_WINDOWS
+
+inline void sehandle(const LLCoros::callable_t& callable)
+{
+ callable();
+}
+
+#endif // ! LL_WINDOWS
+
+} // anonymous namespace
+
+// Top-level wrapper around caller's coroutine callable.
+// Normally we like to pass strings and such by const reference -- but in this
+// case, we WANT to copy both the name and the callable to our local stack!
+void LLCoros::toplevel(std::string name, callable_t callable)
{
// keep the CoroData on this top-level function's stack frame
CoroData corodata(name);
@@ -350,12 +350,12 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call
// run the code the caller actually wants in the coroutine
try
{
- callable();
+ sehandle(callable);
}
catch (const Stop& exc)
{
LL_INFOS("LLCoros") << "coroutine " << name << " terminating because "
- << exc.what() << LL_ENDL;
+ << exc.what() << LL_ENDL;
}
catch (const LLContinueError&)
{
@@ -366,36 +366,14 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call
}
catch (...)
{
-#if LL_WINDOWS
- // Any OTHER kind of uncaught exception will cause the viewer to
- // crash, SEH handling should catch it and report to bugsplat.
- LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name));
- // to not modify callstack
- throw;
-#else
// Stash any OTHER kind of uncaught exception in the rethrow() queue
// to be rethrown by the main fiber.
LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine "
<< name << LL_ENDL;
LLCoros::instance().saveException(name, std::current_exception());
-#endif
}
}
-// Top-level wrapper around caller's coroutine callable.
-// Normally we like to pass strings and such by const reference -- but in this
-// case, we WANT to copy both the name and the callable to our local stack!
-void LLCoros::toplevel(std::string name, callable_t callable)
-{
-#if LL_WINDOWS
- // Because SEH can's have unwinding, need to call a wrapper
- // 'try' is inside SEH handling to not catch LLContinue
- sehHandle(name, callable);
-#else
- toplevelTryWrapper(name, callable);
-#endif
-}
-
//static
void LLCoros::checkStop()
{
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index dbff921f16..966ce03296 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -307,11 +307,7 @@ public:
private:
std::string generateDistinctName(const std::string& prefix) const;
- void toplevelTryWrapper(const std::string& name, const callable_t& callable);
-#if LL_WINDOWS
- void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper
-#endif
- void toplevel(std::string name, callable_t callable); // calls sehHandle or toplevelTryWrapper
+ void toplevel(std::string name, callable_t callable);
struct CoroData;
static CoroData& get_CoroData(const std::string& caller);
void saveException(const std::string& name, std::exception_ptr exc);
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 919d2dabc4..56fb7c21ca 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -943,7 +943,7 @@ namespace LLError
for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
{
const LLSD& entry = *a;
- if (entry.isMap() && !entry.emptyMap())
+ if (entry.isMap() && entry.size() != 0)
{
ELevel level = decodeLevel(entry["level"]);
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 8b4a0ee6d8..a510b73096 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -34,6 +34,9 @@
#include <iostream>
#include "apr_base64.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
#ifdef LL_USESYSTEMLIBS
# include <zlib.h>
#else
@@ -2128,7 +2131,9 @@ std::string zip_llsd(LLSD& data)
{ //copy result into output
if (strm.avail_out >= CHUNK)
{
- free(output);
+ deflateEnd(&strm);
+ if(output)
+ free(output);
LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
return std::string();
}
@@ -2151,7 +2156,9 @@ std::string zip_llsd(LLSD& data)
}
else
{
- free(output);
+ deflateEnd(&strm);
+ if(output)
+ free(output);
LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
return std::string();
}
@@ -2162,7 +2169,8 @@ std::string zip_llsd(LLSD& data)
std::string result((char*) output, size);
deflateEnd(&strm);
- free(output);
+ if(output)
+ free(output);
return result;
}
@@ -2172,53 +2180,66 @@ std::string zip_llsd(LLSD& data)
// and deserializes from that copy using LLSDSerialize
LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size)
{
+ std::unique_ptr<U8[]> in = std::unique_ptr<U8[]>(new(std::nothrow) U8[size]);
+ if (!in)
+ {
+ return ZR_MEM_ERROR;
+ }
+ is.read((char*) in.get(), size);
+
+ return unzip_llsd(data, in.get(), size);
+}
+
+LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size)
+{
U8* result = NULL;
U32 cur_size = 0;
z_stream strm;
- const U32 CHUNK = 65536;
+ constexpr U32 CHUNK = 1024 * 512;
- U8 *in = new(std::nothrow) U8[size];
- if (!in)
+ static thread_local std::unique_ptr<U8[]> out;
+ if (!out)
{
- return ZR_MEM_ERROR;
+ out = std::unique_ptr<U8[]>(new(std::nothrow) U8[CHUNK]);
}
- is.read((char*) in, size);
-
- U8 out[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = size;
- strm.next_in = in;
+ strm.next_in = const_cast<U8*>(in);
S32 ret = inflateInit(&strm);
do
{
strm.avail_out = CHUNK;
- strm.next_out = out;
+ strm.next_out = out.get();
ret = inflate(&strm, Z_NO_FLUSH);
- if (ret == Z_STREAM_ERROR)
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
{
inflateEnd(&strm);
free(result);
- delete [] in;
return ZR_DATA_ERROR;
}
-
- switch (ret)
+ case Z_STREAM_ERROR:
+ case Z_BUF_ERROR:
{
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR;
- case Z_DATA_ERROR:
+ inflateEnd(&strm);
+ free(result);
+ return ZR_BUFFER_ERROR;
+ }
+
case Z_MEM_ERROR:
+ {
inflateEnd(&strm);
free(result);
- delete [] in;
return ZR_MEM_ERROR;
- break;
+ }
}
U32 have = CHUNK-strm.avail_out;
@@ -2231,17 +2252,15 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
{
free(result);
}
- delete[] in;
return ZR_MEM_ERROR;
}
result = new_result;
- memcpy(result+cur_size, out, have);
+ memcpy(result+cur_size, out.get(), have);
cur_size += have;
- } while (ret == Z_OK);
+ } while (ret == Z_OK && ret != Z_STREAM_END);
inflateEnd(&strm);
- delete [] in;
if (ret != Z_STREAM_END)
{
@@ -2251,37 +2270,11 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
//result now points to the decompressed LLSD block
{
- std::istringstream istr;
- // Since we are using this for meshes, data we are dealing with tend to be large.
- // So string can potentially fail to allocate, make sure this won't cause problems
- try
- {
- std::string res_str((char*)result, cur_size);
-
- std::string deprecated_header("<? LLSD/Binary ?>");
-
- if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
- {
- res_str = res_str.substr(deprecated_header.size() + 1, cur_size);
- }
- cur_size = res_str.size();
-
- istr.str(res_str);
- }
-#ifdef LL_WINDOWS
- catch (std::length_error)
- {
- free(result);
- return ZR_SIZE_ERROR;
- }
-#endif
- catch (std::bad_alloc&)
- {
- free(result);
- return ZR_MEM_ERROR;
- }
+ char* result_ptr = strip_deprecated_header((char*)result, cur_size);
- if (!LLSDSerialize::fromBinary(data, istr, cur_size, UNZIP_LLSD_MAX_DEPTH))
+ boost::iostreams::stream<boost::iostreams::array_source> istrm(result_ptr, cur_size);
+
+ if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH))
{
free(result);
return ZR_PARSE_ERROR;
@@ -2395,4 +2388,22 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32
return result;
}
+char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size)
+{
+ const char* deprecated_header = "<? LLSD/Binary ?>";
+ constexpr size_t deprecated_header_size = 17;
+
+ if (cur_size > deprecated_header_size
+ && memcmp(in, deprecated_header, deprecated_header_size) == 0)
+ {
+ in = in + deprecated_header_size;
+ cur_size = cur_size - deprecated_header_size;
+ if (header_size)
+ {
+ *header_size = deprecated_header_size + 1;
+ }
+ }
+
+ return in;
+}
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index d6079fd9fa..d33d2b6f34 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -858,9 +858,12 @@ public:
ZR_SIZE_ERROR,
ZR_DATA_ERROR,
ZR_PARSE_ERROR,
+ ZR_BUFFER_ERROR,
+ ZR_VERSION_ERROR
} EZipRresult;
// return OK or reason for failure
static EZipRresult unzip_llsd(LLSD& data, std::istream& is, S32 size);
+ static EZipRresult unzip_llsd(LLSD& data, const U8* in, S32 size);
};
//dirty little zip functions -- yell at davep
@@ -868,4 +871,7 @@ LL_COMMON_API std::string zip_llsd(LLSD& data);
LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize,std::istream& is, S32 size);
+
+// returns a pointer to the array or past the array if the deprecated header exists
+LL_COMMON_API char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size = nullptr);
#endif // LL_LLSDSERIALIZE_H
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index 8ff6c45760..fc04dca08d 100644
--- a/indra/llcommon/lluuid.cpp
+++ b/indra/llcommon/lluuid.cpp
@@ -44,6 +44,7 @@
#include "lltimer.h"
#include "llthread.h"
#include "llmutex.h"
+#include "llmd5.h"
#include "hbxxh.h"
const LLUUID LLUUID::null;
@@ -400,11 +401,16 @@ LLUUID LLUUID::operator^(const LLUUID& rhs) const
return id;
}
+// WARNING: this algorithm SHALL NOT be changed. It is also used by the server
+// and plays a role in some assets validation (e.g. clothing items). Changing
+// it would cause invalid assets.
void LLUUID::combine(const LLUUID& other, LLUUID& result) const
{
- HBXXH128 hash((const void*)mData, 16, false); // false = do not finalize
- hash.update((const void*)other.mData, 16);
- hash.digest(result);
+ LLMD5 md5_uuid;
+ md5_uuid.update((unsigned char*)mData, 16);
+ md5_uuid.update((unsigned char*)other.mData, 16);
+ md5_uuid.finalize();
+ md5_uuid.raw_digest(result.mData);
}
LLUUID LLUUID::combine(const LLUUID &other) const
@@ -997,36 +1003,6 @@ LLUUID::LLUUID()
return !(word[0] | word[1] | word[2] | word[3]);
}
-// Copy constructor
- LLUUID::LLUUID(const LLUUID& rhs)
-{
- U32 *tmp = (U32 *)mData;
- U32 *rhstmp = (U32 *)rhs.mData;
- tmp[0] = rhstmp[0];
- tmp[1] = rhstmp[1];
- tmp[2] = rhstmp[2];
- tmp[3] = rhstmp[3];
-}
-
- LLUUID::~LLUUID()
-{
-}
-
-// Assignment
- LLUUID& LLUUID::operator=(const LLUUID& rhs)
-{
- // No need to check the case where this==&rhs. The branch is slower than the write.
- U32 *tmp = (U32 *)mData;
- U32 *rhstmp = (U32 *)rhs.mData;
- tmp[0] = rhstmp[0];
- tmp[1] = rhstmp[1];
- tmp[2] = rhstmp[2];
- tmp[3] = rhstmp[3];
-
- return *this;
-}
-
-
LLUUID::LLUUID(const char *in_string)
{
if (!in_string || in_string[0] == 0)
diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
index 86a396ab06..c139c4eb4e 100644
--- a/indra/llcommon/lluuid.h
+++ b/indra/llcommon/lluuid.h
@@ -55,10 +55,7 @@ public:
LLUUID();
explicit LLUUID(const char *in_string); // Convert from string.
explicit LLUUID(const std::string& in_string); // Convert from string.
- LLUUID(const LLUUID &in);
- LLUUID &operator=(const LLUUID &rhs);
-
- ~LLUUID();
+ ~LLUUID() = default;
//
// MANIPULATORS
@@ -131,6 +128,9 @@ public:
U8 mData[UUID_BYTES];
};
+static_assert(std::is_trivially_copyable<LLUUID>::value, "LLUUID must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLUUID>::value, "LLUUID must be trivial move");
+static_assert(std::is_standard_layout<LLUUID>::value, "LLUUID must be a standard layout type");
typedef std::vector<LLUUID> uuid_vec_t;
typedef std::set<LLUUID> uuid_set_t;
diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h
index 3e0da94c02..0c3a541196 100644
--- a/indra/llcommon/threadsafeschedule.h
+++ b/indra/llcommon/threadsafeschedule.h
@@ -248,7 +248,7 @@ namespace LL
TimePoint until = TimePoint::clock::now() + std::chrono::hours(24);
pop_result popped = tryPopUntil_(lock, until, tt);
if (popped == POPPED)
- return std::move(tt);
+ return tt;
// DONE: throw, just as super::pop() does
if (popped == DONE)