refactor: Fixed memory leaks in find_binary.

This commit is contained in:
2026-06-12 09:33:32 -04:00
parent 5865315161
commit dff5235d65
5 changed files with 58 additions and 14 deletions

View File

@@ -512,7 +512,7 @@ update_dir :: proc(f: ^EnvFile, new_dir: string) {
find_moved_dirs :: proc(d: ^Db, f: ^EnvFile) -> ([dynamic]string, bool) {
feats := check_features()
if !has_feature(feats, .Fd) || !has_feature(feats, .Git) {
if .Fd not_in feats || .Git not_in feats {
fmt.println("Error: fd and git are required for moved dir detection")
return {}, false
}

View File

@@ -1,5 +1,7 @@
package main
import "base:runtime"
import "core:mem"
import "core:os"
import "core:strings"
@@ -14,25 +16,36 @@ AvailableFeatures :: bit_set[Feature]
check_features :: proc() -> AvailableFeatures {
feats: AvailableFeatures
if find_binary("git") != "" {
s: mem.Scratch
mem.scratch_init(&s, 4 * mem.DEFAULT_PAGE_SIZE)
defer mem.scratch_destroy(&s)
context.temp_allocator = mem.scratch_allocator(&s)
path_env := os.get_env("PATH", context.temp_allocator)
paths := strings.split(path_env, ":", context.temp_allocator)
if find_binary(paths, "git") != "" {
feats += {.Git}
}
if find_binary("fd") != "" {
if find_binary(paths, "fd") != "" {
feats += {.Fd}
}
if find_binary("age") != "" {
if find_binary(paths, "age") != "" {
feats += {.Age}
}
return feats
}
find_binary :: proc(name: string) -> string {
path_env := os.get_env("PATH", context.allocator)
paths := strings.split(path_env, ":")
find_binary :: proc(
paths: []string,
name: string,
allocator: runtime.Allocator = context.temp_allocator,
) -> string {
for p in paths {
candidate := strings.join({strings.trim_right(p, "/"), name}, "/")
_, err := os.stat(candidate, context.allocator)
candidate := strings.join({strings.trim_right(p, "/"), name}, "/", allocator)
_, err := os.stat(candidate, allocator)
if err == nil {
return candidate
}
@@ -40,6 +53,3 @@ find_binary :: proc(name: string) -> string {
return ""
}
has_feature :: proc(feats: AvailableFeatures, f: Feature) -> bool {
return f in feats
}

34
features_test.odin Normal file
View File

@@ -0,0 +1,34 @@
package main
import "core:os"
import "core:strings"
import "core:testing"
@(test)
test_find_binary_exists :: proc(t: ^testing.T) {
path := os.get_env("PATH", context.allocator)
paths := strings.split(path, ":")
result := find_binary(paths, "sh")
testing.expect(t, result != "", "sh should be found on PATH")
}
@(test)
test_find_binary_not_exists :: proc(t: ^testing.T) {
old_path := os.get_env("PATH", context.allocator)
defer {
if old_path != "" {
os.set_env("PATH", old_path)
}
}
os.set_env("PATH", "/tmp/envr-nope")
path := os.get_env("PATH", context.allocator)
paths := strings.split(path, ":")
result := find_binary(paths, "no_such_binary_xyz")
testing.expect(t, result == "", "nonexistent binary should not be found")
}

View File

@@ -125,7 +125,7 @@ scan_path :: proc(search_path: string, cfg: Config) -> (paths: [dynamic]string,
can_scan :: proc() -> bool {
feats := check_features()
return has_feature(feats, .Fd)
return Feature.Fd in feats
}
find_unbacked :: proc(local_files: []string, db_files: []EnvFile) -> [dynamic]string {

View File

@@ -16,7 +16,7 @@ test_scan_path_finds_gitignored_env_files :: proc(t: ^testing.T) {
defer os.remove_all(base)
git_init := os.Process_Desc{
command = []string{"git", "init"},
command = []string{"git", "-c", "advice.defaultBranchName=false", "init"},
working_dir = base,
stdout = os.stderr,
stderr = os.stderr,