Skip to content

Commit 8e471e0

Browse files
Andy Leminrdmark
authored andcommitted
testsuite: refactored lantest_dircache_stats.c to use static log buffer to overcome SonarQube static analysis warnings
1 parent be33e33 commit 8e471e0

File tree

2 files changed

+75
-72
lines changed

2 files changed

+75
-72
lines changed

test/testsuite/lantest.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,7 @@
1313
* GNU General Public License for more details.
1414
*/
1515

16-
/* Feature test macros for strdup and other POSIX functions - MUST be before any includes */
17-
#ifndef _GNU_SOURCE
18-
#define _GNU_SOURCE
19-
#endif
20-
#ifndef _DEFAULT_SOURCE
21-
#define _DEFAULT_SOURCE
22-
#endif
23-
#ifndef _POSIX_C_SOURCE
24-
#define _POSIX_C_SOURCE 200112L
25-
#endif
26-
16+
/* Specs must be first */
2717
#include "specs.h"
2818

2919
/* Standard C library includes */

test/testsuite/lantest_dircache_stats.c

Lines changed: 74 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,19 @@
4646
extern bool Debug;
4747

4848
/* Constants */
49-
#define LOG_BUFFER_SIZE (100 * 1024) /* 100KB buffer for reading log file */
50-
#define MAX_LOG_LINES_DISPLAY 10 /* Number of log lines to show when no stats found */
49+
/* 100KB buffer for reading log file */
50+
#define LOG_BUFFER_SIZE (100 * 1024)
51+
/* Number of log lines to show when no stats found */
52+
#define MAX_LOG_LINES_DISPLAY 10
53+
54+
/* Static buffer for reading log file - shared across functions */
55+
static char log_buffer[LOG_BUFFER_SIZE + 1];
56+
/* Actual number of bytes read into log_buffer */
57+
static size_t log_buffer_bytes_read = 0;
58+
59+
/* Compile-time assertion to ensure buffer size is reasonable */
60+
_Static_assert(LOG_BUFFER_SIZE > 0 && LOG_BUFFER_SIZE <= (1024 * 1024),
61+
"LOG_BUFFER_SIZE must be between 1 byte and 1MB");
5162

5263
/* Debug logging macro */
5364
#define DEBUG_LOG(fmt, ...) \
@@ -62,7 +73,6 @@ static char *parse_config_for_log_path(void)
6273
dictionary *iniconfig = NULL;
6374
char *log_file_path = NULL;
6475
DEBUG_LOG("Loading config file: %safp.conf", _PATH_CONFDIR);
65-
/* Load the config file using iniparser */
6676
iniconfig = iniparser_load(_PATH_CONFDIR "afp.conf");
6777

6878
if (!iniconfig) {
@@ -90,25 +100,20 @@ static char *parse_config_for_log_path(void)
90100
return log_file_path;
91101
}
92102

93-
/* Read the last portion of log file into buffer
94-
* Buffer must be at least LOG_BUFFER_SIZE + 1 bytes */
95-
static ssize_t read_log_tail(const char *log_file_path, char *buffer)
103+
/* Read the last portion of log file into the static log_buffer
104+
* Returns: true on success, false on error */
105+
static bool read_log_tail(const char *log_file_path)
96106
{
97107
FILE *log_fp = NULL;
98-
99-
/* Validate input parameters */
100-
if (!buffer) {
101-
fprintf(stderr, "ERROR: Buffer is NULL\n");
102-
return -1;
103-
}
104-
108+
/* Reset global state */
109+
log_buffer_bytes_read = 0;
105110
DEBUG_LOG("Opening log file: %s", log_file_path);
106111
log_fp = fopen(log_file_path, "rb");
107112

108113
if (!log_fp) {
109114
DEBUG_LOG("Failed to open log file: %s (errno=%d: %s)",
110115
log_file_path, errno, strerror(errno));
111-
return -1;
116+
return false;
112117
}
113118

114119
DEBUG_LOG("Successfully opened log file");
@@ -117,7 +122,7 @@ static ssize_t read_log_tail(const char *log_file_path, char *buffer)
117122
fprintf(stderr, "ERROR: Failed to seek to end of log file: %s\n",
118123
strerror(errno));
119124
fclose(log_fp);
120-
return -1;
125+
return false;
121126
}
122127

123128
long file_size = ftell(log_fp);
@@ -126,76 +131,82 @@ static ssize_t read_log_tail(const char *log_file_path, char *buffer)
126131
fprintf(stderr, "ERROR: Failed to determine log file size: %s\n",
127132
strerror(errno));
128133
fclose(log_fp);
129-
return -1;
134+
return false;
130135
}
131136

