Skip to content

Commit

Permalink
Fix edge cases in snprintf
Browse files Browse the repository at this point in the history
  • Loading branch information
Sympatron committed Oct 25, 2024
1 parent dd6f569 commit d7349e4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 7 deletions.
15 changes: 8 additions & 7 deletions src/snprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ int vsnprintf(
{
char s[MAXIMUM_NUMBER_LENGTH] = { 0 };
signed long long ll = 0;
unsigned long long ull = 0;
if ( is_long == 2 )
{
// Render %lld
Expand All @@ -226,11 +227,8 @@ int vsnprintf(
ll = va_arg( ap, signed int );
}
bool is_negative = ll < 0;
if (is_negative)
{
ll = -ll;
}
itoa( ll, s, sizeof(s), 10 );
ull = is_negative ? -ll : ll;
utoa( ull, s, sizeof(s), 10 );
write_padding( str, size, &written, strlen(s), width, precision, zero_pad, is_negative );
for ( const char* p = s; *p != '\0'; p++ )
{
Expand Down Expand Up @@ -430,10 +428,13 @@ static void write_padding(char* restrict str, size_t size, size_t* written, size
unsigned long zero_pad_len = 0;
if ( precision != 0 && precision != (unsigned long)-1 )
{
zero_pad_len = precision > len ? precision - len : 0;
if ( is_negative )
{
zero_pad_len++;
zero_pad_len = precision >= len ? precision - len + 1 : 0;
}
else
{
zero_pad_len = precision >= len ? precision - len : 0;
}
}
else if ( zero_pad )
Expand Down
28 changes: 28 additions & 0 deletions src/snprintf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,34 @@ mod test {
);
}

#[test]
fn int_min() {
asprintf(
"%d",
&format!("{}", CInt::min_value()),
|buf, len, fmt| unsafe { snprintf(buf, len, fmt, CInt::min_value()) },
);
asprintf(
"%lld",
&format!("{}", CLongLong::min_value()),
|buf, len, fmt| unsafe { snprintf(buf, len, fmt, CLongLong::min_value()) },
);
}

#[test]
fn int_max() {
asprintf(
"%d",
&format!("{}", CInt::max_value()),
|buf, len, fmt| unsafe { snprintf(buf, len, fmt, CInt::max_value()) },
);
asprintf(
"%lld",
&format!("{}", CLongLong::max_value()),
|buf, len, fmt| unsafe { snprintf(buf, len, fmt, CLongLong::max_value()) },
);
}

#[test]
fn non_null_terminated_with_length() {
asprintf("%.*s", "01234", |buf, len, fmt: *const u8| unsafe {
Expand Down

0 comments on commit d7349e4

Please sign in to comment.