Skip to content

Commit 584df7c

Browse files
authored
Merge pull request #1576 from bratpiorka/rrudnick_log_fix
fix potential mem corruption in utils_log_internal
2 parents c7fdae5 + b0d6724 commit 584df7c

2 files changed

Lines changed: 109 additions & 31 deletions

File tree

src/utils/utils_log.c

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
*
3-
* Copyright (C) 2024-2025 Intel Corporation
3+
* Copyright (C) 2024-2026 Intel Corporation
44
*
55
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
66
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -72,6 +72,46 @@ typedef struct {
7272
utils_log_config_t loggerConfig = {false, false, LOG_ERROR,
7373
LOG_ERROR, NULL, ""};
7474

75+
static void log_buffer_advance(char **pos, size_t *size, size_t written) {
76+
ASSERT(pos);
77+
ASSERT(size);
78+
79+
// do nothing if the size is 0 or can only hold the NULL terminator
80+
if (*size <= 1) {
81+
*size = 0;
82+
return;
83+
}
84+
85+
size_t advance = utils_min(written, *size - 1);
86+
*pos += advance;
87+
88+
if (written >= *size) {
89+
*size = 0;
90+
return;
91+
}
92+
93+
*size -= advance;
94+
}
95+
96+
static void log_buffer_append(char **pos, size_t *size, const char *src) {
97+
ASSERT(pos);
98+
ASSERT(size);
99+
ASSERT(src);
100+
101+
if (*size == 0) {
102+
return;
103+
}
104+
105+
size_t src_len = strlen(src);
106+
size_t copy_len = utils_min(src_len, *size - 1);
107+
memcpy(*pos, src, copy_len);
108+
109+
// copy_len excludes the trailing NULL, add it explicitly
110+
(*pos)[copy_len] = '\0';
111+
112+
log_buffer_advance(pos, size, src_len);
113+
}
114+
75115
static const char *level_to_str(utils_log_level_t l) {
76116
switch (l) {
77117
case LOG_DEBUG:
@@ -113,24 +153,29 @@ static void utils_log_internal(utils_log_level_t level, int perror,
113153

114154
char buffer[LOG_MAX];
115155
char *b_pos = buffer;
116-
int b_size = sizeof(buffer);
156+
size_t b_size = sizeof(buffer);
117157

118158
int tmp = 0;
119159
if (fileline == NULL) {
120160
tmp = snprintf(b_pos, b_size, "%s: ", func);
121161
} else {
122162
tmp = snprintf(b_pos, b_size, "%s %s: ", fileline, func);
123163
}
124-
ASSERT(tmp > 0);
125164

126-
b_pos += (int)tmp;
127-
b_size -= (int)tmp;
165+
if (tmp < 0) {
166+
return; // snprintf error
167+
}
168+
169+
size_t written = (size_t)tmp;
170+
log_buffer_advance(&b_pos, &b_size, written);
128171

129172
tmp = vsnprintf(b_pos, b_size, format, args);
130-
ASSERT(tmp > 0);
173+
if (tmp < 0) {
174+
return; // vsnprintf error
175+
}
131176

132-
b_pos += (int)tmp;
133-
b_size -= (int)tmp;
177+
written = (size_t)tmp;
178+
log_buffer_advance(&b_pos, &b_size, written);
134179

135180
const char *postfix = "";
136181

@@ -139,10 +184,12 @@ static void utils_log_internal(utils_log_level_t level, int perror,
139184
strncat(b_pos, ": ", b_size);
140185
b_pos += 2;
141186
b_size -= 2;
187+
const char *err = "";
142188
#if defined(_WIN32)
143-
char err[80]; // max size according to msdn
144-
if (strerror_s(err, sizeof(err), errno)) {
145-
*err = '\0';
189+
char err_buff[80]; // max size according to msdn
190+
err = err_buff;
191+
if (strerror_s(err_buff, sizeof(err_buff), errno)) {
192+
*err_buff = '\0';
146193
postfix = "[strerror_s failed]";
147194
}
148195
#else
@@ -151,33 +198,27 @@ static void utils_log_internal(utils_log_level_t level, int perror,
151198

152199
#if defined(__APPLE__) || \
153200
((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
154-
char err[1024];
155-
int ret = strerror_r(saveno, err, sizeof(err));
201+
char err_buff[1024];
202+
err = err_buff;
203+
int ret = strerror_r(saveno, err_buff, sizeof(err_buff));
156204
if (ret) {
157-
*err = '\0';
205+
*err_buff = '\0';
158206
postfix = "[strerror_r failed]";
159207
}
160208
if (errno == ERANGE) {
161209
postfix = "[truncated...]";
162210
}
163211
#else
164212
char err_buff[1024];
165-
const char *err = strerror_r(saveno, err_buff, sizeof(err_buff));
213+
err = strerror_r(saveno, err_buff, sizeof(err_buff));
166214
if (errno == ERANGE) {
167215
postfix = "[truncated...]";
168216
}
169217
#endif
170218

171219
errno = saveno;
172220
#endif
173-
strncpy(b_pos, err, b_size);
174-
size_t err_size = strlen(err);
175-
b_pos += err_size;
176-
b_size -= (int)err_size;
177-
if (b_size <= 0) {
178-
buffer[LOG_MAX - 1] =
179-
'\0'; //strncpy do not add \0 in case of overflow
180-
}
221+
log_buffer_append(&b_pos, &b_size, err);
181222
} else {
182223
postfix = "[truncated...]";
183224
}
@@ -190,7 +231,7 @@ static void utils_log_internal(utils_log_level_t level, int perror,
190231

191232
char header[LOG_HEADER];
192233
char *h_pos = header;
193-
int h_size = sizeof(header);
234+
size_t h_size = sizeof(header);
194235
memset(header, 0, sizeof(header));
195236

196237
if (loggerConfig.enableTimestamp) {
@@ -202,18 +243,22 @@ static void utils_log_internal(utils_log_level_t level, int perror,
202243
localtime_r(&now, &tm_info);
203244
#endif
204245

205-
ASSERT(h_size > 0);
206-
tmp = (int)strftime(h_pos, h_size, "%Y-%m-%dT%H:%M:%S ", &tm_info);
207-
h_pos += tmp;
208-
h_size -= tmp;
246+
written = strftime(h_pos, h_size, "%Y-%m-%dT%H:%M:%S ", &tm_info);
247+
if (written == 0 && h_size > 0) {
248+
h_pos[0] = '\0';
249+
}
250+
log_buffer_advance(&h_pos, &h_size, written);
209251
}
210252

211253
if (loggerConfig.enablePid) {
212254
ASSERT(h_size > 0);
213255
tmp = snprintf(h_pos, h_size, "PID:%-6lu TID:%-6lu ",
214256
(unsigned long)pid, (unsigned long)tid);
215-
h_pos += tmp;
216-
h_size -= tmp;
257+
if (tmp < 0) {
258+
return; // snprintf error
259+
}
260+
written = (size_t)tmp;
261+
log_buffer_advance(&h_pos, &h_size, written);
217262
}
218263

219264
// We take twice header size here to ensure that
@@ -222,6 +267,7 @@ static void utils_log_internal(utils_log_level_t level, int perror,
222267
char logLine[LOG_MAX + LOG_HEADER * 2];
223268
snprintf(logLine, sizeof(logLine), "[%s%-5s UMF] %s%s\n", header,
224269
level_to_str(level), buffer, postfix);
270+
225271
FILE *out = loggerConfig.output ? loggerConfig.output : stderr;
226272
fputs(logLine, out);
227273

test/utils/utils_log.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2024-2025 Intel Corporation
1+
// Copyright (C) 2024-2026 Intel Corporation
22
// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
33
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44

@@ -368,6 +368,38 @@ TEST_F(test, long_log) {
368368
std::string(8190 - MOCK_FN_NAME.size(), 'x').c_str());
369369
}
370370

371+
TEST_F(test, long_func_name) {
372+
expect_fput_count = 1;
373+
expect_fflush_count = 1;
374+
loggerConfig =
375+
utils_log_config_t{false, false, LOG_DEBUG, LOG_DEBUG, stderr, ""};
376+
377+
std::string long_func(LOG_MAX, 'f');
378+
expected_message =
379+
"[DEBUG UMF] " + long_func.substr(0, LOG_MAX - 1) + "[truncated...]\n";
380+
381+
helper_test_log(LOG_DEBUG, long_func.c_str(), "%s", "tail");
382+
}
383+
384+
TEST_F(test, long_fileline_and_func_name) {
385+
expect_fput_count = 1;
386+
expect_fflush_count = 1;
387+
loggerConfig =
388+
utils_log_config_t{false, false, LOG_DEBUG, LOG_DEBUG, stderr, ""};
389+
390+
std::string long_fileline(LOG_MAX, 'l');
391+
std::string long_func(LOG_MAX, 'f');
392+
expected_message = "[DEBUG UMF] " + long_fileline.substr(0, LOG_MAX - 1) +
393+
"[truncated...]\n";
394+
395+
fput_count = 0;
396+
fflush_count = 0;
397+
utils_log(LOG_DEBUG, long_fileline.c_str(), long_func.c_str(), "%s",
398+
"tail");
399+
EXPECT_EQ(fput_count, expect_fput_count);
400+
EXPECT_EQ(fflush_count, expect_fflush_count);
401+
}
402+
371403
TEST_F(test, timestamp_log) {
372404
expect_fput_count = 1;
373405
expect_fflush_count = 1;

0 commit comments

Comments
 (0)