132137
DEBUG_LOG("Log file size: %ld bytes", file_size);
133138

134139
if (file_size <= 0) {
135140
fprintf(stderr, "WARNING: Log file size is 0, no content to read\n");
136141
fclose(log_fp);
137-
return 0;
142+
/* Not an error, just no content */
143+
return true;
138144
}
139145

140146
/* Read from the end, up to LOG_BUFFER_SIZE to reserve space for null terminator */
141-
size_t max_read = LOG_BUFFER_SIZE;
142-
long read_start = (file_size > (long)max_read) ? (file_size -
143-
(long)max_read) : 0;
144-
size_t read_size = (file_size > (long)max_read) ? max_read :
147+
long read_start = (file_size > LOG_BUFFER_SIZE) ? (file_size - LOG_BUFFER_SIZE)
148+
: 0;
149+
size_t read_size = (file_size > LOG_BUFFER_SIZE) ? LOG_BUFFER_SIZE :
145150
(size_t)file_size;
146151
DEBUG_LOG("Reading %zu bytes from position: %ld", read_size, read_start);
147152

148153
if (fseek(log_fp, read_start, SEEK_SET) != 0) {
149154
fprintf(stderr, "ERROR: Failed to seek to read position: %s\n",
150155
strerror(errno));
151156
fclose(log_fp);
152-
return -1;
157+
return false;
153158
}
154159

155-
size_t bytes_read = fread(buffer, 1, read_size, log_fp);
160+
size_t bytes_read = fread(log_buffer, 1, read_size, log_fp);
156161

157162
if (ferror(log_fp)) {
158163
fprintf(stderr, "ERROR: Failed to read log file: %s\n", strerror(errno));
159164
fclose(log_fp);
160-
return -1;
165+
return false;
161166
}
162167

163-
/* Simple validation - fread cannot return more than requested */
164-
if (bytes_read > read_size) {
165-
fprintf(stderr, "ERROR: fread returned more bytes than requested\n");
168+
/* Explicit bounds check and enforcement for static analyzer */
169+
if (bytes_read > LOG_BUFFER_SIZE) {
170+
fprintf(stderr, "ERROR: Read more bytes than buffer size (corruption?)\n");
166171
fclose(log_fp);
167-
return -1;
172+
return false;
173+
}
174+
175+
/* Explicitly cap the value to help static analyzer understand the bound */
176+
if (bytes_read > LOG_BUFFER_SIZE) {
177+
bytes_read = LOG_BUFFER_SIZE;
168178
}
169179

170-
/* Null-terminate the buffer
171-
* Since read_size <= LOG_BUFFER_SIZE and bytes_read <= read_size,
172-
* we know bytes_read <= LOG_BUFFER_SIZE, so this is always safe */
173-
buffer[bytes_read] = '\0';
180+
/* Null-terminate the buffer - always safe with static buffer */
181+
log_buffer[bytes_read] = '\0';
182+
log_buffer_bytes_read = bytes_read;
174183
fclose(log_fp);
175-
return (ssize_t)bytes_read;
184+
return true;
176185
}
177186

