Skip to content

Commit 284a9d3

Browse files
committed
Fix edge cases in snprintf
1 parent dd6f569 commit 284a9d3

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

src/snprintf.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ int vsnprintf(
210210
{
211211
char s[MAXIMUM_NUMBER_LENGTH] = { 0 };
212212
signed long long ll = 0;
213+
unsigned long long ull = 0;
213214
if ( is_long == 2 )
214215
{
215216
// Render %lld
@@ -226,11 +227,8 @@ int vsnprintf(
226227
ll = va_arg( ap, signed int );
227228
}
228229
bool is_negative = ll < 0;
229-
if (is_negative)
230-
{
231-
ll = -ll;
232-
}
233-
itoa( ll, s, sizeof(s), 10 );
230+
ull = is_negative ? -ll : ll;
231+
utoa( ull, s, sizeof(s), 10 );
234232
write_padding( str, size, &written, strlen(s), width, precision, zero_pad, is_negative );
235233
for ( const char* p = s; *p != '\0'; p++ )
236234
{
@@ -430,13 +428,16 @@ static void write_padding(char* restrict str, size_t size, size_t* written, size
430428
unsigned long zero_pad_len = 0;
431429
if ( precision != 0 && precision != (unsigned long)-1 )
432430
{
433-
zero_pad_len = precision > len ? precision - len : 0;
434431
if ( is_negative )
435432
{
436-
zero_pad_len++;
433+
zero_pad_len = precision >= len ? precision - len + 1 : 0;
434+
}
435+
else
436+
{
437+
zero_pad_len = precision >= len ? precision - len : 0;
437438
}
438439
}
439-
else if ( zero_pad )
440+
else if ( zero_pad && precision == (unsigned long)-1 )
440441
{
441442
zero_pad_len = pad_len;
442443
}

src/snprintf.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,34 @@ mod test {
9494
);
9595
}
9696

97+
#[test]
98+
fn int_min() {
99+
asprintf(
100+
"%d",
101+
&format!("{}", CInt::min_value()),
102+
|buf, len, fmt| unsafe { snprintf(buf, len, fmt, CInt::min_value()) },
103+
);
104+
asprintf(
105+
"%lld",
106+
&format!("{}", CLongLong::min_value()),
107+
|buf, len, fmt| unsafe { snprintf(buf, len, fmt, CLongLong::min_value()) },
108+
);
109+
}
110+
111+
#[test]
112+
fn int_max() {
113+
asprintf(
114+
"%d",
115+
&format!("{}", CInt::max_value()),
116+
|buf, len, fmt| unsafe { snprintf(buf, len, fmt, CInt::max_value()) },
117+
);
118+
asprintf(
119+
"%lld",
120+
&format!("{}", CLongLong::max_value()),
121+
|buf, len, fmt| unsafe { snprintf(buf, len, fmt, CLongLong::max_value()) },
122+
);
123+
}
124+
97125
#[test]
98126
fn non_null_terminated_with_length() {
99127
asprintf("%.*s", "01234", |buf, len, fmt: *const u8| unsafe {
@@ -246,5 +274,15 @@ mod test {
246274
asprintf("%5.0d", " -123", |buf, len, fmt| unsafe {
247275
snprintf(buf, len, fmt, CInt::from(-123i8))
248276
});
277+
278+
asprintf("%05.4d", "-0123", |buf, len, fmt| unsafe {
279+
snprintf(buf, len, fmt, CInt::from(-123i8))
280+
});
281+
asprintf("%05.3d", " -123", |buf, len, fmt| unsafe {
282+
snprintf(buf, len, fmt, CInt::from(-123i8))
283+
});
284+
asprintf("%05.0d", " -123", |buf, len, fmt| unsafe {
285+
snprintf(buf, len, fmt, CInt::from(-123i8))
286+
});
249287
}
250288
}

0 commit comments

Comments
 (0)