builtin: fix leak in rune.str(), fix leaks in most assert x == y statements in tests (#11091)
parent
0bd68bf5a2
commit
34d39ccb64
|
@ -55,6 +55,23 @@ pub:
|
||||||
rvalue string // the stringified *actual value* of the right side of a failed assertion
|
rvalue string // the stringified *actual value* of the right side of a failed assertion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// free is used to free the memory occupied by the assertion meta data.
|
||||||
|
// It is called by cb_assertion_failed, and cb_assertion_ok in the preludes,
|
||||||
|
// once they are done with reporting/formatting the meta data.
|
||||||
|
[manualfree; unsafe]
|
||||||
|
pub fn (ami &VAssertMetaInfo) free() {
|
||||||
|
unsafe {
|
||||||
|
ami.fpath.free()
|
||||||
|
ami.fn_name.free()
|
||||||
|
ami.src.free()
|
||||||
|
ami.op.free()
|
||||||
|
ami.llabel.free()
|
||||||
|
ami.rlabel.free()
|
||||||
|
ami.lvalue.free()
|
||||||
|
ami.rvalue.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn __print_assert_failure(i &VAssertMetaInfo) {
|
fn __print_assert_failure(i &VAssertMetaInfo) {
|
||||||
eprintln('$i.fpath:${i.line_nr + 1}: FAIL: fn $i.fn_name: assert $i.src')
|
eprintln('$i.fpath:${i.line_nr + 1}: FAIL: fn $i.fn_name: assert $i.src')
|
||||||
if i.op.len > 0 && i.op != 'call' {
|
if i.op.len > 0 && i.op != 'call' {
|
||||||
|
|
|
@ -12,34 +12,38 @@ pub fn utf8_char_len(b byte) int {
|
||||||
pub fn utf32_to_str(code u32) string {
|
pub fn utf32_to_str(code u32) string {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut buffer := malloc_noscan(5)
|
mut buffer := malloc_noscan(5)
|
||||||
return utf32_to_str_no_malloc(code, buffer)
|
res := utf32_to_str_no_malloc(code, buffer)
|
||||||
|
if res.len == 0 {
|
||||||
|
// the buffer was not used at all
|
||||||
|
free(buffer)
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[unsafe]
|
[manualfree; unsafe]
|
||||||
pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string {
|
pub fn utf32_to_str_no_malloc(code u32, buf &byte) string {
|
||||||
icode := int(code) // Prevents doing casts everywhere
|
|
||||||
mut res := ''
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
icode := int(code) // Prevents doing casts everywhere
|
||||||
mut buffer := &byte(buf)
|
mut buffer := &byte(buf)
|
||||||
if icode <= 127 {
|
if icode <= 127 {
|
||||||
// 0x7F
|
// 0x7F
|
||||||
buffer[0] = byte(icode)
|
buffer[0] = byte(icode)
|
||||||
buffer[1] = 0
|
buffer[1] = 0
|
||||||
res = tos(buffer, 1)
|
return tos(buffer, 1)
|
||||||
} else if icode <= 2047 {
|
} else if icode <= 2047 {
|
||||||
// 0x7FF
|
// 0x7FF
|
||||||
buffer[0] = 192 | byte(icode >> 6) // 0xC0 - 110xxxxx
|
buffer[0] = 192 | byte(icode >> 6) // 0xC0 - 110xxxxx
|
||||||
buffer[1] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
buffer[1] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||||
buffer[2] = 0
|
buffer[2] = 0
|
||||||
res = tos(buffer, 2)
|
return tos(buffer, 2)
|
||||||
} else if icode <= 65535 {
|
} else if icode <= 65535 {
|
||||||
// 0xFFFF
|
// 0xFFFF
|
||||||
buffer[0] = 224 | byte(icode >> 12) // 0xE0 - 1110xxxx
|
buffer[0] = 224 | byte(icode >> 12) // 0xE0 - 1110xxxx
|
||||||
buffer[1] = 128 | (byte(icode >> 6) & 63) // 0x80 - 0x3F - 10xxxxxx
|
buffer[1] = 128 | (byte(icode >> 6) & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||||
buffer[2] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
buffer[2] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||||
buffer[3] = 0
|
buffer[3] = 0
|
||||||
res = tos(buffer, 3)
|
return tos(buffer, 3)
|
||||||
}
|
}
|
||||||
// 0x10FFFF
|
// 0x10FFFF
|
||||||
else if icode <= 1114111 {
|
else if icode <= 1114111 {
|
||||||
|
@ -48,11 +52,10 @@ pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string {
|
||||||
buffer[2] = 128 | (byte(icode >> 6) & 63) // 0x80 - 0x3F - 10xxxxxx
|
buffer[2] = 128 | (byte(icode >> 6) & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||||
buffer[3] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
buffer[3] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||||
buffer[4] = 0
|
buffer[4] = 0
|
||||||
res = tos(buffer, 4)
|
return tos(buffer, 4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.is_lit = 1 // let autofree know this string doesn't have to be freed
|
return ''
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert utf8 to utf32
|
// Convert utf8 to utf32
|
||||||
|
|
|
@ -60,7 +60,7 @@ pub fn (mut cb Clipboard) get_text() string {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
utf8_clip := C.darwin_get_pasteboard_text(cb.pb)
|
utf8_clip := C.darwin_get_pasteboard_text(cb.pb)
|
||||||
return unsafe { utf8_clip.vstring() }
|
return unsafe { tos_clone(&byte(utf8_clip)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// new_primary returns a new X11 `PRIMARY` type `Clipboard` instance allocated on the heap.
|
// new_primary returns a new X11 `PRIMARY` type `Clipboard` instance allocated on the heap.
|
||||||
|
|
|
@ -6,6 +6,7 @@ fn test_long_encoding() {
|
||||||
|
|
||||||
s_original := []byte{len: input_size, init: `a`}
|
s_original := []byte{len: input_size, init: `a`}
|
||||||
s_encoded := base64.encode(s_original)
|
s_encoded := base64.encode(s_original)
|
||||||
|
s_encoded_bytes := s_encoded.bytes()
|
||||||
s_decoded := base64.decode(s_encoded)
|
s_decoded := base64.decode(s_encoded)
|
||||||
|
|
||||||
assert s_encoded.len > s_original.len
|
assert s_encoded.len > s_original.len
|
||||||
|
@ -13,6 +14,10 @@ fn test_long_encoding() {
|
||||||
|
|
||||||
ebuffer := unsafe { malloc(s_encoded.len) }
|
ebuffer := unsafe { malloc(s_encoded.len) }
|
||||||
dbuffer := unsafe { malloc(s_decoded.len) }
|
dbuffer := unsafe { malloc(s_decoded.len) }
|
||||||
|
defer {
|
||||||
|
unsafe { free(ebuffer) }
|
||||||
|
unsafe { free(dbuffer) }
|
||||||
|
}
|
||||||
//
|
//
|
||||||
encoded_size := base64.encode_in_buffer(s_original, ebuffer)
|
encoded_size := base64.encode_in_buffer(s_original, ebuffer)
|
||||||
mut encoded_in_buf := []byte{len: encoded_size}
|
mut encoded_in_buf := []byte{len: encoded_size}
|
||||||
|
@ -27,7 +32,8 @@ fn test_long_encoding() {
|
||||||
assert encoded_in_buf[encoded_size - 3] == `W`
|
assert encoded_in_buf[encoded_size - 3] == `W`
|
||||||
assert encoded_in_buf[encoded_size - 2] == `F`
|
assert encoded_in_buf[encoded_size - 2] == `F`
|
||||||
assert encoded_in_buf[encoded_size - 1] == `h`
|
assert encoded_in_buf[encoded_size - 1] == `h`
|
||||||
assert encoded_in_buf == s_encoded.bytes()
|
|
||||||
|
assert encoded_in_buf == s_encoded_bytes
|
||||||
|
|
||||||
decoded_size := base64.decode_in_buffer(s_encoded, dbuffer)
|
decoded_size := base64.decode_in_buffer(s_encoded, dbuffer)
|
||||||
assert decoded_size == input_size
|
assert decoded_size == input_size
|
||||||
|
|
|
@ -181,11 +181,13 @@ fn supports_escape_sequences(fd int) bool {
|
||||||
if vcolors_override == 'never' {
|
if vcolors_override == 'never' {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if os.getenv('TERM') == 'dumb' {
|
env_term := os.getenv('TERM')
|
||||||
|
if env_term == 'dumb' {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
if os.getenv('ConEmuANSI') == 'ON' {
|
env_conemu := os.getenv('ConEmuANSI')
|
||||||
|
if env_conemu == 'ON' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// 4 is enable_virtual_terminal_processing
|
// 4 is enable_virtual_terminal_processing
|
||||||
|
|
|
@ -290,16 +290,17 @@ pub fn (x Expr) str() string {
|
||||||
}
|
}
|
||||||
CallExpr {
|
CallExpr {
|
||||||
sargs := args2str(x.args)
|
sargs := args2str(x.args)
|
||||||
|
propagate_suffix := if x.or_block.kind == .propagate { ' ?' } else { '' }
|
||||||
if x.is_method {
|
if x.is_method {
|
||||||
return '${x.left.str()}.${x.name}($sargs)'
|
return '${x.left.str()}.${x.name}($sargs)$propagate_suffix'
|
||||||
}
|
}
|
||||||
if x.name.starts_with('${x.mod}.') {
|
if x.name.starts_with('${x.mod}.') {
|
||||||
return util.strip_main_name('${x.name}($sargs)')
|
return util.strip_main_name('${x.name}($sargs)$propagate_suffix')
|
||||||
}
|
}
|
||||||
if x.mod == '' && x.name == '' {
|
if x.mod == '' && x.name == '' {
|
||||||
return x.left.str() + '($sargs)'
|
return x.left.str() + '($sargs)$propagate_suffix'
|
||||||
}
|
}
|
||||||
return '${x.mod}.${x.name}($sargs)'
|
return '${x.mod}.${x.name}($sargs)$propagate_suffix'
|
||||||
}
|
}
|
||||||
CharLiteral {
|
CharLiteral {
|
||||||
return '`$x.val`'
|
return '`$x.val`'
|
||||||
|
|
|
@ -101,6 +101,7 @@ fn (mut g Gen) gen_assert_metainfo(node ast.AssertStmt) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_assert_single_expr(expr ast.Expr, typ ast.Type) {
|
fn (mut g Gen) gen_assert_single_expr(expr ast.Expr, typ ast.Type) {
|
||||||
|
// eprintln('> gen_assert_single_expr typ: $typ | expr: $expr | typeof(expr): ${typeof(expr)}')
|
||||||
unknown_value := '*unknown value*'
|
unknown_value := '*unknown value*'
|
||||||
match expr {
|
match expr {
|
||||||
ast.CastExpr, ast.IndexExpr, ast.MatchExpr {
|
ast.CastExpr, ast.IndexExpr, ast.MatchExpr {
|
||||||
|
@ -121,7 +122,29 @@ fn (mut g Gen) gen_assert_single_expr(expr ast.Expr, typ ast.Type) {
|
||||||
g.write(ctoslit('$sym.name'))
|
g.write(ctoslit('$sym.name'))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
mut should_clone := true
|
||||||
|
if typ == ast.string_type && expr is ast.StringLiteral {
|
||||||
|
should_clone = false
|
||||||
|
}
|
||||||
|
if expr is ast.CTempVar {
|
||||||
|
if expr.orig is ast.CallExpr {
|
||||||
|
should_clone = false
|
||||||
|
if expr.orig.or_block.kind == .propagate {
|
||||||
|
should_clone = true
|
||||||
|
}
|
||||||
|
if expr.orig.is_method && expr.orig.args.len == 0
|
||||||
|
&& expr.orig.name == 'type_name' {
|
||||||
|
should_clone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if should_clone {
|
||||||
|
g.write('string_clone(')
|
||||||
|
}
|
||||||
g.gen_expr_to_string(expr, typ)
|
g.gen_expr_to_string(expr, typ)
|
||||||
|
if should_clone {
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write(' /* typeof: ' + expr.type_name() + ' type: ' + typ.str() + ' */ ')
|
g.write(' /* typeof: ' + expr.type_name() + ' type: ' + typ.str() + ' */ ')
|
||||||
|
|
|
@ -3625,7 +3625,7 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
||||||
if sym.kind == .sum_type {
|
if sym.kind == .sum_type {
|
||||||
// When encountering a .sum_type, typeof() should be done at runtime,
|
// When encountering a .sum_type, typeof() should be done at runtime,
|
||||||
// because the subtype of the expression may change:
|
// because the subtype of the expression may change:
|
||||||
g.write('tos3( /* $sym.name */ v_typeof_sumtype_${sym.cname}( (')
|
g.write('charptr_vstring_literal( /* $sym.name */ v_typeof_sumtype_${sym.cname}( (')
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
g.write(')._typ ))')
|
g.write(')._typ ))')
|
||||||
} else if sym.kind == .array_fixed {
|
} else if sym.kind == .array_fixed {
|
||||||
|
|
|
@ -745,14 +745,14 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if left_sym.kind == .sum_type && node.name == 'type_name' {
|
if left_sym.kind == .sum_type && node.name == 'type_name' {
|
||||||
g.write('tos3( /* $left_sym.name */ v_typeof_sumtype_${typ_sym.cname}( (')
|
g.write('charptr_vstring_literal( /* $left_sym.name */ v_typeof_sumtype_${typ_sym.cname}( (')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
||||||
g.write(')${dot}_typ ))')
|
g.write(')${dot}_typ ))')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if left_sym.kind == .interface_ && node.name == 'type_name' {
|
if left_sym.kind == .interface_ && node.name == 'type_name' {
|
||||||
g.write('tos3( /* $left_sym.name */ v_typeof_interface_${typ_sym.cname}( (')
|
g.write('charptr_vstring_literal( /* $left_sym.name */ v_typeof_interface_${typ_sym.cname}( (')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
||||||
g.write(')${dot}_typ ))')
|
g.write(')${dot}_typ ))')
|
||||||
|
|
|
@ -49,8 +49,10 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||||
// byteptr and charptr
|
// byteptr and charptr
|
||||||
'3.vstring',
|
'3.vstring',
|
||||||
'3.vstring_with_len',
|
'3.vstring_with_len',
|
||||||
|
'3.vstring_literal',
|
||||||
'4.vstring',
|
'4.vstring',
|
||||||
'4.vstring_with_len',
|
'4.vstring_with_len',
|
||||||
|
'4.vstring_literal',
|
||||||
// byte. methods
|
// byte. methods
|
||||||
'9.str_escaped',
|
'9.str_escaped',
|
||||||
// string. methods
|
// string. methods
|
||||||
|
|
|
@ -62,6 +62,7 @@ fn cb_assertion_failed(i &VAssertMetaInfo) {
|
||||||
eprintln(' $final_src')
|
eprintln(' $final_src')
|
||||||
}
|
}
|
||||||
eprintln('')
|
eprintln('')
|
||||||
|
unsafe { i.free() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cb_assertion_ok(i &VAssertMetaInfo) {
|
fn cb_assertion_ok(i &VAssertMetaInfo) {
|
||||||
|
@ -85,6 +86,7 @@ fn cb_assertion_ok(i &VAssertMetaInfo) {
|
||||||
}
|
}
|
||||||
println('$final_funcname ($final_filepath)')
|
println('$final_funcname ($final_filepath)')
|
||||||
*/
|
*/
|
||||||
|
unsafe { i.free() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cb_propagate_test_error(line_nr int, file string, mod string, fn_name string, errmsg string) {
|
fn cb_propagate_test_error(line_nr int, file string, mod string, fn_name string, errmsg string) {
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import encoding.base64
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
repeats := 1000
|
||||||
|
input_size := 3000
|
||||||
|
|
||||||
|
s_original := []byte{len: input_size, init: `a`}
|
||||||
|
s_encoded := base64.encode(s_original)
|
||||||
|
s_encoded_bytes := s_encoded.bytes()
|
||||||
|
s_decoded := base64.decode(s_encoded)
|
||||||
|
|
||||||
|
assert s_encoded.len > s_original.len
|
||||||
|
assert s_original == s_decoded
|
||||||
|
|
||||||
|
ebuffer := unsafe { malloc(s_encoded.len) }
|
||||||
|
dbuffer := unsafe { malloc(s_decoded.len) }
|
||||||
|
defer {
|
||||||
|
unsafe { free(ebuffer) }
|
||||||
|
unsafe { free(dbuffer) }
|
||||||
|
}
|
||||||
|
//
|
||||||
|
encoded_size := base64.encode_in_buffer(s_original, ebuffer)
|
||||||
|
mut encoded_in_buf := []byte{len: encoded_size}
|
||||||
|
unsafe { C.memcpy(encoded_in_buf.data, ebuffer, encoded_size) }
|
||||||
|
assert input_size * 4 / 3 == encoded_size
|
||||||
|
assert encoded_in_buf[0] == `Y`
|
||||||
|
assert encoded_in_buf[1] == `W`
|
||||||
|
assert encoded_in_buf[2] == `F`
|
||||||
|
assert encoded_in_buf[3] == `h`
|
||||||
|
|
||||||
|
assert encoded_in_buf[encoded_size - 4] == `Y`
|
||||||
|
assert encoded_in_buf[encoded_size - 3] == `W`
|
||||||
|
assert encoded_in_buf[encoded_size - 2] == `F`
|
||||||
|
assert encoded_in_buf[encoded_size - 1] == `h`
|
||||||
|
|
||||||
|
assert encoded_in_buf == s_encoded_bytes
|
||||||
|
|
||||||
|
decoded_size := base64.decode_in_buffer(s_encoded, dbuffer)
|
||||||
|
assert decoded_size == input_size
|
||||||
|
mut decoded_in_buf := []byte{len: decoded_size}
|
||||||
|
unsafe { C.memcpy(decoded_in_buf.data, dbuffer, decoded_size) }
|
||||||
|
assert decoded_in_buf == s_original
|
||||||
|
|
||||||
|
mut s := 0
|
||||||
|
for _ in 0 .. repeats {
|
||||||
|
resultsize := base64.encode_in_buffer(s_original, ebuffer)
|
||||||
|
s += resultsize
|
||||||
|
assert resultsize == s_encoded.len
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0 .. repeats {
|
||||||
|
resultsize := base64.decode_in_buffer(s_encoded, dbuffer)
|
||||||
|
s += resultsize
|
||||||
|
assert resultsize == s_decoded.len
|
||||||
|
}
|
||||||
|
|
||||||
|
println('Final s: $s')
|
||||||
|
// assert s == 39147008
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
mut buffer := malloc_noscan(5)
|
||||||
|
s := utf32_to_str_no_malloc(77, buffer)
|
||||||
|
println(s)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
a := `Y`.str()
|
||||||
|
println(a)
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
a := 'Y'.str()
|
||||||
|
println(a)
|
||||||
|
}
|
Loading…
Reference in New Issue