@@ -22,9 +22,11 @@ to be replaced by the proper DefaultErrorHandler()
2222
2323#include " TError.h"
2424
25+ #include < cassert>
2526#include < cstdarg>
2627#include < cstdio>
2728#include < cstdlib>
29+ #include < cstring>
2830#include < cerrno>
2931#include < string>
3032
@@ -108,46 +110,59 @@ ErrorHandlerFunc_t GetErrorHandler()
108110
109111void ErrorHandler (Int_t level, const char *location, const char *fmt, std::va_list ap)
110112{
111- thread_local Int_t buf_size ( 256 );
112- thread_local char * buf_storage ( nullptr ) ;
113+ if (!fmt)
114+ fmt = " no error message provided " ;
113115
114- char small_buf[256 ];
115- char *buf = buf_storage ? buf_storage : small_buf;
116+ char smallBuf[256 ];
116117
117- std::va_list ap_copy ;
118- va_copy (ap_copy, ap) ;
118+ thread_local int bufSize = sizeof (smallBuf) ;
119+ thread_local char *bufDynStorage = nullptr ;
119120
120- if (!fmt)
121- fmt = " no error message provided" ;
121+ char *buf = bufDynStorage ? bufDynStorage : smallBuf;
122122
123- Int_t n = vsnprintf (buf, buf_size, fmt, ap_copy);
124- if (n >= buf_size) {
125- va_end (ap_copy);
123+ std::va_list apCopy;
124+ va_copy (apCopy, ap);
125+
126+ // Figure out exactly how many bytes we need
127+ int nRequired = vsnprintf (nullptr , 0 , fmt, ap) + 1 ;
128+ if (level >= kSysError && level < kFatal ) {
129+ auto sysHandler = GetErrorSystemMsgHandlerRef ();
130+ if (sysHandler)
131+ nRequired += strlen (sysHandler ()) + 1 ; // +1 for the whitespace
132+ else {
133+ nRequired += snprintf (nullptr , 0 , " (errno: %d)" , errno) + 1 ;
134+ }
135+ }
126136
127- buf_size = n + 1 ;
128- if (buf != &(small_buf[0 ]))
137+ if (nRequired >= bufSize) {
138+ // Not enough space: allocate more space on the heap to fit the string
139+ if (buf != smallBuf)
129140 delete[] buf;
130- buf_storage = buf = new char [buf_size];
131141
132- // Try again with a sufficiently large buffer
133- va_copy (ap_copy, ap);
134- vsnprintf (buf, buf_size, fmt, ap_copy);
142+ bufSize = std::max (bufSize * 2 , nRequired + 1 );
143+ buf = bufDynStorage = new char [bufSize];
135144 }
136- va_end (ap_copy);
137145
138- std::string bp = buf;
146+ // Actually write the string
147+ int nWrittenPre = vsnprintf (buf, bufSize, fmt, apCopy);
148+ int nWrittenPost = 0 ;
139149 if (level >= kSysError && level < kFatal ) {
140- bp.push_back (' ' );
141- if (GetErrorSystemMsgHandlerRef ())
142- bp += GetErrorSystemMsgHandlerRef ()();
143- else
144- bp += std::string (" (errno: " ) + std::to_string (errno) + " )" ;
150+ auto sysHandler = GetErrorSystemMsgHandlerRef ();
151+ if (sysHandler) {
152+ // NOTE: overwriting the null byte written by the previous vsnprintf
153+ nWrittenPost = snprintf (buf + nWrittenPre, bufSize - nWrittenPre, " %s" , sysHandler ());
154+ } else {
155+ // NOTE: overwriting the null byte written by the previous vsnprintf
156+ nWrittenPost = snprintf (buf + nWrittenPre, bufSize - nWrittenPre, " (errno: %d)" , errno);
157+ }
145158 }
159+ assert (nWrittenPre + nWrittenPost + 1 <= nRequired);
160+ va_end (apCopy);
146161
147162 if (level != kFatal )
148- gErrorHandler (level, level >= gErrorAbortLevel , location, bp. c_str () );
163+ gErrorHandler (level, level >= gErrorAbortLevel , location, buf );
149164 else
150- gErrorHandler (level, kTRUE , location, bp. c_str () );
165+ gErrorHandler (level, kTRUE , location, buf );
151166}
152167
153168// //////////////////////////////////////////////////////////////////////////////
0 commit comments