From 0d2edb2f1bf1aff00bba67d77615e53cf935bd98 Mon Sep 17 00:00:00 2001 From: anders_k Date: Sun, 10 Mar 2013 22:26:27 +0000 Subject: [PATCH] Use dynamic buffer sizes for formated CEXEBuild warning/error methods git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6292 212acab6-be3b-0410-9dea-997c60f758d6 --- Source/build.cpp | 45 +++++++++++++++-------------------- Source/util.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ Source/util.h | 24 +++++++++++++++++++ 3 files changed, 104 insertions(+), 26 deletions(-) diff --git a/Source/build.cpp b/Source/build.cpp index 02b6681c..1630bdb9 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -492,7 +492,9 @@ int CEXEBuild::add_string(const TCHAR *string, int process/*=1*/, UINT codepage/ int i; if (process) { - TCHAR buf[NSIS_MAX_STRLEN*4]; + ExpandoString buf; + // NOTE: It is impossible to know how much preprocessing will increase the size, we have to guess + buf.Reserve(_tcsclen(string) * 2); preprocess_string(buf, string, codepage); i = cur_strlist->add(buf, (WORD)codepage, true); } @@ -3310,42 +3312,36 @@ bool IsStringASCII(const TCHAR* s) void CEXEBuild::warning(const TCHAR *s, ...) { - TCHAR buf[NSIS_MAX_STRLEN*10]; + ExpandoString buf; va_list val; va_start(val,s); -#ifdef _WIN32 - _vstprintf(buf,s,val); -#else - _vsntprintf(buf,NSIS_MAX_STRLEN*10,s,val); -#endif + buf.StrFmt(s,val); va_end(val); m_warnings.add(buf,0); - notify(MAKENSIS_NOTIFY_WARNING,buf); + notify(MAKENSIS_NOTIFY_WARNING,buf.GetPtr()); if (display_warnings) { - PrintColorFmtMsg_WARN(_T("warning: %s\n"),buf); + PrintColorFmtMsg_WARN(_T("warning: %s\n"),buf.GetPtr()); } } void CEXEBuild::warning_fl(const TCHAR *s, ...) { - TCHAR buf[NSIS_MAX_STRLEN*10]; + ExpandoString buf; va_list val; va_start(val,s); -#ifdef _WIN32 - _vstprintf(buf,s,val); -#else - _vsntprintf(buf,NSIS_MAX_STRLEN*10,s,val); -#endif + size_t cchMsg = buf.StrFmt(s,val); va_end(val); - _stprintf(buf+_tcslen(buf),_T(" (%s:%d)"),curfilename,linecnt); + + buf.Reserve(cchMsg+2+_tcslen(curfilename)+50+1+1); + _stprintf(&buf[cchMsg],_T(" (%s:%u)"),curfilename,linecnt); m_warnings.add(buf,0); - notify(MAKENSIS_NOTIFY_WARNING,buf); + notify(MAKENSIS_NOTIFY_WARNING,buf.GetPtr()); if (display_warnings) { - PrintColorFmtMsg_WARN(_T("warning: %s\n"),buf); + PrintColorFmtMsg_WARN(_T("warning: %s\n"),buf.GetPtr()); } } @@ -3353,19 +3349,16 @@ void CEXEBuild::ERROR_MSG(const TCHAR *s, ...) const { if (display_errors || notify_hwnd) { - TCHAR buf[NSIS_MAX_STRLEN*10]; + ExpandoString buf; va_list val; va_start(val,s); -#ifdef _WIN32 - _vstprintf(buf,s,val); -#else - _vsntprintf(buf,NSIS_MAX_STRLEN*10,s,val); -#endif + buf.StrFmt(s,val); va_end(val); - notify(MAKENSIS_NOTIFY_ERROR,buf); + + notify(MAKENSIS_NOTIFY_ERROR,buf.GetPtr()); if (display_errors) { - PrintColorFmtMsg_ERR(_T("%s"),buf); + PrintColorFmtMsg_ERR(_T("%s"),buf.GetPtr()); } } } diff --git a/Source/util.cpp b/Source/util.cpp index b4b1364e..491a5c21 100644 --- a/Source/util.cpp +++ b/Source/util.cpp @@ -552,6 +552,67 @@ tstring lowercase(const tstring &str) { return result; } +/* + * ExpandoStrFmtVaList returns the number of characters written excluding + * the \0 terminator or 0 on error. + * realloc() is used on *ppMalloc if cchStack is not + * large enough to hold the formated string. +*/ +size_t ExpandoStrFmtVaList(wchar_t*Stack, size_t cchStack, wchar_t**ppMalloc, const wchar_t*FmtStr, va_list Args) +{ +#ifdef _WIN32 +// For _vsnwprintf, the \0 terminator is not part of the size +#define ExpandoStrFmtVaList_vsnwprintf(d,c,f,v) _vsnwprintf((d),(c)?(c)-1:0,(f),(v)) +#else +#define ExpandoStrFmtVaList_vsnwprintf vswprintf +#endif +#if defined(_ISOC99_SOURCE) || _POSIX_C_SOURCE >= 200112L + const bool cansizecalc = true, msvcbackdoor = false; +#else + static char testedsizecalc = 0; + if (!testedsizecalc) + { +#ifdef _WIN32 + size_t cch = ExpandoStrFmtVaList_vsnwprintf(0, INT_MAX, L"333", Args); +#else + wchar_t testbuf[1+1]; + size_t cch = ExpandoStrFmtVaList_vsnwprintf(testbuf, COUNTOF(testbuf), L"333", Args); +#endif + testedsizecalc = (3 == cch) + 1; + } +#ifdef _WIN32 + const bool msvcbackdoor = !!(testedsizecalc - 1), cansizecalc = false; +#else + const bool cansizecalc = !!(testedsizecalc - 1), msvcbackdoor = false; +#endif +#endif + size_t &cchAvail = cchStack, cch; + wchar_t *&dest = Stack, *mem = *ppMalloc; + for(;;) + { + cch = ExpandoStrFmtVaList_vsnwprintf(dest, cchAvail, FmtStr, Args); + if (-1 == cch) + { + cch = 0; + if (cansizecalc) break; // vswprintf error, abort! + if (msvcbackdoor) + cchAvail = ExpandoStrFmtVaList_vsnwprintf(0, INT_MAX, FmtStr, Args) + 1; + else + cchAvail = 4 * STD_MAX(cchAvail, (size_t)500); + } + else + { + if (cch < cchAvail) break; // We are done. + cchAvail = ++cch; // cch from vswprintf did not include the \0 terminator + } + dest = mem = (wchar_t*) realloc(mem, cchAvail * sizeof(wchar_t)); + if (!mem) return 0; + } + *ppMalloc = mem; + return cch; +} + + int sane_system(const TCHAR *command) { #ifdef _WIN32 diff --git a/Source/util.h b/Source/util.h index f93a80e1..7234dddd 100644 --- a/Source/util.h +++ b/Source/util.h @@ -56,6 +56,30 @@ tstring lowercase(const tstring&); tstring get_string_prefix(const tstring& str, const tstring& separator); tstring get_string_suffix(const tstring& str, const tstring& separator); +size_t ExpandoStrFmtVaList(wchar_t*Stack, size_t cchStack, wchar_t**ppMalloc, const wchar_t*FmtStr, va_list Args); + +template class ExpandoString { + T m_stack[S ? S : 1], *m_heap; +public: + ExpandoString() : m_heap(0) {} + ~ExpandoString() { free(m_heap); } + void Reserve(size_t cch) + { + if (S && cch <= S) return ; + void *p = realloc(m_heap, cch * sizeof(T)); + if (!p) throw std::bad_alloc(); + m_heap = (T*) p; + } + size_t StrFmt(const T*FmtStr, va_list Args) + { + size_t n = ExpandoStrFmtVaList(m_stack, COUNTOF(m_stack), &m_heap, FmtStr, Args); + if (!n && *FmtStr) throw std::bad_alloc(); + return n; + } + T* GetPtr() { return m_heap ? m_heap : m_stack; } + operator T*() { return GetPtr(); } +}; + int sane_system(const TCHAR *command); void PrintColorFmtMsg(unsigned int type, const TCHAR *fmtstr, va_list args);