Skip to content

Commit a89fc48

Browse files
authored
Merge pull request #7656 from eduardorittner/main
printf: make negative values wrap around with unsigned/hex format
2 parents eca400f + 36ef501 commit a89fc48

File tree

2 files changed

+69
-13
lines changed

2 files changed

+69
-13
lines changed

src/uucore/src/lib/features/parser/num_parser.rs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -165,23 +165,24 @@ impl ExtendedParser for u64 {
165165
ExtendedBigDecimal::BigDecimal(bd) => {
166166
let (digits, scale) = bd.into_bigint_and_scale();
167167
if scale == 0 {
168-
let negative = digits.sign() == Sign::Minus;
168+
let (sign, digits) = digits.into_parts();
169+
169170
match u64::try_from(digits) {
170-
Ok(i) => Ok(i),
171-
_ => Err(ExtendedParserError::Overflow(if negative {
172-
// TODO: We should wrap around here #7488
173-
0
174-
} else {
175-
u64::MAX
176-
})),
171+
Ok(i) => {
172+
if sign == Sign::Minus {
173+
Ok(!i + 1)
174+
} else {
175+
Ok(i)
176+
}
177+
}
178+
_ => Err(ExtendedParserError::Overflow(u64::MAX)),
177179
}
178180
} else {
179181
// Should not happen.
180182
Err(ExtendedParserError::NotNumeric)
181183
}
182184
}
183-
// TODO: Handle -0 too #7488
184-
// No other case should not happen.
185+
ExtendedBigDecimal::MinusZero => Ok(0),
185186
_ => Err(ExtendedParserError::NotNumeric),
186187
}
187188
}
@@ -527,10 +528,28 @@ mod tests {
527528
fn test_decimal_u64() {
528529
assert_eq!(Ok(123), u64::extended_parse("123"));
529530
assert_eq!(Ok(u64::MAX), u64::extended_parse(&format!("{}", u64::MAX)));
530-
// TODO: We should wrap around here #7488
531+
assert_eq!(Ok(0), u64::extended_parse("-0"));
532+
assert_eq!(Ok(u64::MAX), u64::extended_parse("-1"));
533+
assert_eq!(
534+
Ok(u64::MAX / 2 + 1),
535+
u64::extended_parse("-9223372036854775808") // i64::MIN
536+
);
537+
assert_eq!(
538+
Ok(1123372036854675616),
539+
u64::extended_parse("-17323372036854876000") // 2*i64::MIN
540+
);
541+
assert_eq!(Ok(1), u64::extended_parse("-18446744073709551615")); // -u64::MAX
542+
assert!(matches!(
543+
u64::extended_parse("-18446744073709551616"), // -u64::MAX - 1
544+
Err(ExtendedParserError::Overflow(u64::MAX))
545+
));
546+
assert!(matches!(
547+
u64::extended_parse("-92233720368547758150"),
548+
Err(ExtendedParserError::Overflow(u64::MAX))
549+
));
531550
assert!(matches!(
532-
u64::extended_parse("-123"),
533-
Err(ExtendedParserError::Overflow(0))
551+
u64::extended_parse("-170141183460469231731687303715884105729"),
552+
Err(ExtendedParserError::Overflow(u64::MAX))
534553
));
535554
assert!(matches!(
536555
u64::extended_parse(""),

tests/by-util/test_printf.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
//
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
5+
6+
// spell-checker:ignore fffffffffffffffc
57
use uutests::new_ucmd;
68
use uutests::util::TestScenario;
79
use uutests::util_name;
@@ -791,6 +793,41 @@ fn partial_integer() {
791793
.stderr_is("printf: '42x23': value not completely converted\n");
792794
}
793795

796+
#[test]
797+
fn unsigned_hex_negative_wraparound() {
798+
new_ucmd!()
799+
.args(&["%x", "-0b100"])
800+
.succeeds()
801+
.stdout_only("fffffffffffffffc");
802+
803+
new_ucmd!()
804+
.args(&["%x", "-0100"])
805+
.succeeds()
806+
.stdout_only("ffffffffffffffc0");
807+
808+
new_ucmd!()
809+
.args(&["%x", "-100"])
810+
.succeeds()
811+
.stdout_only("ffffffffffffff9c");
812+
813+
new_ucmd!()
814+
.args(&["%x", "-0x100"])
815+
.succeeds()
816+
.stdout_only("ffffffffffffff00");
817+
818+
new_ucmd!()
819+
.args(&["%x", "-92233720368547758150"])
820+
.fails_with_code(1)
821+
.stdout_is("ffffffffffffffff")
822+
.stderr_is("printf: '-92233720368547758150': Numerical result out of range\n");
823+
824+
new_ucmd!()
825+
.args(&["%u", "-1002233720368547758150"])
826+
.fails_with_code(1)
827+
.stdout_is("18446744073709551615")
828+
.stderr_is("printf: '-1002233720368547758150': Numerical result out of range\n");
829+
}
830+
794831
#[test]
795832
fn test_overflow() {
796833
new_ucmd!()

0 commit comments

Comments
 (0)