Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #4890 #4891

Merged
merged 2 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/os/os2/path_openbsd.odin
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
strings.write_string(&buf, "/")
strings.write_string(&buf, sarg)

cpath := strings.to_cstring(&buf)
cpath := strings.to_cstring(&buf) or_return
if posix.access(cpath, {.X_OK}) == .OK {
return real(cpath, allocator)
}
Expand Down
4 changes: 2 additions & 2 deletions core/os/os2/pipe_posix.odin
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
strings.write_string(&rname, "/dev/fd/")
strings.write_int(&rname, int(fds[0]))
ri.name = strings.to_string(rname)
ri.cname = strings.to_cstring(&rname)
ri.cname = strings.to_cstring(&rname) or_return

w = __new_file(fds[1], file_allocator())
wi := (^File_Impl)(w.impl)
Expand All @@ -39,7 +39,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
strings.write_string(&wname, "/dev/fd/")
strings.write_int(&wname, int(fds[1]))
wi.name = strings.to_string(wname)
wi.cname = strings.to_cstring(&wname)
wi.cname = strings.to_cstring(&wname) or_return

return
}
Expand Down
16 changes: 8 additions & 8 deletions core/os/os2/process_linux.odin
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator

strings.write_string(&path_builder, "/proc/")
strings.write_int(&path_builder, pid)
proc_fd, errno := linux.open(strings.to_cstring(&path_builder), _OPENDIR_FLAGS)
proc_fd, errno := linux.open(strings.to_cstring(&path_builder) or_return, _OPENDIR_FLAGS)
if errno != .NONE {
err = _get_platform_error(errno)
return
Expand Down Expand Up @@ -169,7 +169,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
strings.write_int(&path_builder, pid)
strings.write_string(&path_builder, "/cmdline")

cmdline_bytes, cmdline_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder), temp_allocator())
cmdline_bytes, cmdline_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
if cmdline_err != nil || len(cmdline_bytes) == 0 {
err = cmdline_err
break cmdline_if
Expand All @@ -190,7 +190,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
strings.write_int(&path_builder, pid)
strings.write_string(&path_builder, "/cwd")

cwd, cwd_err = _read_link_cstr(strings.to_cstring(&path_builder), temp_allocator()) // allowed to fail
cwd, cwd_err = _read_link_cstr(strings.to_cstring(&path_builder) or_return, temp_allocator()) // allowed to fail
if cwd_err == nil && .Working_Dir in selection {
info.working_dir = strings.clone(cwd, allocator) or_return
info.fields += {.Working_Dir}
Expand Down Expand Up @@ -258,7 +258,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
strings.write_int(&path_builder, pid)
strings.write_string(&path_builder, "/stat")

proc_stat_bytes, stat_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder), temp_allocator())
proc_stat_bytes, stat_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
if stat_err != nil {
err = stat_err
break stat_if
Expand Down Expand Up @@ -330,7 +330,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
strings.write_int(&path_builder, pid)
strings.write_string(&path_builder, "/environ")

if env_bytes, env_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder), temp_allocator()); env_err == nil {
if env_bytes, env_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator()); env_err == nil {
env := string(env_bytes)

env_list := make([dynamic]string, allocator) or_return
Expand Down Expand Up @@ -418,7 +418,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
strings.write_byte(&exe_builder, '/')
strings.write_string(&exe_builder, executable_name)

exe_path = strings.to_cstring(&exe_builder)
exe_path = strings.to_cstring(&exe_builder) or_return
if linux.access(exe_path, linux.X_OK) == .NONE {
found = true
break
Expand All @@ -430,7 +430,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
strings.write_string(&exe_builder, "./")
strings.write_string(&exe_builder, executable_name)

exe_path = strings.to_cstring(&exe_builder)
exe_path = strings.to_cstring(&exe_builder) or_return
if linux.access(exe_path, linux.X_OK) != .NONE {
return process, .Not_Exist
}
Expand Down Expand Up @@ -594,7 +594,7 @@ _process_state_update_times :: proc(state: ^Process_State) -> (err: Error) {
strings.write_string(&path_builder, "/stat")

stat_buf: []u8
stat_buf, err = _read_entire_pseudo_file(strings.to_cstring(&path_builder), temp_allocator())
stat_buf, err = _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
if err != nil {
return
}
Expand Down
8 changes: 4 additions & 4 deletions core/os/os2/process_posix.odin
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
strings.write_byte(&exe_builder, '/')
strings.write_string(&exe_builder, exe_name)

if exe_fd := posix.open(strings.to_cstring(&exe_builder), {.CLOEXEC, .EXEC}); exe_fd == -1 {
if exe_fd := posix.open(strings.to_cstring(&exe_builder) or_return, {.CLOEXEC, .EXEC}); exe_fd == -1 {
continue
} else {
posix.close(exe_fd)
Expand All @@ -91,7 +91,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {

// "hello/./world" is fine right?

if exe_fd := posix.open(strings.to_cstring(&exe_builder), {.CLOEXEC, .EXEC}); exe_fd == -1 {
if exe_fd := posix.open(strings.to_cstring(&exe_builder) or_return, {.CLOEXEC, .EXEC}); exe_fd == -1 {
err = .Not_Exist
return
} else {
Expand All @@ -102,7 +102,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
strings.builder_reset(&exe_builder)
strings.write_string(&exe_builder, exe_name)

if exe_fd := posix.open(strings.to_cstring(&exe_builder), {.CLOEXEC, .EXEC}); exe_fd == -1 {
if exe_fd := posix.open(strings.to_cstring(&exe_builder) or_return, {.CLOEXEC, .EXEC}); exe_fd == -1 {
err = .Not_Exist
return
} else {
Expand Down Expand Up @@ -181,7 +181,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
if posix.chdir(cwd) != .OK { abort(pipe[WRITE]) }
}

res := posix.execve(strings.to_cstring(&exe_builder), raw_data(cmd), env)
res := posix.execve(strings.to_cstring(&exe_builder) or_return, raw_data(cmd), env)
assert(res == -1)
abort(pipe[WRITE])

Expand Down
25 changes: 24 additions & 1 deletion core/strings/builder.odin
Original file line number Diff line number Diff line change
Expand Up @@ -288,18 +288,41 @@ to_string :: proc(b: Builder) -> (res: string) {
/*
Appends a trailing null byte after the end of the current Builder byte buffer and then casts it to a cstring
NOTE: This procedure will not check if the backing buffer has enough space to include the extra null byte.
Inputs:
- b: A pointer to builder
Returns:
- res: A cstring of the Builder's buffer
*/
to_cstring :: proc(b: ^Builder) -> (res: cstring) {
unsafe_to_cstring :: proc(b: ^Builder) -> (res: cstring) {
append(&b.buf, 0)
pop(&b.buf)
return cstring(raw_data(b.buf))
}
/*
Appends a trailing null byte after the end of the current Builder byte buffer and then casts it to a cstring
Inputs:
- b: A pointer to builder
Returns:
- res: A cstring of the Builder's buffer upon success
- err: An optional allocator error if one occured, `nil` otherwise
*/
to_cstring :: proc(b: ^Builder) -> (res: cstring, err: mem.Allocator_Error) {
n := append(&b.buf, 0) or_return
if n != 1 {
return nil, .Out_Of_Memory
}
pop(&b.buf)
#no_bounds_check {
assert(b.buf[len(b.buf)] == 0)
}
return cstring(raw_data(b.buf)), nil
}
/*
Returns the length of the Builder's buffer, in bytes
Inputs:
Expand Down
43 changes: 43 additions & 0 deletions tests/core/strings/test_core_strings.odin
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package test_core_strings

import "core:mem"
import "core:strings"
import "core:testing"
import "base:runtime"
Expand Down Expand Up @@ -175,3 +176,45 @@ test_substring :: proc(t: ^testing.T) {
testing.expectf(t, sub == tc.sub, "expected %v[%v:%v] to return sub: %v, got: %v", tc.s, tc.start, tc.end, tc.sub, sub)
}
}

@test
test_builder_to_cstring_with_nil_allocator :: proc(t: ^testing.T) {
b := strings.builder_make_none(mem.nil_allocator())

cstr, err := strings.to_cstring(&b)
testing.expect_value(t, cstr, nil)
testing.expect_value(t, err, mem.Allocator_Error.Out_Of_Memory)
}

@test
test_builder_to_cstring :: proc(t: ^testing.T) {
buf: [8]byte
a: mem.Arena
mem.arena_init(&a, buf[:])

b := strings.builder_make_none(mem.arena_allocator(&a))

{
cstr, err := strings.to_cstring(&b)
testing.expectf(t, cstr != nil, "expected cstr to not be nil, got %v", cstr)
testing.expect_value(t, err, nil)
}

n := strings.write_byte(&b, 'a')
testing.expect(t, n == 1)

{
cstr, err := strings.to_cstring(&b)
testing.expectf(t, cstr != nil, "expected cstr to not be nil, got %v", cstr)
testing.expect_value(t, err, nil)
}

n = strings.write_string(&b, "aaaaaaa")
testing.expect(t, n == 7)

{
cstr, err := strings.to_cstring(&b)
testing.expect(t, cstr == nil)
testing.expect(t, err == .Out_Of_Memory)
}
}