strconv: fix a double free bug in v_sprintf/remove_tail_zeros_old, reduce leaks

pull/13724/head
Delyan Angelov 2022-03-11 18:54:28 +02:00
parent 795fe5844c
commit a3e9409196
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
3 changed files with 69 additions and 14 deletions

View File

@ -89,6 +89,7 @@ pub mut:
rm_tail_zero bool // remove the tail zeros from floats rm_tail_zero bool // remove the tail zeros from floats
} }
[manualfree]
pub fn format_str(s string, p BF_param) string { pub fn format_str(s string, p BF_param) string {
if p.len0 <= 0 { if p.len0 <= 0 {
return s.clone() return s.clone()

View File

@ -108,3 +108,8 @@ fn test_format() {
cnt++ cnt++
} }
} }
fn test_sprintf_does_not_double_free_on_g() {
x := 3.141516
assert strconv.v_sprintf('aaa %G', x) == 'aaa 3.141516'
}

View File

@ -26,6 +26,7 @@ pub fn v_printf(str string, pt ...voidptr) {
print(v_sprintf(str, ...pt)) print(v_sprintf(str, ...pt))
} }
[manualfree]
pub fn v_sprintf(str string, pt ...voidptr) string { pub fn v_sprintf(str string, pt ...voidptr) string {
mut res := strings.new_builder(pt.len * 16) mut res := strings.new_builder(pt.len * 16)
defer { defer {
@ -269,14 +270,16 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
d1 = if positive { u64(x) } else { u64(-x) } d1 = if positive { u64(x) } else { u64(-x) }
} }
} }
res.write_string(format_dec_old(d1, tmp := format_dec_old(d1,
pad_ch: pad_ch pad_ch: pad_ch
len0: len0 len0: len0
len1: 0 len1: 0
positive: positive positive: positive
sign_flag: sign sign_flag: sign
allign: allign allign: allign
)) )
res.write_string(tmp)
unsafe { tmp.free() }
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
@ -318,14 +321,16 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
} }
} }
res.write_string(format_dec_old(d1, tmp := format_dec_old(d1,
pad_ch: pad_ch pad_ch: pad_ch
len0: len0 len0: len0
len1: 0 len1: 0
positive: positive positive: positive
sign_flag: sign sign_flag: sign
allign: allign allign: allign
)) )
res.write_string(tmp)
unsafe { tmp.free() }
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
@ -370,17 +375,22 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
} }
if ch == `X` { if ch == `X` {
tmp := s
s = s.to_upper() s = s.to_upper()
unsafe { tmp.free() }
} }
res.write_string(format_str(s, tmp := format_str(s,
pad_ch: pad_ch pad_ch: pad_ch
len0: len0 len0: len0
len1: 0 len1: 0
positive: true positive: true
sign_flag: false sign_flag: false
allign: allign allign: allign
)) )
res.write_string(tmp)
unsafe { tmp.free() }
unsafe { s.free() }
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
@ -402,7 +412,14 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
sign_flag: sign sign_flag: sign
allign: allign allign: allign
) )
res.write_string(if ch == `F` { s.to_upper() } else { s }) if ch == `F` {
tmp := s.to_upper()
res.write_string(tmp)
unsafe { tmp.free() }
} else {
res.write_string(s)
}
unsafe { s.free() }
} }
status = .reset_params status = .reset_params
p_index++ p_index++
@ -422,7 +439,14 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
sign_flag: sign sign_flag: sign
allign: allign allign: allign
) )
res.write_string(if ch == `E` { s.to_upper() } else { s }) if ch == `E` {
tmp := s.to_upper()
res.write_string(tmp)
unsafe { tmp.free() }
} else {
res.write_string(s)
}
unsafe { s.free() }
} }
status = .reset_params status = .reset_params
p_index++ p_index++
@ -438,6 +462,7 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
if tx < 999_999.0 && tx >= 0.00001 { if tx < 999_999.0 && tx >= 0.00001 {
// println("Here g format_fl [$tx]") // println("Here g format_fl [$tx]")
len1 = if len1 >= 0 { len1 + 1 } else { def_len1 } len1 = if len1 >= 0 { len1 + 1 } else { def_len1 }
tmp := s
s = format_fl_old(x, s = format_fl_old(x,
pad_ch: pad_ch pad_ch: pad_ch
len0: len0 len0: len0
@ -447,8 +472,10 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
allign: allign allign: allign
rm_tail_zero: true rm_tail_zero: true
) )
unsafe { tmp.free() }
} else { } else {
len1 = if len1 >= 0 { len1 + 1 } else { def_len1 } len1 = if len1 >= 0 { len1 + 1 } else { def_len1 }
tmp := s
s = format_es_old(x, s = format_es_old(x,
pad_ch: pad_ch pad_ch: pad_ch
len0: len0 len0: len0
@ -458,8 +485,16 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
allign: allign allign: allign
rm_tail_zero: true rm_tail_zero: true
) )
unsafe { tmp.free() }
} }
res.write_string(if ch == `G` { s.to_upper() } else { s }) if ch == `G` {
tmp := s.to_upper()
res.write_string(tmp)
unsafe { tmp.free() }
} else {
res.write_string(s)
}
unsafe { s.free() }
} }
status = .reset_params status = .reset_params
p_index++ p_index++
@ -471,14 +506,16 @@ pub fn v_sprintf(str string, pt ...voidptr) string {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
s1 := unsafe { *(&string(pt[p_index])) } s1 := unsafe { *(&string(pt[p_index])) }
pad_ch = ` ` pad_ch = ` `
res.write_string(format_str(s1, tmp := format_str(s1,
pad_ch: pad_ch pad_ch: pad_ch
len0: len0 len0: len0
len1: 0 len1: 0
positive: true positive: true
sign_flag: false sign_flag: false
allign: allign allign: allign
)) )
res.write_string(tmp)
unsafe { tmp.free() }
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
@ -596,11 +633,15 @@ pub fn format_es_old(f f64, p BF_param) string {
mut s := '' mut s := ''
mut fs := f64_to_str_pad(if f > 0 { f } else { -f }, p.len1) mut fs := f64_to_str_pad(if f > 0 { f } else { -f }, p.len1)
if p.rm_tail_zero { if p.rm_tail_zero {
tmp := fs
fs = remove_tail_zeros_old(fs) fs = remove_tail_zeros_old(fs)
tmp.free()
} }
mut res := strings.new_builder(if p.len0 > fs.len { p.len0 } else { fs.len }) mut res := strings.new_builder(if p.len0 > fs.len { p.len0 } else { fs.len })
defer { defer {
res.free() res.free()
fs.free()
s.free()
} }
mut sign_len_diff := 0 mut sign_len_diff := 0
@ -647,8 +688,6 @@ pub fn format_es_old(f f64, p BF_param) string {
res.write_byte(p.pad_ch) res.write_byte(p.pad_ch)
} }
} }
s.free()
fs.free()
return res.str() return res.str()
} }
} }
@ -685,7 +724,7 @@ pub fn remove_tail_zeros_old(s string) string {
tmp = s[..last_zero_start] + s[i..] tmp = s[..last_zero_start] + s[i..]
} }
} else { } else {
tmp = s tmp = s.clone()
} }
if unsafe { tmp.str[tmp.len - 1] } == `.` { if unsafe { tmp.str[tmp.len - 1] } == `.` {
return tmp[..tmp.len - 1] return tmp[..tmp.len - 1]
@ -694,11 +733,13 @@ pub fn remove_tail_zeros_old(s string) string {
} }
// max int64 9223372036854775807 // max int64 9223372036854775807
[manualfree]
pub fn format_dec_old(d u64, p BF_param) string { pub fn format_dec_old(d u64, p BF_param) string {
mut s := '' mut s := ''
mut res := strings.new_builder(20) mut res := strings.new_builder(20)
defer { defer {
unsafe { res.free() } unsafe { res.free() }
unsafe { s.free() }
} }
mut sign_len_diff := 0 mut sign_len_diff := 0
if p.pad_ch == `0` { if p.pad_ch == `0` {
@ -711,16 +752,24 @@ pub fn format_dec_old(d u64, p BF_param) string {
res.write_byte(`-`) res.write_byte(`-`)
sign_len_diff = -1 sign_len_diff = -1
} }
tmp := s
s = d.str() s = d.str()
unsafe { tmp.free() }
} else { } else {
if p.positive { if p.positive {
if p.sign_flag { if p.sign_flag {
tmp := s
s = '+' + d.str() s = '+' + d.str()
unsafe { tmp.free() }
} else { } else {
tmp := s
s = d.str() s = d.str()
unsafe { tmp.free() }
} }
} else { } else {
tmp := s
s = '-' + d.str() s = '-' + d.str()
unsafe { tmp.free() }
} }
} }
dif := p.len0 - s.len + sign_len_diff dif := p.len0 - s.len + sign_len_diff