Skip to content

Commit b310322

Browse files
committed
Ensure the correctness when using formatted output conversion
The implementation of __format() produces incorrect results when using field width and flag characters. For example, consider the following printf calls, where the prepended characters are placed in incorrect positions. printf("%#12x\n", 0xff00cde1) --> "0x ff00cde1\n" printf("%#12o\n", 0x1000c) --> "0 200014\n" printf("%12d\n", -3580) --> "0000000-3580\n" Thus, this commit improves __format() to ensure correctness and to make the results consistent with GCC, and adds a test case to validate the changes.
1 parent a5e901b commit b310322

File tree

4 files changed

+168
-72
lines changed

4 files changed

+168
-72
lines changed

lib/c.c

+45-70
Original file line numberDiff line numberDiff line change
@@ -214,37 +214,13 @@ int __format(char *buffer,
214214
{
215215
int bi = 0;
216216
char pb[INT_BUF_LEN];
217-
int pbi = 0;
218-
219-
if (alternate_form == 1) {
220-
switch (base) {
221-
case 8:
222-
/* octal */
223-
buffer[0] = '0';
224-
bi = 1;
225-
width -= 1;
226-
break;
227-
case 16:
228-
/* hex */
229-
buffer[0] = '0';
230-
buffer[1] = 'x';
231-
bi = 2;
232-
width -= 2;
233-
break;
234-
default:
235-
/* decimal */
236-
/* do nothing */
237-
break;
238-
}
239-
if (width < 0)
240-
width = 0;
241-
}
217+
int pbi;
242218

243219
/* set to zeroes */
244-
while (pbi < INT_BUF_LEN) {
220+
for (pbi = 0; pbi < INT_BUF_LEN; pbi++)
245221
pb[pbi] = '0';
246-
pbi++;
247-
}
222+
223+
pbi = 0;
248224

249225
switch (base) {
250226
case 8:
@@ -261,53 +237,52 @@ int __format(char *buffer,
261237
break;
262238
}
263239

264-
while (width > INT_BUF_LEN) {
265-
/* need to add extra padding */
266-
if (zeropad == 1)
267-
buffer[bi] = '0';
268-
else
269-
buffer[bi] = ' ';
270-
bi++;
271-
width--;
272-
}
240+
while (pb[pbi] == '0' && pbi < INT_BUF_LEN - 1)
241+
pbi++;
273242

274-
/* no padding */
275-
if (width == 0) {
276-
int c = 0;
277-
int started = 0;
278-
279-
/* output from first digit */
280-
while (c < INT_BUF_LEN) {
281-
if (pb[c] != '0')
282-
started = 1;
283-
if (started) {
284-
buffer[bi] = pb[c];
285-
bi++;
286-
}
287-
c++;
243+
switch (base) {
244+
case 8:
245+
if (alternate_form) {
246+
if (width && zeropad && pb[pbi] != '0') {
247+
buffer[bi++] = '0';
248+
width -= 1;
249+
} else if (pb[pbi] != '0')
250+
pb[--pbi] = '0';
288251
}
289-
/* special case - zero */
290-
if (started == 0) {
291-
buffer[bi] = '0';
292-
bi++;
252+
break;
253+
case 10:
254+
if (width && zeropad && pb[pbi] == '-') {
255+
buffer[bi++] = '-';
256+
pbi++;
257+
width--;
293258
}
294-
} else {
295-
/* padding */
296-
int c = INT_BUF_LEN - width;
297-
int started = 0;
298-
while (c < INT_BUF_LEN) {
299-
if (pb[c] != '0')
300-
started = 1;
301-
if (started)
302-
buffer[bi] = pb[c];
303-
else if (zeropad == 1)
304-
buffer[bi] = '0';
305-
else
306-
buffer[bi] = ' ';
307-
bi++;
308-
c++;
259+
break;
260+
case 16:
261+
if (alternate_form) {
262+
if (width && zeropad && pb[pbi] != '0') {
263+
buffer[bi++] = '0';
264+
buffer[bi++] = 'x';
265+
width -= 2;
266+
} else if (pb[pbi] != '0') {
267+
pb[--pbi] = 'x';
268+
pb[--pbi] = '0';
269+
}
309270
}
271+
break;
310272
}
273+
274+
width -= (INT_BUF_LEN - pbi);
275+
if (width < 0)
276+
width = 0;
277+
278+
while (width) {
279+
buffer[bi++] = zeropad ? '0' : ' ';
280+
width--;
281+
}
282+
283+
for (; pbi < INT_BUF_LEN; pbi++)
284+
buffer[bi++] = pb[pbi];
285+
311286
return bi;
312287
}
313288

tests/driver.sh

+121
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,127 @@ int main() {
630630
}
631631
EOF
632632

633+
fmt_ans="0x0000000000000000000000ff00cde1
634+
0xff00cde1
635+
000000000000000000000000ff00cde1
636+
ff00cde1
637+
0xff00cde1
638+
ff00cde1
639+
0x00ff00cde1
640+
0xff00cde1
641+
0000ff00cde1
642+
ff00cde1
643+
00000000000000000000037700146741
644+
037700146741
645+
00000000000000000000037700146741
646+
37700146741
647+
037700146741
648+
37700146741
649+
037700146741
650+
037700146741
651+
037700146741
652+
37700146741
653+
-0000000000000000000000016724511
654+
-16724511
655+
-16724511
656+
-00016724511
657+
-16724511
658+
0x0000000000000000000000fffff204
659+
0xfffff204
660+
000000000000000000000000fffff204
661+
fffff204
662+
0xfffff204
663+
fffff204
664+
0x00fffff204
665+
0xfffff204
666+
0000fffff204
667+
fffff204
668+
00000000000000000000037777771004
669+
037777771004
670+
00000000000000000000037777771004
671+
37777771004
672+
037777771004
673+
37777771004
674+
037777771004
675+
037777771004
676+
037777771004
677+
37777771004
678+
-0000000000000000000000000003580
679+
-3580
680+
-3580
681+
-00000003580
682+
-3580
683+
0x00000000000000000000000001000c
684+
0x1000c
685+
0000000000000000000000000001000c
686+
1000c
687+
0x1000c
688+
1000c
689+
0x000001000c
690+
0x1000c
691+
00000001000c
692+
1000c
693+
00000000000000000000000000200014
694+
0200014
695+
00000000000000000000000000200014
696+
200014
697+
0200014
698+
200014
699+
000000200014
700+
0200014
701+
000000200014
702+
200014
703+
00000000000000000000000000065548
704+
65548
705+
65548
706+
000000065548
707+
65548
708+
00000000000000000000000000000000
709+
0
710+
00000000000000000000000000000000
711+
0
712+
0
713+
0
714+
000000000000
715+
0
716+
000000000000
717+
0
718+
00000000000000000000000000000000
719+
0
720+
00000000000000000000000000000000
721+
0
722+
0
723+
0
724+
000000000000
725+
0
726+
000000000000
727+
0
728+
00000000000000000000000000000000
729+
0
730+
0
731+
000000000000
732+
0"
733+
734+
try_output 0 "$fmt_ans" << EOF
735+
void printf_conversion(int num) {
736+
printf("%#032x\n%#32x\n%032x\n%32x\n%#x\n%x\n", num, num, num, num, num, num);
737+
printf("%#012x\n%#12x\n%012x\n%12x\n", num, num, num, num);
738+
printf("%#032o\n%#32o\n%032o\n%32o\n%#o\n%o\n", num, num, num, num, num, num);
739+
printf("%#012o\n%#12o\n%012o\n%12o\n", num, num, num, num);
740+
printf("%032d\n%32d\n%d\n", num, num, num);
741+
printf("%012d\n%12d\n", num, num);
742+
}
743+
744+
int main() {
745+
int a = 0xFF00CDE1, b = 0xFFFFF204, c = 65548, d = 0;
746+
printf_conversion(a);
747+
printf_conversion(b);
748+
printf_conversion(c);
749+
printf_conversion(d);
750+
return 0;
751+
}
752+
EOF
753+
633754
try_ 0 << EOF
634755
int main() {
635756
return '\0';

tests/snapshots/fib.json

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

tests/snapshots/hello.json

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

0 commit comments

Comments
 (0)