Skip to content

Commit 21dc60f

Browse files
Jim HsuChAoSUnItY
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 <[email protected]>
1 parent a603970 commit 21dc60f

File tree

8 files changed

+111
-92
lines changed

8 files changed

+111
-92
lines changed

lib/c.c

Lines changed: 37 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,27 @@ 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+
return __syscall(__syscall_write, 1, buffer, len);
369+
}
363370

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;
371+
int sprintf(char *buffer, char *str, ...)
372+
{
373+
return __format_to_buf(buffer, str, &str + 4, 0x7fffffff);
374+
}
371375

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;
376+
int snprintf(char *buffer, int n, char *str, ...)
377+
{
378+
return __format_to_buf(buffer, str, &str + 4, n);
420379
}
421380

422381
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: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,4 +1611,66 @@ 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 247 "" << EOF
1623+
int main()
1624+
{
1625+
__syscall(__syscall_close, 1);
1626+
int written = printf("Hello\n");
1627+
return written;
1628+
}
1629+
EOF
1630+
1631+
try_output 11 "Hello World" << EOF
1632+
int main() {
1633+
char buffer[50];
1634+
int written = sprintf(buffer, "Hello World");
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 = sprintf(buffer, "Hello %s %d", "World", 1123);
1644+
printf("%s", buffer);
1645+
return written;
1646+
}
1647+
EOF
1648+
1649+
try_output 16 "Hello World 1123" << EOF
1650+
int main() {
1651+
char buffer[50];
1652+
int written = snprintf(buffer, 50, "Hello %s %d", "World", 1123);
1653+
printf("%s", buffer);
1654+
return written;
1655+
}
1656+
EOF
1657+
1658+
try_output 0 "" << EOF
1659+
int main() {
1660+
char buffer[20];
1661+
int written = snprintf(buffer, 0, "Number: %d", -37);
1662+
printf("%s", buffer);
1663+
return written;
1664+
}
1665+
EOF
1666+
1667+
try_output 9 "Number: -" << EOF
1668+
int main() {
1669+
char buffer[10];
1670+
int written = snprintf(buffer, 10, "Number: %d", -37);
1671+
printf("%s", buffer);
1672+
return written;
1673+
}
1674+
EOF
1675+
16141676
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)