From c51df72f1a8a21dd0064086dfc1186a3dd79e2ef Mon Sep 17 00:00:00 2001 From: Christiano Haesbaert Date: Sat, 11 Jan 2025 21:46:28 +0100 Subject: [PATCH] Make sure we don't leak os.args. Fixes #1633. os.args is never freed, while this is an insignificant leak, it is a bit annoying as it makes valgrind complain: ==234270== Memcheck, a memory error detector ==234270== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al. ==234270== Using Valgrind-3.24.0 and LibVEX; rerun with -h for copyright info ==234270== Command: ./wc /tmp/mulumulu ==234270== 1 8 58 /tmp/mulumulu ==234270== ==234270== HEAP SUMMARY: ==234270== in use at exit: 47 bytes in 1 blocks ==234270== total heap usage: 5 allocs, 4 frees, 4,195,875 bytes allocated ==234270== ==234270== 47 bytes in 1 blocks are possibly lost in loss record 1 of 1 ==234270== at 0x484BC13: calloc (vg_replace_malloc.c:1675) ==234270== by 0x402E49: runtime._heap_alloc-769 (in /d/learn-odin/wc/wc) ==234270== by 0x40A8D7: runtime.heap_alloc (in /d/learn-odin/wc/wc) ==234270== by 0x436E9D: runtime.heap_allocator_proc.aligned_alloc-0 (in /d/learn-odin/wc/wc) ==234270== by 0x4022DC: runtime.heap_allocator_proc (in /d/learn-odin/wc/wc) ==234270== by 0x4165E0: runtime.make_aligned-22560 (in /d/learn-odin/wc/wc) ==234270== by 0x41F6D0: runtime.make_slice-22340 (in /d/learn-odin/wc/wc) ==234270== by 0x40156B: os._alloc_command_line_arguments-4679 (in /d/learn-odin/wc/wc) ==234270== by 0x4011AF: __$startup_runtime (in /d/learn-odin/wc/wc) ==234270== by 0x406F17: main (in /d/learn-odin/wc/wc) ==234270== ==234270== LEAK SUMMARY: ==234270== definitely lost: 0 bytes in 0 blocks ==234270== indirectly lost: 0 bytes in 0 blocks ==234270== possibly lost: 47 bytes in 1 blocks ==234270== still reachable: 0 bytes in 0 blocks ==234270== suppressed: 0 bytes in 0 blocks ==234270== ==234270== For lists of detected and suppressed errors, rerun with: -s ==234270== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) With the fix the leak is gone, tested on linux only. While here, also make _alloc_command_line_arguments() private. --- core/os/os_darwin.odin | 7 ++++++- core/os/os_freebsd.odin | 7 ++++++- core/os/os_haiku.odin | 7 ++++++- core/os/os_linux.odin | 7 ++++++- core/os/os_netbsd.odin | 7 ++++++- core/os/os_openbsd.odin | 7 ++++++- core/os/os_wasi.odin | 7 ++++++- core/os/os_windows.odin | 10 +++++++++- 8 files changed, 51 insertions(+), 8 deletions(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index d4435ec639e..3247eeeee00 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -1196,7 +1196,7 @@ _processor_core_count :: proc() -> int { return 1 } -@(require_results) +@(private, require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for _, i in res { @@ -1205,6 +1205,11 @@ _alloc_command_line_arguments :: proc() -> []string { return res } +@(private, fini) +_delete_command_line_arguments :: proc() { + delete(args) +} + socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := _unix_socket(c.int(domain), c.int(type), c.int(protocol)) if result < 0 { diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 87a56b05729..7eafb499303 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -936,7 +936,7 @@ _processor_core_count :: proc() -> int { } -@(require_results) +@(private, require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { @@ -944,3 +944,8 @@ _alloc_command_line_arguments :: proc() -> []string { } return res } + +@(private, fini) +_delete_command_line_arguments :: proc() { + delete(args) +} diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index 4a57afb87e6..24d68d3419f 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -316,7 +316,7 @@ file_size :: proc(fd: Handle) -> (i64, Error) { // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() -@(require_results) +@(private, require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { @@ -325,6 +325,11 @@ _alloc_command_line_arguments :: proc() -> []string { return res } +@(private, fini) +_delete_command_line_arguments :: proc() { + delete(args) +} + @(private, require_results) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index e023ce7cb84..47b321f9536 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -1069,7 +1069,7 @@ _processor_core_count :: proc() -> int { return int(_unix_get_nprocs()) } -@(require_results) +@(private, require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { @@ -1078,6 +1078,11 @@ _alloc_command_line_arguments :: proc() -> []string { return res } +@(private, fini) +_delete_command_line_arguments :: proc() { + delete(args) +} + @(require_results) socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := unix.sys_socket(domain, type, protocol) diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index e3ba760a4de..7bef85bed08 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -986,7 +986,7 @@ _processor_core_count :: proc() -> int { return 1 } -@(require_results) +@(private, require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { @@ -994,3 +994,8 @@ _alloc_command_line_arguments :: proc() -> []string { } return res } + +@(private, fini) +_delete_command_line_arguments :: proc() { + delete(args) +} diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 3c377968c56..c013fbc9148 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -885,7 +885,7 @@ _processor_core_count :: proc() -> int { return int(_sysconf(_SC_NPROCESSORS_ONLN)) } -@(require_results) +@(private, require_results) _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { @@ -893,3 +893,8 @@ _alloc_command_line_arguments :: proc() -> []string { } return res } + +@(private, fini) +_delete_command_line_arguments :: proc() { + delete(args) +} diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 28f470357b6..0edc08415f8 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -27,7 +27,7 @@ stderr: Handle = 2 args := _alloc_command_line_arguments() -@(require_results) +@(private, require_results) _alloc_command_line_arguments :: proc() -> (args: []string) { args = make([]string, len(runtime.args__)) for &arg, i in args { @@ -36,6 +36,11 @@ _alloc_command_line_arguments :: proc() -> (args: []string) { return } +@(private, fini) +_delete_command_line_arguments :: proc() { + delete(args) +} + // WASI works with "preopened" directories, the environment retrieves directories // (for example with `wasmtime --dir=. module.wasm`) and those given directories // are the only ones accessible by the application. diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 0c532bf143e..3c1725cc58c 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -193,7 +193,7 @@ current_thread_id :: proc "contextless" () -> int { -@(require_results) +@(private, require_results) _alloc_command_line_arguments :: proc() -> []string { arg_count: i32 arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count) @@ -215,6 +215,14 @@ _alloc_command_line_arguments :: proc() -> []string { return arg_list } +@(private, fini) +_delete_command_line_arguments :: proc() { + for s in args { + delete(s) + } + delete(args) +} + /* Windows 11 (preview) has the same major and minor version numbers as Windows 10: 10 and 0 respectively.