Skip to content

Commit 9497f56

Browse files
Jim HsuChAoSUnItY
authored andcommitted
feat: Add snprintf
This patch adds snprintf. The second parameter "size" is expected to accept only zero or positive integer, otherwise as C11 specification states, it would be undefined behavior. Co-authored-by: Jim Hsu <[email protected]>
1 parent a603970 commit 9497f56

File tree

8 files changed

+103
-92
lines changed

8 files changed

+103
-92
lines changed

lib/c.c

Lines changed: 38 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -288,60 +288,63 @@ int __format(char *buffer,
288288
return bi;
289289
}
290290

291-
void printf(char *str, ...)
291+
int __format_to_buf(char *buffer, char *format, int *var_args, int size)
292292
{
293-
int *var_args = &str + 4;
294-
char buffer[200];
295293
int si = 0, bi = 0, pi = 0;
296294

297-
while (str[si]) {
298-
if (str[si] != '%') {
299-
buffer[bi] = str[si];
295+
if (size == 0)
296+
return 0;
297+
298+
while (format[si]) {
299+
if (bi >= size - 1) {
300+
break;
301+
} else if (format[si] != '%') {
302+
buffer[bi] = format[si];
300303
bi++;
301304
si++;
302305
} else {
303306
int w = 0, zp = 0, pp = 0;
304307

305308
si++;
306-
if (str[si] == '#') {
309+
if (format[si] == '#') {
307310
pp = 1;
308311
si++;
309312
}
310-
if (str[si] == '0') {
313+
if (format[si] == '0') {
311314
zp = 1;
312315
si++;
313316
}
314-
if (str[si] >= '1' && str[si] <= '9') {
315-
w = str[si] - '0';
317+
if (format[si] >= '1' && format[si] <= '9') {
318+
w = format[si] - '0';
316319
si++;
317-
while (str[si] >= '0' && str[si] <= '9') {
320+
while (format[si] >= '0' && format[si] <= '9') {
318321
w *= 10;
319-
w += str[si] - '0';
322+
w += format[si] - '0';
320323
si++;
321324
}
322325
}
323-
if (str[si] == 's') {
326+
if (format[si] == 's') {
324327
/* append param pi as string */
325328
int l = strlen(var_args[pi]);
326329
strcpy(buffer + bi, var_args[pi]);
327330
bi += l;
328-
} else if (str[si] == 'c') {
331+
} else if (format[si] == 'c') {
329332
/* append param pi as char */
330333
buffer[bi] = var_args[pi];
331334
bi += 1;
332-
} else if (str[si] == 'o') {
335+
} else if (format[si] == 'o') {
333336
/* append param as octal */
334337
int v = var_args[pi];
335338
bi += __format(buffer + bi, v, w, zp, 8, pp);
336-
} else if (str[si] == 'd') {
339+
} else if (format[si] == 'd') {
337340
/* append param as decimal */
338341
int v = var_args[pi];
339342
bi += __format(buffer + bi, v, w, zp, 10, 0);
340-
} else if (str[si] == 'x') {
343+
} else if (format[si] == 'x') {
341344
/* append param as hex */
342345
int v = var_args[pi];
343346
bi += __format(buffer + bi, v, w, zp, 16, pp);
344-
} else if (str[si] == '%') {
347+
} else if (format[si] == '%') {
345348
/* append literal '%' character */
346349
buffer[bi] = '%';
347350
bi++;
@@ -352,71 +355,28 @@ void printf(char *str, ...)
352355
si++;
353356
}
354357
}
355-
buffer[bi] = 0;
356-
__syscall(__syscall_write, 1, buffer, bi);
358+
359+
int len = size - 1 > bi ? bi : size - 1;
360+
buffer[len] = 0;
361+
return len;
357362
}
358363

359-
void sprintf(char *buffer, char *str, ...)
364+
int printf(char *str, ...)
360365
{
361-
int *var_args = &str + 4;
362-
int si = 0, bi = 0, pi = 0;
366+
char buffer[200];
367+
int len = __format_to_buf(buffer, str, &str + 4, 0x7fffffff);
368+
__syscall(__syscall_write, 1, buffer, len);
369+
return len;
370+
}
363371

364-
while (str[si]) {
365-
if (str[si] != '%') {
366-
buffer[bi] = str[si];
367-
bi++;
368-
si++;
369-
} else {
370-
int w = 0, zp = 0, pp = 0;
372+
int sprintf(char *buffer, char *str, ...)
373+
{
374+
return __format_to_buf(buffer, str, &str + 4, 0x7fffffff);
375+
}
371376

372-
si++;
373-
if (str[si] == '#') {
374-
pp = 1;
375-
si++;
376-
}
377-
if (str[si] == '0') {
378-
zp = 1;
379-
si++;
380-
}
381-
if (str[si] >= '1' && str[si] <= '9') {
382-
w = str[si] - '0';
383-
si++;
384-
if (str[si] >= '0' && str[si] <= '9') {
385-
w *= 10;
386-
w += str[si] - '0';
387-
si++;
388-
}
389-
}
390-
switch (str[si]) {
391-
case 37: /* % */
392-
buffer[bi++] = '%';
393-
si++;
394-
continue;
395-
case 99: /* c */
396-
buffer[bi++] = var_args[pi];
397-
break;
398-
case 115: /* s */
399-
strcpy(buffer + bi, var_args[pi]);
400-
bi += strlen(var_args[pi]);
401-
break;
402-
case 111: /* o */
403-
bi += __format(buffer + bi, var_args[pi], w, zp, 8, pp);
404-
break;
405-
case 100: /* d */
406-
bi += __format(buffer + bi, var_args[pi], w, zp, 10, 0);
407-
break;
408-
case 120: /* x */
409-
bi += __format(buffer + bi, var_args[pi], w, zp, 16, pp);
410-
break;
411-
default:
412-
abort();
413-
break;
414-
}
415-
pi++;
416-
si++;
417-
}
418-
}
419-
buffer[bi] = 0;
377+
int snprintf(char *buffer, int n, char *str, ...)
378+
{
379+
return __format_to_buf(buffer, str, &str + 4, n);
420380
}
421381

422382
int __free_all();

src/defs.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@
1717
#define MAX_VAR_LEN 32
1818
#define MAX_TYPE_LEN 32
1919
#define MAX_PARAMS 8
20-
#define MAX_LOCALS 1500
20+
#define MAX_LOCALS 1600
2121
#define MAX_FIELDS 64
2222
#define MAX_FUNCS 512
2323
#define MAX_TYPES 64
24-
#define MAX_IR_INSTR 50000
24+
#define MAX_IR_INSTR 60000
2525
#define MAX_BB_PRED 128
2626
#define MAX_BB_DOM_SUCC 64
2727
#define MAX_BB_RDOM_SUCC 256
2828
#define MAX_GLOBAL_IR 256
2929
#define MAX_LABEL 4096
30-
#define MAX_SOURCE 327680
30+
#define MAX_SOURCE 524288
3131
#define MAX_CODE 262144
3232
#define MAX_DATA 262144
3333
#define MAX_SYMTAB 65536
@@ -39,7 +39,7 @@
3939
#define MAX_CASES 128
4040
#define MAX_NESTING 128
4141
#define MAX_OPERAND_STACK_SIZE 32
42-
#define MAX_ANALYSIS_STACK_SIZE 750
42+
#define MAX_ANALYSIS_STACK_SIZE 800
4343

4444
/* Default capacities for common data structures */
4545
/* Default arena size is initialized with 256 KiB */

src/parser.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3401,17 +3401,15 @@ void load_source_file(char *file)
34013401
}
34023402
if (!strncmp(buffer, "#include ", 9) && (buffer[9] == '"')) {
34033403
char path[MAX_LINE_LEN];
3404-
int c = strlen(file) - 1;
3404+
int c = strlen(file) - 1, inclusion_path_len = strlen(buffer) - 11;
34053405
while (c > 0 && file[c] != '/')
34063406
c--;
34073407
if (c) {
34083408
/* prepend directory name */
3409-
strncpy(path, file, c + 1);
3410-
c++;
3409+
snprintf(path, c + 2, "%s", file);
34113410
}
3412-
path[c] = 0;
3413-
buffer[strlen(buffer) - 2] = 0;
3414-
strcpy(path + c, buffer + 10);
3411+
3412+
snprintf(path + c + 1, inclusion_path_len, "%s", buffer + 10);
34153413
load_source_file(path);
34163414
} else {
34173415
strcpy(SOURCE + source_idx, buffer);

tests/driver.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,4 +1611,57 @@ int main()
16111611
}
16121612
EOF
16131613

1614+
# printf family, including truncation and zero size input
1615+
try_output 11 "Hello World" << EOF
1616+
int main() {
1617+
int written = printf("Hello World");
1618+
return written;
1619+
}
1620+
EOF
1621+
1622+
try_output 11 "Hello World" << EOF
1623+
int main() {
1624+
char buffer[50];
1625+
int written = sprintf(buffer, "Hello World");
1626+
printf("%s", buffer);
1627+
return written;
1628+
}
1629+
EOF
1630+
1631+
try_output 16 "Hello World 1123" << EOF
1632+
int main() {
1633+
char buffer[50];
1634+
int written = sprintf(buffer, "Hello %s %d", "World", 1123);
1635+
printf("%s", buffer);
1636+
return written;
1637+
}
1638+
EOF
1639+
1640+
try_output 16 "Hello World 1123" << EOF
1641+
int main() {
1642+
char buffer[50];
1643+
int written = snprintf(buffer, 50, "Hello %s %d", "World", 1123);
1644+
printf("%s", buffer);
1645+
return written;
1646+
}
1647+
EOF
1648+
1649+
try_output 0 "" << EOF
1650+
int main() {
1651+
char buffer[20];
1652+
int written = snprintf(buffer, 0, "Number: %d", -37);
1653+
printf("%s", buffer);
1654+
return written;
1655+
}
1656+
EOF
1657+
1658+
try_output 9 "Number: -" << EOF
1659+
int main() {
1660+
char buffer[10];
1661+
int written = snprintf(buffer, 10, "Number: %d", -37);
1662+
printf("%s", buffer);
1663+
return written;
1664+
}
1665+
EOF
1666+
16141667
echo OK

tests/snapshots/fib-arm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/fib-riscv.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello-arm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello-riscv.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)