178-
/* Search buffer backwards for dircache statistics line */
179-
static char *find_dircache_stats_line(const char *buffer, size_t bytes_read)
187+
/* Search buffer backwards for dircache statistics line
188+
* Uses the global log_buffer and log_buffer_bytes_read */
189+
static char *find_dircache_stats_line(void)
180190
{
181191
char *stats_line = NULL;
182192

183-
/* Validate bytes_read before using for allocation */
184-
if (bytes_read == 0 || bytes_read > LOG_BUFFER_SIZE) {
193+
if (log_buffer_bytes_read == 0) {
185194
return NULL;
186195
}
187196

188-
/* Make a working copy of the buffer to avoid const issues */
189-
char *work_buffer = malloc(bytes_read + 1);
197+
/* Make a working copy of the static buffer to avoid modifying it
198+
* log_buffer_bytes_read is guaranteed <= LOG_BUFFER_SIZE by read_log_tail() */
199+
char *work_buffer = malloc(log_buffer_bytes_read + 1);
190200

191201
if (!work_buffer) {
192202
return NULL;
193203
}
194204

195-
memcpy(work_buffer, buffer, bytes_read);
196-
work_buffer[bytes_read] = '\0';
205+
/* Safe copy - log_buffer_bytes_read is bounded by LOG_BUFFER_SIZE */
206+
memcpy(work_buffer, log_buffer, log_buffer_bytes_read);
207+
work_buffer[log_buffer_bytes_read] = '\0';
197208
/* Search backwards through buffer for the LAST dircache statistics line */
198-
char *current = work_buffer + bytes_read;
209+
char *current = work_buffer + log_buffer_bytes_read;
199210

200211
while (current > work_buffer) {
201212
/* Find end of previous line */
@@ -238,34 +249,34 @@ static char *find_dircache_stats_line(const char *buffer, size_t bytes_read)
238249
}
239250

240251
/* Display the last N lines from buffer when no stats found */
241-
static void display_last_log_lines(const char *buffer, size_t bytes_read)
252+
static void display_last_log_lines(void)
242253
{
243-
/* No dircache statistics found - print message and last 10 lines of log */
244254
printf("No 'dircache statistics:' logs found.\n\n");
245255
printf("(At least 'log level = default:info' is required)\n");
246256
printf("Last 10 lines of log file:\n");
247257
printf("---------------------------\n");
248258

249-
/* Validate bytes_read before using for allocation */
250-
if (bytes_read == 0 || bytes_read > LOG_BUFFER_SIZE) {
251-
printf("Invalid buffer size\n");
259+
if (log_buffer_bytes_read == 0) {
260+
printf("No log content available\n");
252261
return;
253262
}
254263

255-
/* Make a working copy of the buffer to avoid const issues */
256-
char *work_buffer = malloc(bytes_read + 1);
264+
/* Make a working copy of the static buffer
265+
* log_buffer_bytes_read is guaranteed <= LOG_BUFFER_SIZE by read_log_tail() */
266+
char *work_buffer = malloc(log_buffer_bytes_read + 1);
257267

258268
if (!work_buffer) {
259269
printf("Memory allocation failed\n");
260270
return;
261271
}
262272

263-
memcpy(work_buffer, buffer, bytes_read);
264-
work_buffer[bytes_read] = '\0';
273+
/* Safe copy - log_buffer_bytes_read is bounded by LOG_BUFFER_SIZE */
274+
memcpy(work_buffer, log_buffer, log_buffer_bytes_read);
275+
work_buffer[log_buffer_bytes_read] = '\0';
265276
/* Search backwards through buffer for last 10 lines */
266277
char *last_lines[MAX_LOG_LINES_DISPLAY] = {NULL};
267278
int line_count = 0;
268-
char *curr = work_buffer + bytes_read;
279+
char *curr = work_buffer + log_buffer_bytes_read;
269280

270281
while (curr > work_buffer && line_count < MAX_LOG_LINES_DISPLAY) {
271282
/* Find end of previous line */
@@ -326,8 +337,7 @@ void display_dircache_statistics(void)
326337
{
327338
char *log_file_path = NULL;
328339
char *stats_line = NULL;
329-
static char buffer[LOG_BUFFER_SIZE + 1];
330-
ssize_t bytes_read;
340+
bool read_success;
331341
log_file_path = parse_config_for_log_path();
332342

333343
if (!log_file_path) {
@@ -337,21 +347,24 @@ void display_dircache_statistics(void)
337347
}
338348

339349
DEBUG_LOG("Log file path: %s", log_file_path);
340-
bytes_read = read_log_tail(log_file_path, buffer, sizeof(buffer));
350+
read_success = read_log_tail(log_file_path);
341351

342-
if (bytes_read <= 0) {
352+
if (!read_success) {
343353
free(log_file_path);
344354
return;
345355
}
346356

347-
/* Validate bytes_read is positive and reasonable before casting */
348-
if (bytes_read < 0 || bytes_read > LOG_BUFFER_SIZE) {
349-
fprintf(stderr, "ERROR: Invalid bytes_read value: %zd\n", bytes_read);
357+
/* Check if we actually read any content */
358+
if (log_buffer_bytes_read == 0) {
359+
printf("\nDircache Statistics (%s):\n", log_file_path);
360+
printf("------------------------------------------------------------------\n");
361+
printf("Log file is empty\n");
350362
free(log_file_path);
351363
return;
352364
}
353365

354-
stats_line = find_dircache_stats_line(buffer, (size_t)bytes_read);
366+
/* Search for dircache statistics line using global buffer */
367+
stats_line = find_dircache_stats_line();
355368
printf("\nDircache Statistics (%s):\n", log_file_path);
356369
printf("------------------------------------------------------------------\n");
357370

@@ -366,7 +379,7 @@ void display_dircache_statistics(void)
366379

367380
free(stats_line);
368381
} else {
369-
display_last_log_lines(buffer, (size_t)bytes_read);
382+
display_last_log_lines();
370383
}
371384

372385
free(log_file_path);

0 commit comments

Comments
 (0)