Skip to content

Commit

Permalink
Fixed a bug in snprintf
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrea Palmatè committed Aug 1, 2022
1 parent da140d9 commit 8f72dbd
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 55 deletions.
58 changes: 21 additions & 37 deletions library/stdio/vfprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ static void pad(Out *f, char c, int w, int l, int fl);

static void out_init_file(Out *out, FILE *f) {
memset(out, 0, sizeof(*out));
out->buffer_size = f->size;
out->buffer_pos = f->position;
out->file = f;
}

Expand All @@ -33,6 +35,7 @@ static void out(Out *_out, const char *text, size_t l) {
}
if (_out->file != NULL) {
const char *w = text;
_out->buffer_pos += length;
while (length--) {
__putc_unlocked(*w++, _out->file);
}
Expand Down Expand Up @@ -396,8 +399,8 @@ static int getint(char **s) {
}

static int printf_core(Out *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type) {
char buf[(sizeof(uintmax_t) * 3 + 3 + (LDBL_MANT_DIG / 4))],
mb[4],
char buf[(sizeof(uintmax_t) * 3 + 3 + (LDBL_MANT_DIG / 4))] = {0},
mb[4] = {0},
*a, *z, *s = (char *) fmt;
const char *prefix;
wchar_t wc[2], *ws;
Expand All @@ -410,7 +413,7 @@ static int printf_core(Out *f, const char *fmt, va_list *ap, union arg *nl_arg,
/* Update output count, end loop when fmt is exhausted */
if (cnt >= 0) {
if (l > INT_MAX - cnt) {
errno = EOVERFLOW;
__set_errno(EOVERFLOW);
cnt = -1;
} else
cnt += l;
Expand Down Expand Up @@ -448,15 +451,14 @@ static int printf_core(Out *f, const char *fmt, va_list *ap, union arg *nl_arg,
w = (int) nl_arg[s[1] - '0'].i;
s += 3;
} else if (!l10n) {
w = f ? va_arg(*ap,
int) : 0;
w = f ? va_arg(*ap, int) : 0;
s++;
} else
return -1;
return EOF;
if (w < 0)
fl |= __S_LEFT_ADJ, w = -w;
} else if ((w = getint(&s)) < 0)
return -1;
return EOF;

/* Read precision */
if (*s == '.' && s[1] == '*') {
Expand All @@ -469,7 +471,7 @@ static int printf_core(Out *f, const char *fmt, va_list *ap, union arg *nl_arg,
int) : 0);
s += 2;
} else
return -1;
return EOF;
} else if (*s == '.') {
s++;
p = getint(&s);
Expand All @@ -480,13 +482,13 @@ static int printf_core(Out *f, const char *fmt, va_list *ap, union arg *nl_arg,
st = 0;
do {
if (__OOP(*s))
return -1;
return EOF;
ps = st;
st = states[st]
S(*s++);
} while ((st - 1) < _STOP);
if (!st)
return -1;
return EOF;

/* Check validity of argument type (nl/normal) */
if (st == _NOARG) {
Expand Down Expand Up @@ -593,33 +595,15 @@ static int printf_core(Out *f, const char *fmt, va_list *ap, union arg *nl_arg,
break;
case 'm':
if (1)
a = strerror(errno);
else
case 's':
a = arg.p ? arg.p : (char *) "(null)";
#if 1
/* On Android, memchr() will return NULL for
* out-of-bound requests, e.g. if |p == -1|. */
if (p >= 0) {
z = memchr(a, 0, (size_t) p);
if (!z)
z = a + p;
else
p = (int) (z - a);
} else {
if (a) {
p = (int) strlen(a);
}
else
p = 0;
z = a + p;
a = strerror(errno); else
case 's':
a = arg.p ? arg.p : (char *) "(null)";
z = a + strnlen(a, p<0 ? INT_MAX : p);
if (p<0 && *z) {
__set_errno(EOVERFLOW);
return EOF;
}
#else
if (!z)
z = a + p;
else
p = z - a;
#endif
p = z-a;
fl &= ~__U_ZERO_PAD;
break;
case 'C':
Expand All @@ -638,7 +622,7 @@ static int printf_core(Out *f, const char *fmt, va_list *ap, union arg *nl_arg,
);
i += l);
if (l < 0)
return -1;
return EOF;
p = i;
pad(f, ' ', w, p, (int) fl);
ws = arg.p;
Expand Down
21 changes: 3 additions & 18 deletions library/stdio/vsnprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ int
vsnprintf(char *buffer, size_t size, const char *format, va_list arg) {
struct iob string_iob;
int result = EOF;
char local_buffer[32];
char local_buffer[32] = {0};

ENTER();

Expand All @@ -27,6 +27,7 @@ vsnprintf(char *buffer, size_t size, const char *format, va_list arg) {
__set_errno(EFAULT);
goto out;
}
memset(buffer, 0, size);

__initialize_iob(&string_iob, __vsnprintf_hook_entry,
NULL,
Expand All @@ -37,30 +38,14 @@ vsnprintf(char *buffer, size_t size, const char *format, va_list arg) {
NULL);

/* Store up to 'size-1' characters in the output buffer. This
does not include the terminating NUL character, which we
will add later. */
does not include the terminating NUL character */
string_iob.iob_String = (STRPTR) buffer;
string_iob.iob_StringSize = (size > 0) ? (size - 1) : 0;

/* We will return the number of characters that would have been
stored if there had been enough room. */
result = vfprintf((FILE * ) &string_iob, format, arg);

/* Figure out how many characters were stored. Fewer than
the output buffer size allows for may have been written
to the buffer. The string needs to be terminated with a
NUL byte behind the last character stored. */
if (size > 0) {
assert(string_iob.iob_StringPosition >= 0);
assert(string_iob.iob_StringPosition + 1 <= size);

buffer[string_iob.iob_StringPosition] = '\0';

SHOWSTRING(buffer);
} else {
SHOWMSG("output buffer is empty");
}

fflush((FILE * ) &string_iob);

out:
Expand Down
23 changes: 23 additions & 0 deletions test_programs/print/snprintf1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// C program to demonstrate snprintf()
#include <stdio.h>

int main() {
char buffer[50];
char *s = "geeksforgeeks";

// Counting the character and storing
// in buffer using snprintf
printf("Writing %s onto buffer"
" with capacity 6",
s);
int j = snprintf(buffer, 6, "%s\n", s);

// Print the string stored in buffer and
// character count
printf("\nString written on "
"buffer = '%s'", buffer);
printf("\nValue returned by "
"snprintf() method = %d\n", j);

return 0;
}
26 changes: 26 additions & 0 deletions test_programs/print/snprintf2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// C program to demonstrate snprintf()
#include <stdio.h>

int main() {
char buffer[50];

// join two or more strings
char *str1 = "quick";
char *str2 = "brown";
char *str3 = "lazy";
int max_len = sizeof buffer;

int j = snprintf(buffer, max_len,
"The %s %s fox jumped over the %s dog.",
str1, str2, str3);
printf("\nThe number of bytes printed to 'buffer' "
"(excluding the null terminator) is %d\n",
j);
if (j >= max_len)
fputs("Buffer length exceeded; string truncated",
stderr);
puts("Joined string:");
puts(buffer);

return 0;
}

0 comments on commit 8f72dbd

Please sign in to comment.