v
v copied to clipboard
autofree: memory leak
Describe the bug
-autofree should not leak
Reproduction Steps
leak.v
module main
struct MyLeak {
a u32
}
fn leak_test(leak &MyLeak) {
println(leak)
}
fn main() {
leak := MyLeak{}
leak_test(&leak)
}
then compile
v . -gc none -autofree && valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes ./leak
Expected Behavior
no leak report
Current Behavior
==68272== Memcheck, a memory error detector
==68272== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==68272== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==68272== Command: ./leak
==68272==
&MyLeak{
a: 0
}
==68272==
==68272== HEAP SUMMARY:
==68272== in use at exit: 19 bytes in 1 blocks
==68272== total heap usage: 8 allocs, 7 frees, 1,619 bytes allocated
==68272==
==68272== 19 bytes in 1 blocks are definitely lost in loss record 1 of 1
==68272== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==68272== by 0x6192C1: malloc_noscan (in /home/mars/v/leak/leak)
==68272== by 0x619D16: memdup_noscan (in /home/mars/v/leak/leak)
==68272== by 0x6036F8: strings__Builder_str (in /home/mars/v/leak/leak)
==68272== by 0x632391: str_intp (in /home/mars/v/leak/leak)
==68272== by 0x602951: indent_main__MyLeak_str (in /home/mars/v/leak/leak)
==68272== by 0x6025A3: main__MyLeak_str (in /home/mars/v/leak/leak)
==68272== by 0x63421D: main__leak_test (in /home/mars/v/leak/leak)
==68272== by 0x6342DE: main__main (in /home/mars/v/leak/leak)
==68272== by 0x634840: main (in /home/mars/v/leak/leak)
==68272==
==68272== LEAK SUMMARY:
==68272== definitely lost: 19 bytes in 1 blocks
==68272== indirectly lost: 0 bytes in 0 blocks
==68272== possibly lost: 0 bytes in 0 blocks
==68272== still reachable: 0 bytes in 0 blocks
==68272== suppressed: 0 bytes in 0 blocks
==68272==
==68272== For lists of detected and suppressed errors, rerun with: -s
==68272== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Possible Solution
generated c code:
VV_LOCAL_SYMBOL void main__leak_test(main__MyLeak* leak) {
string _t1 = str_intp(1, _MOV((StrIntpData[]){{_SLIT("&"), 0xfe10 ,{.d_s = isnil(leak) ? _SLIT("nil") : main__MyLeak_str(*leak)}}})); println(_t1); string_free(&_t1);
;
}
VV_LOCAL_SYMBOL void main__main(void) {
main__MyLeak leak = ((main__MyLeak){.a = 0,});
main__leak_test(&leak);
}
maybe can be modified as follow:
VV_LOCAL_SYMBOL void main__leak_test(main__MyLeak* leak) {
string _t1 = main__MyLeak_str(*leak);
string _t2 = str_intp(1, _MOV((StrIntpData[]){{_SLIT("&"), 0xfe10 ,{.d_s = isnil(leak) ? _SLIT("nil") : _t1}}})); string_free(&_t1); println(_t2); string_free(&_t2);
;
}
VV_LOCAL_SYMBOL void main__main(void) {
main__MyLeak leak = ((main__MyLeak){.a = 0,});
main__leak_test(&leak);
}
Additional Information/Context
No response
V version
V 0.4.4 88bc620.fffb82d
Environment details (OS name and version, etc.)
V full version: V 0.4.4 88bc620.fffb82d OS: linux, Ubuntu 22.04.4 LTS Processor: 8 cpus, 64bit, little endian, Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
getwd: /home/mars/v/leak vexe: /HD/github/kbkpbot/v/v vexe mtime: 2024-02-19 10:26:50
vroot: OK, value: /HD/github/kbkpbot/v VMODULES: OK, value: /home/mars/.vmodules VTMP: OK, value: /tmp/v_1000
Git version: git version 2.34.1 Git vroot status: weekly.2024.07-48-gd198a898 (28 commit(s) behind V master) .git/config present: true
CC version: cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 thirdparty/tcc status: thirdparty-linux-amd64 40e5cbb5-dirty
[!NOTE] You can use the 👍 reaction to increase the issue's priority for developers.
Please note that only the 👍 reaction to the issue itself counts as a vote. Other reactions and those to comments will not be taken into account.
This bug is related to how V(c gen) operate on string. For example:
VV_LOCAL_SYMBOL void main__leak_test(main__MyLeak* leak) {
string _t1 = str_intp(1, _MOV((StrIntpData[]){{_SLIT("&"), 0xfe10 ,{.d_s = isnil(leak) ? _SLIT("nil") : main__MyLeak_str(*leak)}}})); println(_t1); string_free(&_t1);
;
}
As the function main__MyLeak_str(*leak)
will create a new string on heap, but there is noway free it.
I checked the vlib/gen/c/str.v: fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type)
, it try to generate a string from expr, but this will sometimes alloc a new string on heap.
It need to free somewhere.