1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

strconv.atoi: fix string.int() returning numbers for non number characters (fix #18875) (#18925)

This commit is contained in:
penguindark 2023-07-22 05:43:10 +02:00 committed by GitHub
parent 7b306e9b8f
commit ba1c5def77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 8 deletions

View File

@ -89,6 +89,7 @@ pub fn common_parse_uint2(s string, _base int, _bit_size int) (u64, int) {
// Use compile-time constants for common cases.
cutoff := strconv.max_u64 / u64(base) + u64(1)
max_val := if bit_size == 64 { strconv.max_u64 } else { (u64(1) << u64(bit_size)) - u64(1) }
basem1 := base - 1
mut n := u64(0)
for i in start_index .. s.len {
@ -96,7 +97,6 @@ pub fn common_parse_uint2(s string, _base int, _bit_size int) (u64, int) {
// manage underscore inside the number
if c == `_` {
// println("Here: ${s#[i..]}")
if i == start_index || i >= (s.len - 1) {
// println("_ limit")
return u64(0), 1
@ -109,21 +109,25 @@ pub fn common_parse_uint2(s string, _base int, _bit_size int) (u64, int) {
continue
}
mut sub_count := 0
// get the 0-9 digit
c -= 48 // subtract the rune `0`
// check if we are in the superior base rune interval [A..Z]
if c >= base {
c -= 7
}
if c >= 17 { // (65 - 48)
sub_count++
c -= 7 // subtract the `A` - `0` rune to obtain the value of the digit
// check if we are in the superior base rune interval [a..z]
if c >= base {
c -= 32 // subtract the `A` - `0` rune to obtain the value of the digit
// check if we are in the superior base rune interval [a..z]
if c >= 42 { // (97 - 7 - 48)
sub_count++
c -= 32 // subtract the `a` - `0` rune to obtain the value of the digit
}
}
// check for digit over base
if c >= base {
if c > basem1 || (sub_count == 0 && c > 9) {
return n, i + 1
}

View File

@ -27,6 +27,9 @@ fn test_atoi() {
}
fn test_parse_int() {
// symbols coverage
assert strconv.parse_int('1234567890', 10, 32)! == 1234567890
assert strconv.parse_int('19aAbBcCdDeEfF', 16, 64)! == 0x19aAbBcCdDeEfF
// Different bases
assert strconv.parse_int('16', 16, 0)! == 0x16
assert strconv.parse_int('16', 8, 0)! == 0o16
@ -83,6 +86,32 @@ fn test_common_parse_uint2() {
assert error == 4
}
fn test_common_parse_uint2_fail() {
mut ascii_characters := [' ', '!', '"', '#', '\$', '%', '&', "'", '(', ')', '*', '+', ',',
'-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|',
'}', '~']
mut special_characters := [':', ';', '<', '=', '>', '?', '@', 'X', 'Y', 'Z', '[', '\\', ']',
'^', '_', '`']
num0, err0 := strconv.common_parse_uint2('1Ab', 16, 32)
assert num0 == 427
assert err0 == 0
for ch in ascii_characters {
// println("ch: [${ch}]")
txt_str := '${ch[0]:c}12Ab'
num, err := strconv.common_parse_uint2(txt_str, 16, 32)
assert err != 0
}
for ch in special_characters {
// println("ch: [${ch}]")
txt_str := '${ch[0]:c}12Ab'
num, err := strconv.common_parse_uint2(txt_str, 16, 32)
assert err != 0
}
}
fn test_common_parse_uint2_compatibility() {
test_list := [
'1234,1234',