diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/llcoros.cpp | 74 | ||||
| -rw-r--r-- | indra/llcommon/llcoros.h | 6 | ||||
| -rw-r--r-- | indra/llcommon/llsdserialize.cpp | 121 | ||||
| -rw-r--r-- | indra/llcommon/llsdserialize.h | 6 | 
4 files changed, 99 insertions, 108 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/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  | 
