From a265a441fd89a84b882a9051b42e27c9b0cc7270 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Tue, 7 Nov 2006 21:03:13 +0000 Subject: [PATCH] # Fixed string handling for Windows/Linux compatibility. * vsnprintf2: Made compatible between GCC and MSVC - it now always null-terminates the buffer, and returns -1 on overflow. Fixes #158. Added tests. * MeshManager: Use shared_ptr.expired() instead of checking for bad_weak_ptr exception. * Xeromyces: Added tests for GetXMBPath, because it does unusual things in sscanf which MSVC's /analyze complains about. * ConfigDB, ScriptGlue: Replaced some asserts with return-on-failure, to avoid invalid array accesses when continuing after the assert (as complained about by /analyze). * CStr: Removed "using namespace std". Added tests for handling of invalid UTF-8. This was SVN commit r4625. --- source/graphics/MeshManager.cpp | 16 ++---- source/gui/CGUI.cpp | 1 - source/lib/self_test.h | 1 + source/lib/sysdep/sysdep.h | 12 ++-- source/lib/sysdep/tests/test_printf.h | 73 ++++++++++++++++++++++++ source/lib/sysdep/unix/printf.cpp | 26 +++++++++ source/lib/sysdep/win/printf.cpp | 20 +++++-- source/ps/CConsole.cpp | 12 ++-- source/ps/CLogger.cpp | 8 +-- source/ps/CStr.cpp | 23 ++++---- source/ps/CStr.h | 9 +-- source/ps/ConfigDB.cpp | 24 ++++++-- source/ps/XML/Xeromyces.cpp | 4 +- source/ps/XML/Xeromyces.h | 3 +- source/ps/XML/tests/test_Xeromyces.h | 32 +++++++++++ source/ps/tests/test_CStr.h | 40 ++++++++++++- source/scripting/ScriptGlue.cpp | 10 ++-- source/tools/atlas/AtlasUI/Misc/stdafx.h | 4 ++ 18 files changed, 254 insertions(+), 64 deletions(-) create mode 100644 source/lib/sysdep/tests/test_printf.h create mode 100644 source/lib/sysdep/unix/printf.cpp create mode 100644 source/ps/XML/tests/test_Xeromyces.h diff --git a/source/graphics/MeshManager.cpp b/source/graphics/MeshManager.cpp index 709f537de2..26798f2e10 100644 --- a/source/graphics/MeshManager.cpp +++ b/source/graphics/MeshManager.cpp @@ -16,19 +16,11 @@ CModelDefPtr CMeshManager::GetMesh(const char *filename) { CStr fn(filename); mesh_map::iterator iter = m_MeshMap.find(fn); - if (iter != m_MeshMap.end()) + if (iter != m_MeshMap.end() && !iter->second.expired()) { - try - { - CModelDefPtr model (iter->second); - //LOG(MESSAGE, "mesh", "Loading mesh '%s%' (cached)...", filename); - return model; - } - // If the mesh has already been deleted, the weak_ptr -> shared_ptr - // conversion will throw bad_weak_ptr (and we need to reload the mesh) - catch (boost::bad_weak_ptr) - { - } + CModelDefPtr model (iter->second); + //LOG(MESSAGE, "mesh", "Loading mesh '%s%' (cached)...", filename); + return model; } try diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index f56fcad925..434a80b5e1 100644 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -1022,7 +1022,6 @@ void CGUI::ReportParseError(const char *str, ...) va_start(argp, str); vsnprintf2(buffer, sizeof(buffer), str, argp); - buffer[sizeof(buffer)-1] = '\0'; va_end(argp); // Print header diff --git a/source/lib/self_test.h b/source/lib/self_test.h index 8417641995..02f1fe7807 100644 --- a/source/lib/self_test.h +++ b/source/lib/self_test.h @@ -188,5 +188,6 @@ extern bool self_test_active; #define TS_ASSERT_OK(expr) TS_ASSERT_EQUALS((expr), INFO::OK) #define TS_ASSERT_STR_EQUALS(str1, str2) TS_ASSERT_EQUALS(std::string(str1), std::string(str2)) +#define TS_ASSERT_WSTR_EQUALS(str1, str2) TS_ASSERT_EQUALS(std::wstring(str1), std::wstring(str2)) #endif // #ifndef SELF_TEST_H__ diff --git a/source/lib/sysdep/sysdep.h b/source/lib/sysdep/sysdep.h index b02dac2433..c22e7b753a 100644 --- a/source/lib/sysdep/sysdep.h +++ b/source/lib/sysdep/sysdep.h @@ -27,6 +27,7 @@ #include "lib/debug.h" // ErrorReaction #include // see comments below about isfinite +#include // needed for vsnprintf2 // some functions among the sysdep API are implemented as macros // that redirect to the platform-dependent version. this is done where @@ -82,13 +83,12 @@ // C99 / SUSv3 emulation where needed //----------------------------------------------------------------------------- -// vsnprintf2: handles positional parameters and %lld. -// already available on *nix, emulated on Win32. -#if OS_WIN +// vsnprintf2: doesn't quite follow the standard for vsnprintf, but works +// better across compilers: +// - handles positional parameters and %lld +// - always null-terminates the buffer +// - returns -1 on overflow (if the output string (including null) does not fit in the buffer) extern int vsnprintf2(char* buffer, size_t count, const char* format, va_list argptr); -#else -#define vsnprintf2 vsnprintf -#endif #if !MSC_VERSION #define stricmp strcasecmp diff --git a/source/lib/sysdep/tests/test_printf.h b/source/lib/sysdep/tests/test_printf.h new file mode 100644 index 0000000000..77806a310a --- /dev/null +++ b/source/lib/sysdep/tests/test_printf.h @@ -0,0 +1,73 @@ +#include "lib/lib.h" +#include "lib/self_test.h" + +class TestPrintf : public CxxTest::TestSuite +{ + // Split some bits into separate functions, so we can get + // a legitimate va_list to pass to vsnprintf2: + + void _test_truncate(int buffer_size, char* expected_output, int expected_return, /* char* input_string */...) + { + char buf[17] = "................"; // fill with dots so null-termination is made obvious + + va_list ap; + va_start(ap, expected_return); + + int ret = vsnprintf2(buf, buffer_size, "%s", ap); + + TS_ASSERT_STR_EQUALS(buf, expected_output); + TS_ASSERT_EQUALS(ret, expected_return); + + std::string past_buffer (buf + buffer_size); + TS_ASSERT(past_buffer.find_first_not_of('.') == past_buffer.npos); + + va_end(ap); + } + + void _test_sprintf(char* expected_output, char* format, ...) + { + char buf[256]; + + va_list ap; + va_start(ap, format); + + vsnprintf2(buf, sizeof(buf), format, ap); + TS_ASSERT_STR_EQUALS(buf, expected_output); + + va_end(ap); + } + +public: + void test_truncate() + { + _test_truncate(8, "1234", 4, "1234"); + _test_truncate(8, "1234567", 7, "1234567"); + _test_truncate(8, "1234567", -1, "12345678"); + _test_truncate(8, "1234567", -1, "123456789"); + _test_truncate(8, "1234567", -1, "123456789abcdef"); + } + + void test_lld() + { + i64 z = 0; + i64 n = 65536; + _test_sprintf("0", "%lld", z); + _test_sprintf("65536", "%lld", n); + _test_sprintf("4294967296", "%lld", n*n); + _test_sprintf("281474976710656", "%lld", n*n*n); + _test_sprintf("-281474976710656", "%lld", -n*n*n); + _test_sprintf("123 456 281474976710656 789", "%d %d %lld %d", 123, 456, n*n*n, 789); + } + + void test_pos() + { + _test_sprintf("a b", "%1$c %2$c", 'a', 'b'); + _test_sprintf("b a", "%2$c %1$c", 'a', 'b'); + } + + void test_pos_lld() + { + _test_sprintf("1 2 3", "%1$d %2$lld %3$d", 1, (i64)2, 3); + _test_sprintf("2 1 3", "%2$lld %1$d %3$d", 1, (i64)2, 3); + } +}; diff --git a/source/lib/sysdep/unix/printf.cpp b/source/lib/sysdep/unix/printf.cpp new file mode 100644 index 0000000000..28ff9c87ef --- /dev/null +++ b/source/lib/sysdep/unix/printf.cpp @@ -0,0 +1,26 @@ +#include "precompiled.h" + +#include +#include + +// See declaration in sysdep.h for explanation of need + +int vsnprintf2(char* buffer, size_t count, const char* format, va_list argptr) +{ + int ret = vsnprintf(buffer, count, format, argptr); + + /* + "The glibc implementation of the functions snprintf() and vsnprintf() conforms + to the C99 standard ... since glibc version 2.1. Until glibc 2.0.6 they would + return -1 when the output was truncated." + - man printf + + MSVC's _vsnprintf still returns -1, so we want this one to do the same (for + compatibility), if the output (including the terminating null) is truncated. + */ + + if (ret >= (int)count) + return -1; + + return ret; +} \ No newline at end of file diff --git a/source/lib/sysdep/win/printf.cpp b/source/lib/sysdep/win/printf.cpp index ac4f06dd37..0ebf11e7b5 100644 --- a/source/lib/sysdep/win/printf.cpp +++ b/source/lib/sysdep/win/printf.cpp @@ -9,7 +9,7 @@ /* Added features (compared to MSVC's printf): Positional parameters (e.g. "%1$d", where '1' means '1st in the parameter list') - %lld (equivalent to %I64d in MSVC) + %lld (equivalent to %I64d in MSVC7.1, though it's supported natively by MSVC8) Unsupported features (compared to a perfect implementation): ' <-- because MSVC doesn't support it @@ -32,6 +32,12 @@ #include #include +#if MSC_VERSION < 1400 +# define USE_I64_FORMAT 1 +#else +# define USE_I64_FORMAT 0 +#endif + enum { SPECFLAG_THOUSANDS = 1, // ' @@ -363,8 +369,8 @@ finished_reading: if (s->length > 256) { if (s->length == 0x00006c6c) - #if MSC_VERSION - newformat += "I64"; // MSVC compatibility + #if USE_I64_FORMAT + newformat += "I64"; #else newformat += "ll"; #endif @@ -464,7 +470,11 @@ finished_reading: int ret = _vsnprintf(buffer, count, newformat.c_str(), (va_list)newstackptr); + // For consistency with GCC's vsnprintf, make sure the buffer is null-terminated + // and return an error if that truncates the output + buffer[count-1] = '\0'; + if (ret == (int)count) + return -1; + return ret; } - - diff --git a/source/ps/CConsole.cpp b/source/ps/CConsole.cpp index 1ce3246ebc..17068abcba 100644 --- a/source/ps/CConsole.cpp +++ b/source/ps/CConsole.cpp @@ -591,7 +591,7 @@ void CConsole::SetBuffer(const wchar_t* szMessage, ...) m_iBufferPos = std::min(oldBufferPos, m_iBufferLength); } -void CConsole::UseHistoryFile( const CStr& filename, int max_history_lines ) +void CConsole::UseHistoryFile(const CStr& filename, int max_history_lines) { m_MaxHistoryLines = max_history_lines; @@ -599,7 +599,8 @@ void CConsole::UseHistoryFile( const CStr& filename, int max_history_lines ) LoadHistory(); } -void CConsole::ProcessBuffer(const wchar_t* szLine){ +void CConsole::ProcessBuffer(const wchar_t* szLine) +{ if (szLine == NULL) return; if (wcslen(szLine) <= 0) return; @@ -609,14 +610,15 @@ void CConsole::ProcessBuffer(const wchar_t* szLine){ SaveHistory(); // Do this each line for the moment; if a script causes // a crash it's a useful record. - wchar_t szCommand[CONSOLE_BUFFER_SIZE]; - memset(szCommand, '\0', sizeof(wchar_t) * CONSOLE_BUFFER_SIZE); + wchar_t szCommand[CONSOLE_BUFFER_SIZE] = { 0 }; std::map::iterator Iter; if (szLine[0] == '\\') { - swscanf(szLine, L"\\%ls", szCommand); + if (swscanf(szLine, L"\\%ls", szCommand) != 1) + return; + Trim(szCommand); ToLower(szCommand); diff --git a/source/ps/CLogger.cpp b/source/ps/CLogger.cpp index 8921eadd3f..05358bca3b 100644 --- a/source/ps/CLogger.cpp +++ b/source/ps/CLogger.cpp @@ -153,11 +153,9 @@ void CLogger::Log(ELogMethod method, const char* category, const char *fmt, ...) { va_list argp; char buffer[512]; - - memset(buffer, 0, sizeof(buffer)); va_start(argp, fmt); - if (vsnprintf2(buffer, sizeof(buffer)-1, fmt, argp) == -1) + if (vsnprintf2(buffer, sizeof(buffer), fmt, argp) == -1) { // Buffer too small - ensure the string is nicely terminated strcpy(buffer+sizeof(buffer)-4, "..."); // safe @@ -173,10 +171,8 @@ void CLogger::LogOnce(ELogMethod method, const char* category, const char *fmt, va_list argp; char buffer[512]; - memset(buffer, 0, sizeof(buffer)); - va_start(argp, fmt); - if (vsnprintf2(buffer, sizeof(buffer)-1, fmt, argp) == -1) + if (vsnprintf2(buffer, sizeof(buffer), fmt, argp) == -1) { // Buffer too small - ensure the string is nicely terminated strcpy(buffer+sizeof(buffer)-4, "..."); // safe diff --git a/source/ps/CStr.cpp b/source/ps/CStr.cpp index 355270c9df..965a90cbfd 100644 --- a/source/ps/CStr.cpp +++ b/source/ps/CStr.cpp @@ -38,7 +38,7 @@ CStr8 CStrW::ToUTF8() const { CStr8 result; - for (size_t i = 0; i < Length(); ++i) + for (size_t i = 0; i < length(); ++i) { unsigned short bytesToWrite; wchar_t ch = (*this)[i]; @@ -58,12 +58,14 @@ CStr8 CStrW::ToUTF8() const case 2: *--target = ((ch | 0x80) & 0xBF); ch >>= 6; case 1: *--target = (ch | firstByteMark[bytesToWrite]); } - result += CStr(buf, bytesToWrite); + result += CStr8(buf, bytesToWrite); } + return result; } -static bool isLegalUTF8(const unsigned char *source, int length) { +static bool isLegalUTF8(const unsigned char *source, int length) +{ unsigned char a; const unsigned char *srcptr = source+length; @@ -92,7 +94,7 @@ CStrW CStr8::FromUTF8() const { CStrW result; - if(empty()) + if (empty()) return result; const unsigned char* source = (const unsigned char*)&*begin(); @@ -103,12 +105,12 @@ CStrW CStr8::FromUTF8() const unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { - debug_warn("Invalid UTF-8 (fell off end)"); + //debug_warn("Invalid UTF-8 (fell off end)"); return L""; } if (! isLegalUTF8(source, extraBytesToRead+1)) { - debug_warn("Invalid UTF-8 (illegal data)"); + //debug_warn("Invalid UTF-8 (illegal data)"); return L""; } @@ -134,7 +136,6 @@ CStrW CStr8::FromUTF8() const // The following code is compiled twice, as CStrW then as CStr8: #include "CStr.h" -using namespace std; #include @@ -282,7 +283,7 @@ long CStr::ReverseFind(const CStr& Str) const // Lowercase and uppercase CStr CStr::LowerCase() const { - tstring NewString = *this; + std::tstring NewString = *this; for (size_t i = 0; i < length(); i++) NewString[i] = (tchar)_totlower((*this)[i]); @@ -291,7 +292,7 @@ CStr CStr::LowerCase() const CStr CStr::UpperCase() const { - tstring NewString = *this; + std::tstring NewString = *this; for (size_t i = 0; i < length(); i++) NewString[i] = (tchar)_totupper((*this)[i]); @@ -302,7 +303,7 @@ CStr CStr::UpperCase() const // code duplication because return by value overhead if they were merely an alias CStr CStr::LCase() const { - tstring NewString = *this; + std::tstring NewString = *this; for (size_t i = 0; i < length(); i++) NewString[i] = (tchar)_totlower((*this)[i]); @@ -311,7 +312,7 @@ CStr CStr::LCase() const CStr CStr::UCase() const { - tstring NewString = *this; + std::tstring NewString = *this; for (size_t i = 0; i < length(); i++) NewString[i] = (tchar)_totupper((*this)[i]); diff --git a/source/ps/CStr.h b/source/ps/CStr.h index ea9b8c80e9..ed5777825f 100644 --- a/source/ps/CStr.h +++ b/source/ps/CStr.h @@ -105,10 +105,11 @@ public: CStrW(const CStr8 &asciiStr); #endif - // Conversion to/from UTF-8, encoded in a CStr8. Non-ASCII characters are - // handled correctly. - // May fail, if converting from invalid UTF-8 data; the empty string will - // be returned. + // Conversion to/from UTF-8, encoded in a CStr8. + // Common non-ASCII characters are handled correctly. + // Characters outside the BMP (above 0xFFFF) are *not* handled correctly. + // FromUTF8 may fail, if converting from invalid UTF-8 data - the empty + // string will be returned. #ifdef _UNICODE CStr8 ToUTF8() const; #else diff --git a/source/ps/ConfigDB.cpp b/source/ps/ConfigDB.cpp index 6b03c4013e..8db99efada 100644 --- a/source/ps/ConfigDB.cpp +++ b/source/ps/ConfigDB.cpp @@ -200,7 +200,11 @@ CConfigValue *CConfigDB::GetValue(EConfigNamespace ns, const CStr& name) CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, const CStr& name ) { - debug_assert(ns < CFG_LAST && ns >= 0); + if (ns < 0 || ns >= CFG_LAST) + { + debug_warn("CConfigDB: Invalid ns value"); + return NULL; + } TConfigMap::iterator it = m_Map[CFG_COMMAND].find( name ); if( it != m_Map[CFG_COMMAND].end() ) @@ -218,7 +222,11 @@ CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, const CStr& name ) CConfigValue *CConfigDB::CreateValue(EConfigNamespace ns, const CStr& name) { - debug_assert(ns < CFG_LAST && ns >= 0); + if (ns < 0 || ns >= CFG_LAST) + { + debug_warn("CConfigDB: Invalid ns value"); + return NULL; + } CConfigValue *ret=GetValue(ns, name); if (ret) return ret; @@ -229,7 +237,11 @@ CConfigValue *CConfigDB::CreateValue(EConfigNamespace ns, const CStr& name) void CConfigDB::SetConfigFile(EConfigNamespace ns, bool useVFS, const CStr& path) { - debug_assert(ns < CFG_LAST && ns >= 0); + if (ns < 0 || ns >= CFG_LAST) + { + debug_warn("CConfigDB: Invalid ns value"); + return; + } m_ConfigFile[ns]=path; m_UseVFS[ns]=useVFS; @@ -328,7 +340,11 @@ bool CConfigDB::Reload(EConfigNamespace ns) bool CConfigDB::WriteFile(EConfigNamespace ns, bool useVFS, const CStr& path) { - debug_assert(ns >= 0 && ns < CFG_LAST); + if (ns < 0 || ns >= CFG_LAST) + { + debug_warn("CConfigDB: Invalid ns value"); + return false; + } char realpath[PATH_MAX]; char nativepath[PATH_MAX]; diff --git a/source/ps/XML/Xeromyces.cpp b/source/ps/XML/Xeromyces.cpp index b31df09c99..e6f3ed05a7 100644 --- a/source/ps/XML/Xeromyces.cpp +++ b/source/ps/XML/Xeromyces.cpp @@ -172,7 +172,7 @@ void CXeromyces::Terminate() // Find out write location of the XMB file corresponding to xmlFilename -void CXeromyces::getXMBPath(const char* xmlFilename, const char* xmbFilename, +void CXeromyces::GetXMBPath(const char* xmlFilename, const char* xmbFilename, char* xmbPath) { // rationale: @@ -257,7 +257,7 @@ PSRETURN CXeromyces::Load(const char* filename) xmbFilename += buf; char xmbPath[PATH_MAX]; - getXMBPath(filename, xmbFilename, xmbPath); + GetXMBPath(filename, xmbFilename, xmbPath); // If the file exists, use it diff --git a/source/ps/XML/Xeromyces.h b/source/ps/XML/Xeromyces.h index 46652b095b..701ad6c0cf 100644 --- a/source/ps/XML/Xeromyces.h +++ b/source/ps/XML/Xeromyces.h @@ -19,6 +19,7 @@ ERROR_TYPE(Xeromyces, XMLParseError); class CXeromyces : public XMBFile { + friend class TestXeromyces; public: CXeromyces(); ~CXeromyces(); @@ -32,7 +33,7 @@ public: private: // Find out write location of the XMB file corresponding to xmlFilename - void getXMBPath(const char* xmlFilename, const char* xmbFilename, + static void GetXMBPath(const char* xmlFilename, const char* xmbFilename, char* xmbPath); bool ReadXMBFile(const char* filename); diff --git a/source/ps/XML/tests/test_Xeromyces.h b/source/ps/XML/tests/test_Xeromyces.h new file mode 100644 index 0000000000..a01afde770 --- /dev/null +++ b/source/ps/XML/tests/test_Xeromyces.h @@ -0,0 +1,32 @@ +#include "lib/self_test.h" + +#include "ps/XML/Xeromyces.h" +#include "lib/res/file/vfs.h" +#include "lib/res/file/path.h" +#include "lib/res/file/trace.h" + +class TestXeromyces : public CxxTest::TestSuite +{ +public: + void test_paths() + { + file_init(); + path_init(); + file_set_root_dir(0, "../data"); + vfs_init(); + + vfs_mount("", "mods/_tests", VFS_MOUNT_RECURSIVE); + vfs_set_write_target("mods/_tests"); + + char xmbPath[PATH_MAX]; + + CXeromyces::GetXMBPath("test1.xml", "test1.xmb", xmbPath); + TS_ASSERT_STR_EQUALS(xmbPath, "cache/mods/_tests/xmb/test1.xmb"); + + CXeromyces::GetXMBPath("a/b/test1.xml", "a/b/test1.xmb", xmbPath); + TS_ASSERT_STR_EQUALS(xmbPath, "cache/mods/_tests/xmb/a/b/test1.xmb"); + + vfs_shutdown(); + path_reset_root_dir(); + } +}; diff --git a/source/ps/tests/test_CStr.h b/source/ps/tests/test_CStr.h index 60e4c82083..60f9b20b0d 100644 --- a/source/ps/tests/test_CStr.h +++ b/source/ps/tests/test_CStr.h @@ -8,12 +8,46 @@ class TestCStr : public CxxTest::TestSuite public: void test_utf8_utf16_conversion() { - const wchar_t chr_utf16[] = { 0x12, 0xff, 0x1234, 0x3456, 0x5678, 0x7890, 0x9abc, 0xbcde, 0xfffe }; - const unsigned char chr_utf8[] = { 0x12, 0xc3, 0xbf, 0xe1, 0x88, 0xb4, 0xe3, 0x91, 0x96, 0xe5, 0x99, 0xb8, 0xe7, 0xa2, 0x90, 0xe9, 0xaa, 0xbc, 0xeb, 0xb3, 0x9e, 0xef, 0xbf, 0xbe }; + const wchar_t chr_utf16[] = { + 0x12, + 0xff, + 0x1234, + 0x3456, + 0x5678, + 0x7890, + 0x9abc, + 0xbcde, + 0xfffe + }; + const unsigned char chr_utf8[] = { + 0x12, + 0xc3, 0xbf, + 0xe1, 0x88, 0xb4, + 0xe3, 0x91, 0x96, + 0xe5, 0x99, 0xb8, + 0xe7, 0xa2, 0x90, + 0xe9, 0xaa, 0xbc, + 0xeb, 0xb3, 0x9e, + 0xef, 0xbf, 0xbe + }; CStrW str_utf16 (chr_utf16, sizeof(chr_utf16)/sizeof(wchar_t)); + CStr8 str_utf8 = str_utf16.ToUTF8(); TS_ASSERT_EQUALS(str_utf8.length(), sizeof(chr_utf8)); TS_ASSERT_SAME_DATA(str_utf8.data(), chr_utf8, sizeof(chr_utf8)); - TS_ASSERT_EQUALS(str_utf8.FromUTF8(), str_utf16); + + CStrW str_utf16b = str_utf8.FromUTF8(); + TS_ASSERT_EQUALS(str_utf16b, str_utf16); + } + + void test_invalid_utf8() + { + const unsigned char chr_utf8_a[] = { 'a', 0xef }; + const unsigned char chr_utf8_b[] = { 'b', 0xef, 0xbf }; + const unsigned char chr_utf8_c[] = { 'c', 0xef, 0xbf, 0x01 }; + + TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_a, sizeof(chr_utf8_a)).FromUTF8(), L""); + TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_b, sizeof(chr_utf8_b)).FromUTF8(), L""); + TS_ASSERT_WSTR_EQUALS(CStr8((const char*)chr_utf8_c, sizeof(chr_utf8_c)).FromUTF8(), L""); } }; diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index a67a845bfb..f99ccabb9e 100644 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -625,11 +625,12 @@ JSBool startXTimer(JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rval JSU_REQUIRE_PARAMS(1); uint slot = ToPrimitive(argv[0]); - debug_assert(slot < MAX_XTIMERS); + if (slot >= MAX_XTIMERS) + return JS_FALSE; debug_assert(xstart_times[slot] == 0); xstart_times[slot] = xtimer_impl.get_timestamp(); - return( JS_TRUE ); + return JS_TRUE; } @@ -637,13 +638,14 @@ JSBool stopXTimer(JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rval) { JSU_REQUIRE_PARAMS(1); uint slot = ToPrimitive(argv[0]); - debug_assert(slot < MAX_XTIMERS); + if (slot >= MAX_XTIMERS) + return JS_FALSE; debug_assert(xstart_times[slot] != 0); XTimerImpl::unit dt = xtimer_impl.get_timestamp() - xstart_times[slot] - xoverhead; xstart_times[slot] = 0; timer_bill_client(&xclients[slot], dt); - return( JS_TRUE ); + return JS_TRUE; } diff --git a/source/tools/atlas/AtlasUI/Misc/stdafx.h b/source/tools/atlas/AtlasUI/Misc/stdafx.h index 6226c38251..1c7e789655 100644 --- a/source/tools/atlas/AtlasUI/Misc/stdafx.h +++ b/source/tools/atlas/AtlasUI/Misc/stdafx.h @@ -4,6 +4,10 @@ # define HAVE_PCH #endif +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# pragma warning(disable: 6334) +#endif + #ifdef HAVE_PCH // Exclude rarely-used stuff from Windows headers