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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
eprintln('$i.fpath:${i.line_nr + 1}: FAIL: fn $i.fn_name: assert $i.src')
|
||||
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 {
|
||||
unsafe {
|
||||
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]
|
||||
pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string {
|
||||
icode := int(code) // Prevents doing casts everywhere
|
||||
mut res := ''
|
||||
[manualfree; unsafe]
|
||||
pub fn utf32_to_str_no_malloc(code u32, buf &byte) string {
|
||||
unsafe {
|
||||
icode := int(code) // Prevents doing casts everywhere
|
||||
mut buffer := &byte(buf)
|
||||
if icode <= 127 {
|
||||
// 0x7F
|
||||
buffer[0] = byte(icode)
|
||||
buffer[1] = 0
|
||||
res = tos(buffer, 1)
|
||||
return tos(buffer, 1)
|
||||
} else if icode <= 2047 {
|
||||
// 0x7FF
|
||||
buffer[0] = 192 | byte(icode >> 6) // 0xC0 - 110xxxxx
|
||||
buffer[1] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||
buffer[2] = 0
|
||||
res = tos(buffer, 2)
|
||||
return tos(buffer, 2)
|
||||
} else if icode <= 65535 {
|
||||
// 0xFFFF
|
||||
buffer[0] = 224 | byte(icode >> 12) // 0xE0 - 1110xxxx
|
||||
buffer[1] = 128 | (byte(icode >> 6) & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||
buffer[2] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||
buffer[3] = 0
|
||||
res = tos(buffer, 3)
|
||||
return tos(buffer, 3)
|
||||
}
|
||||
// 0x10FFFF
|
||||
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[3] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx
|
||||
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 res
|
||||
return ''
|
||||
}
|
||||
|
||||
// Convert utf8 to utf32
|
||||
|
|
|
@ -60,7 +60,7 @@ pub fn (mut cb Clipboard) get_text() string {
|
|||
return ''
|
||||
}
|
||||
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.
|
||||
|
|
|
@ -6,6 +6,7 @@ fn test_long_encoding() {
|
|||
|
||||
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
|
||||
|
@ -13,6 +14,10 @@ fn test_long_encoding() {
|
|||
|
||||
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}
|
||||
|
@ -27,7 +32,8 @@ fn test_long_encoding() {
|
|||
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()
|
||||
|
||||
assert encoded_in_buf == s_encoded_bytes
|
||||
|
||||
decoded_size := base64.decode_in_buffer(s_encoded, dbuffer)
|
||||
assert decoded_size == input_size
|
||||
|
|
|
@ -181,11 +181,13 @@ fn supports_escape_sequences(fd int) bool {
|
|||
if vcolors_override == 'never' {
|
||||
return false
|
||||
}
|
||||
if os.getenv('TERM') == 'dumb' {
|
||||
env_term := os.getenv('TERM')
|
||||
if env_term == 'dumb' {
|
||||
return false
|
||||
}
|
||||
$if windows {
|
||||
if os.getenv('ConEmuANSI') == 'ON' {
|
||||
env_conemu := os.getenv('ConEmuANSI')
|
||||
if env_conemu == 'ON' {
|
||||
return true
|
||||
}
|
||||
// 4 is enable_virtual_terminal_processing
|
||||
|
|
|
@ -290,16 +290,17 @@ pub fn (x Expr) str() string {
|
|||
}
|
||||
CallExpr {
|
||||
sargs := args2str(x.args)
|
||||
propagate_suffix := if x.or_block.kind == .propagate { ' ?' } else { '' }
|
||||
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}.') {
|
||||
return util.strip_main_name('${x.name}($sargs)')
|
||||
return util.strip_main_name('${x.name}($sargs)$propagate_suffix')
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
// eprintln('> gen_assert_single_expr typ: $typ | expr: $expr | typeof(expr): ${typeof(expr)}')
|
||||
unknown_value := '*unknown value*'
|
||||
match expr {
|
||||
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'))
|
||||
}
|
||||
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)
|
||||
if should_clone {
|
||||
g.write(')')
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
// When encountering a .sum_type, typeof() should be done at runtime,
|
||||
// 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.write(')._typ ))')
|
||||
} 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' {
|
||||
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)
|
||||
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
||||
g.write(')${dot}_typ ))')
|
||||
return
|
||||
}
|
||||
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)
|
||||
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
||||
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
|
||||
'3.vstring',
|
||||
'3.vstring_with_len',
|
||||
'3.vstring_literal',
|
||||
'4.vstring',
|
||||
'4.vstring_with_len',
|
||||
'4.vstring_literal',
|
||||
// byte. methods
|
||||
'9.str_escaped',
|
||||
// string. methods
|
||||
|
|
|
@ -62,6 +62,7 @@ fn cb_assertion_failed(i &VAssertMetaInfo) {
|
|||
eprintln(' $final_src')
|
||||
}
|
||||
eprintln('')
|
||||
unsafe { i.free() }
|
||||
}
|
||||
|
||||
fn cb_assertion_ok(i &VAssertMetaInfo) {
|
||||
|
@ -85,6 +86,7 @@ fn cb_assertion_ok(i &VAssertMetaInfo) {
|
|||
}
|
||||
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) {
|
||||
|
|
|
@ -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