Skip to content

Commit d7868c7

Browse files
Jim HsuChAoSUnItY
Jim Hsu
authored andcommitted
feat: Add snprintf and refine printf family funcs
This patch adds snprintf and refines printf family funcs by changing function signature to return an integer to match their original definitions defined by specifications. The second parameter "size" for snprintf is expected to accept only zero or positive integer, otherwise as C11 specification states, it would be undefined behavior. Co-authored-by: Jim Hsu <jimhsu1101@gmail.com>
1 parent a603970 commit d7868c7

File tree

8 files changed

+127
-99
lines changed

8 files changed

+127
-99
lines changed

lib/c.c

+49-85
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#define true 1
1414
#define false 0
1515

16+
#define INT_MAX 0x7fffffff
17+
#define INT_MIN 0x80000000
18+
1619
#if defined(__arm__)
1720
#define __SIZEOF_POINTER__ 4
1821
#define __syscall_exit 1
@@ -288,60 +291,65 @@ int __format(char *buffer,
288291
return bi;
289292
}
290293

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

297-
while (str[si]) {
298-
if (str[si] != '%') {
299-
buffer[bi] = str[si];
298+
if (size == 0)
299+
return 0;
300+
301+
while (format[si] && bi < size - 1) {
302+
if (format[si] != '%') {
303+
buffer[bi] = format[si];
300304
bi++;
301305
si++;
302306
} else {
303-
int w = 0, zp = 0, pp = 0;
307+
int w = 0, zp = 0, pp = 0, v = var_args[pi], l;
304308

305309
si++;
306-
if (str[si] == '#') {
310+
if (format[si] == '#') {
307311
pp = 1;
308312
si++;
309313
}
310-
if (str[si] == '0') {
314+
if (format[si] == '0') {
311315
zp = 1;
312316
si++;
313317
}
314-
if (str[si] >= '1' && str[si] <= '9') {
315-
w = str[si] - '0';
318+
if (format[si] >= '1' && format[si] <= '9') {
319+
w = format[si] - '0';
316320
si++;
317-
while (str[si] >= '0' && str[si] <= '9') {
321+
while (format[si] >= '0' && format[si] <= '9') {
318322
w *= 10;
319-
w += str[si] - '0';
323+
w += format[si] - '0';
320324
si++;
321325
}
322326
}
323-
if (str[si] == 's') {
327+
switch (format[si]) {
328+
case 's':
324329
/* append param pi as string */
325-
int l = strlen(var_args[pi]);
326-
strcpy(buffer + bi, var_args[pi]);
330+
l = strlen(v);
331+
l = l < size - bi ? l : size - bi;
332+
strncpy(buffer + bi, v, l);
327333
bi += l;
328-
} else if (str[si] == 'c') {
334+
break;
335+
case 'c':
329336
/* append param pi as char */
330-
buffer[bi] = var_args[pi];
337+
buffer[bi] = v;
331338
bi += 1;
332-
} else if (str[si] == 'o') {
339+
break;
340+
case 'o':
333341
/* append param as octal */
334-
int v = var_args[pi];
335342
bi += __format(buffer + bi, v, w, zp, 8, pp);
336-
} else if (str[si] == 'd') {
343+
break;
344+
case 'd':
337345
/* append param as decimal */
338-
int v = var_args[pi];
339346
bi += __format(buffer + bi, v, w, zp, 10, 0);
340-
} else if (str[si] == 'x') {
347+
break;
348+
case 'x':
341349
/* append param as hex */
342-
int v = var_args[pi];
343350
bi += __format(buffer + bi, v, w, zp, 16, pp);
344-
} else if (str[si] == '%') {
351+
break;
352+
case '%':
345353
/* append literal '%' character */
346354
buffer[bi] = '%';
347355
bi++;
@@ -352,71 +360,27 @@ void printf(char *str, ...)
352360
si++;
353361
}
354362
}
355-
buffer[bi] = 0;
356-
__syscall(__syscall_write, 1, buffer, bi);
363+
364+
int len = size - 1 > bi ? bi : size - 1;
365+
buffer[len] = 0;
366+
return len;
357367
}
358368

359-
void sprintf(char *buffer, char *str, ...)
369+
int printf(char *str, ...)
360370
{
361-
int *var_args = &str + 4;
362-
int si = 0, bi = 0, pi = 0;
371+
char buffer[200];
372+
int len = __format_to_buf(buffer, str, &str + 4, INT_MAX);
373+
return __syscall(__syscall_write, 1, buffer, len);
374+
}
363375

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;
376+
int sprintf(char *buffer, char *str, ...)
377+
{
378+
return __format_to_buf(buffer, str, &str + 4, INT_MAX);
379+
}
371380

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;
381+
int snprintf(char *buffer, int n, char *str, ...)
382+
{
383+
return __format_to_buf(buffer, str, &str + 4, n);
420384
}
421385

422386
int __free_all();

src/defs.h

+4-4
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

+7-6
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,9 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
26212621
if (lex_peek(T_numeric, NULL)) {
26222622
case_val = read_numeric_constant(token_str);
26232623
lex_expect(T_numeric); /* already read it */
2624+
} else if (lex_peek(T_char, token)) {
2625+
case_val = token[0];
2626+
lex_expect(T_char);
26242627
} else {
26252628
constant_t *cd = find_constant(token_str);
26262629
case_val = cd->value;
@@ -3401,17 +3404,15 @@ void load_source_file(char *file)
34013404
}
34023405
if (!strncmp(buffer, "#include ", 9) && (buffer[9] == '"')) {
34033406
char path[MAX_LINE_LEN];
3404-
int c = strlen(file) - 1;
3407+
int c = strlen(file) - 1, inclusion_path_len = strlen(buffer) - 11;
34053408
while (c > 0 && file[c] != '/')
34063409
c--;
34073410
if (c) {
34083411
/* prepend directory name */
3409-
strncpy(path, file, c + 1);
3410-
c++;
3412+
snprintf(path, c + 2, "%s", file);
34113413
}
3412-
path[c] = 0;
3413-
buffer[strlen(buffer) - 2] = 0;
3414-
strcpy(path + c, buffer + 10);
3414+
3415+
snprintf(path + c + 1, inclusion_path_len, "%s", buffer + 10);
34153416
load_source_file(path);
34163417
} else {
34173418
strcpy(SOURCE + source_idx, buffer);

tests/driver.sh

+63
Original file line numberDiff line numberDiff line change
@@ -1611,4 +1611,67 @@ 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+
# tests printf returns EBADF (errno 9) when stdout is closed
1623+
try_output 1 "" << EOF
1624+
int main()
1625+
{
1626+
__syscall(__syscall_close, 1);
1627+
int written = printf("Hello\n");
1628+
return written == -9;
1629+
}
1630+
EOF
1631+
1632+
try_output 11 "Hello World" << EOF
1633+
int main() {
1634+
char buffer[50];
1635+
int written = sprintf(buffer, "Hello World");
1636+
printf("%s", buffer);
1637+
return written;
1638+
}
1639+
EOF
1640+
1641+
try_output 16 "Hello World 1123" << EOF
1642+
int main() {
1643+
char buffer[50];
1644+
int written = sprintf(buffer, "Hello %s %d", "World", 1123);
1645+
printf("%s", buffer);
1646+
return written;
1647+
}
1648+
EOF
1649+
1650+
try_output 16 "Hello World 1123" << EOF
1651+
int main() {
1652+
char buffer[50];
1653+
int written = snprintf(buffer, 50, "Hello %s %d", "World", 1123);
1654+
printf("%s", buffer);
1655+
return written;
1656+
}
1657+
EOF
1658+
1659+
try_output 0 "" << EOF
1660+
int main() {
1661+
char buffer[20];
1662+
int written = snprintf(buffer, 0, "Number: %d", -37);
1663+
printf("%s", buffer);
1664+
return written;
1665+
}
1666+
EOF
1667+
1668+
try_output 9 "Number: -" << EOF
1669+
int main() {
1670+
char buffer[10];
1671+
int written = snprintf(buffer, 10, "Number: %d", -37);
1672+
printf("%s", buffer);
1673+
return written;
1674+
}
1675+
EOF
1676+
16141677
echo OK

tests/snapshots/fib-arm.json

+1-1
Large diffs are not rendered by default.

tests/snapshots/fib-riscv.json

+1-1
Large diffs are not rendered by default.

tests/snapshots/hello-arm.json

+1-1
Large diffs are not rendered by default.

tests/snapshots/hello-riscv.json

+1-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)