Skip to content

Commit a762654

Browse files
committed
[core] avoid second call to vsnprintf if possible in ErrorHandler()
1 parent c07a29c commit a762654

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

core/foundation/src/TError.cxx

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,41 +123,48 @@ void ErrorHandler(Int_t level, const char *location, const char *fmt, std::va_li
123123
std::va_list apCopy;
124124
va_copy(apCopy, ap);
125125

126-
// Figure out exactly how many bytes we need
127-
int nRequired = vsnprintf(nullptr, 0, fmt, ap) + 1;
126+
// Write the user string to the current buffer and, at the same time, figure out exactly how many bytes we need.
127+
int nWritten = vsnprintf(buf, bufSize, fmt, ap);
128+
int nAdditional = 0;
128129
if (level >= kSysError && level < kFatal) {
129130
auto sysHandler = GetErrorSystemMsgHandlerRef();
130131
if (sysHandler)
131-
nRequired += strlen(sysHandler()) + 1; // +1 for the whitespace
132+
nAdditional = strlen(sysHandler()) + 1; // +1 for the whitespace
132133
else {
133-
nRequired += snprintf(nullptr, 0, " (errno: %d)", errno) + 1;
134+
nAdditional = snprintf(nullptr, 0, " (errno: %d)", errno);
134135
}
135136
}
136137

138+
// nWritten and nAdditional are the number of characters, nRequired is the required
139+
// number of bytes, hence the + 1 for the null terminator.
140+
int nRequired = nWritten + nAdditional + 1;
137141
if (nRequired >= bufSize) {
138-
// Not enough space: allocate more space on the heap to fit the string
142+
// Not enough space: allocate more space on the heap to fit the string.
139143
if (buf != smallBuf)
140144
delete[] buf;
141145

142-
bufSize = std::max(bufSize * 2, nRequired + 1);
146+
bufSize = std::max(bufSize * 2, nRequired);
143147
buf = bufDynStorage = new char[bufSize];
148+
// Write the user string again in the new buffer.
149+
vsnprintf(buf, bufSize, fmt, apCopy);
144150
}
151+
va_end(apCopy);
152+
153+
assert(nRequired <= bufSize);
145154

146-
// Actually write the string
147-
int nWrittenPre = vsnprintf(buf, bufSize, fmt, apCopy);
155+
// if necessary, write the additional string.
156+
// NOTE: this will overwrite the null byte written by the previous vsnprintf, extending the string.
148157
int nWrittenPost = 0;
149-
if (level >= kSysError && level < kFatal) {
158+
if (nAdditional > 0) {
150159
auto sysHandler = GetErrorSystemMsgHandlerRef();
151160
if (sysHandler) {
152-
// NOTE: overwriting the null byte written by the previous vsnprintf
153-
nWrittenPost = snprintf(buf + nWrittenPre, bufSize - nWrittenPre, " %s", sysHandler());
161+
nWrittenPost = snprintf(buf + nWritten, bufSize - nWritten, " %s", sysHandler());
154162
} else {
155-
// NOTE: overwriting the null byte written by the previous vsnprintf
156-
nWrittenPost = snprintf(buf + nWrittenPre, bufSize - nWrittenPre, " (errno: %d)", errno);
163+
nWrittenPost = snprintf(buf + nWritten, bufSize - nWritten, " (errno: %d)", errno);
157164
}
158165
}
159-
assert(nWrittenPre + nWrittenPost + 1 <= nRequired);
160-
va_end(apCopy);
166+
assert(nWrittenPost == nAdditional);
167+
assert(nWritten + nWrittenPost + 1 <= nRequired);
161168

162169
if (level != kFatal)
163170
gErrorHandler(level, level >= gErrorAbortLevel, location, buf);

0 commit comments

Comments
 (0)