diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index d6e88073c..1273c4c81 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -2420,7 +2420,7 @@ buddy_allocator_proc :: proc( // on the old size to work. // // The overhead of this allocator is an extra max(alignment, size_of(Header)) bytes allocated for each allocation, these bytes are -// used to store the size and original pointer. +// used to store the size and alignment. Compat_Allocator :: struct { parent: Allocator, } @@ -2440,51 +2440,87 @@ compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, location := #caller_location) -> (data: []byte, err: Allocator_Error) { - size, old_size := size, old_size - Header :: struct { - size: int, - ptr: rawptr, + size: int, + alignment: int, + } + + @(no_sanitize_address) + get_unpoisoned_header :: #force_inline proc(ptr: rawptr) -> Header { + header := ([^]Header)(ptr)[-1] + a := max(header.alignment, size_of(Header)) + sanitizer.address_unpoison(rawptr(uintptr(ptr)-uintptr(a)), a) + return header } rra := (^Compat_Allocator)(allocator_data) switch mode { case .Alloc, .Alloc_Non_Zeroed: - a := max(alignment, size_of(Header)) - size += a - assert(size >= 0, "overflow") + a := max(alignment, size_of(Header)) + req_size := size + a + assert(req_size >= 0, "overflow") - allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) or_return + allocation := rra.parent.procedure(rra.parent.data, mode, req_size, alignment, old_memory, old_size, location) or_return #no_bounds_check data = allocation[a:] ([^]Header)(raw_data(data))[-1] = { - size = size, - ptr = raw_data(allocation), + size = size, + alignment = alignment, } + + sanitizer.address_poison(raw_data(allocation), a) return case .Free: - header := ([^]Header)(old_memory)[-1] - return rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location) + header := get_unpoisoned_header(old_memory) + a := max(header.alignment, size_of(Header)) + orig_ptr := rawptr(uintptr(old_memory)-uintptr(a)) + orig_size := header.size + a + + return rra.parent.procedure(rra.parent.data, mode, orig_size, header.alignment, orig_ptr, orig_size, location) case .Resize, .Resize_Non_Zeroed: - header := ([^]Header)(old_memory)[-1] + header := get_unpoisoned_header(old_memory) + orig_a := max(header.alignment, size_of(Header)) + orig_ptr := rawptr(uintptr(old_memory)-uintptr(orig_a)) + orig_size := header.size + orig_a - a := max(alignment, size_of(header)) - size += a + new_alignment := max(header.alignment, alignment) + + a := max(new_alignment, size_of(header)) + req_size := size + a assert(size >= 0, "overflow") - allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location) or_return + allocation := rra.parent.procedure(rra.parent.data, mode, req_size, new_alignment, orig_ptr, orig_size, location) or_return #no_bounds_check data = allocation[a:] ([^]Header)(raw_data(data))[-1] = { - size = size, - ptr = raw_data(allocation), + size = size, + alignment = new_alignment, + } + + sanitizer.address_poison(raw_data(allocation), a) + return + + case .Free_All: + return rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) + + case .Query_Info: + info := (^Allocator_Query_Info)(old_memory) + if info != nil && info.pointer != nil { + header := get_unpoisoned_header(info.pointer) + info.size = header.size + info.alignment = header.alignment } return - case .Free_All, .Query_Info, .Query_Features: - return rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) + case .Query_Features: + data, err = rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) + if err != nil { + set := (^Allocator_Mode_Set)(old_memory) + set^ += {.Query_Info} + } + return case: unreachable() } diff --git a/core/net/dns.odin b/core/net/dns.odin index 7eb543db3..a54242549 100644 --- a/core/net/dns.odin +++ b/core/net/dns.odin @@ -49,8 +49,8 @@ init_dns_configuration :: proc() { /* Resolve %ENVIRONMENT% placeholders in their paths. */ - dns_configuration.resolv_conf, _ = replace_environment_path(dns_configuration.resolv_conf) - dns_configuration.hosts_file, _ = replace_environment_path(dns_configuration.hosts_file) + dns_configuration.resolv_conf = os.replace_environment_placeholders(dns_configuration.resolv_conf) + dns_configuration.hosts_file = os.replace_environment_placeholders(dns_configuration.hosts_file) } @(fini, private) @@ -63,28 +63,6 @@ destroy_dns_configuration :: proc() { dns_configuration := DEFAULT_DNS_CONFIGURATION -// Always allocates for consistency. -replace_environment_path :: proc(path: string, allocator := context.allocator) -> (res: string, ok: bool) { - // Nothing to replace. Return a clone of the original. - if strings.count(path, "%") != 2 { - return strings.clone(path, allocator), true - } - - left := strings.index(path, "%") + 1 - assert(left > 0 && left <= len(path)) // should be covered by there being two % - - right := strings.index(path[left:], "%") + 1 - assert(right > 0 && right <= len(path)) // should be covered by there being two % - - env_key := path[left: right] - env_val := os.get_env(env_key, allocator) - defer delete(env_val) - - res, _ = strings.replace(path, path[left - 1: right + 1], env_val, 1, allocator) - return res, true -} - - /* Resolves a hostname to exactly one IP4 and IP6 endpoint. It's then up to you which one you use. diff --git a/core/os/os.odin b/core/os/os.odin index fde48fbf4..fe08edff4 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -4,6 +4,7 @@ import "base:intrinsics" import "base:runtime" import "core:io" import "core:strconv" +import "core:strings" import "core:unicode/utf8" @@ -210,3 +211,55 @@ heap_free :: runtime.heap_free processor_core_count :: proc() -> int { return _processor_core_count() } + +// Always allocates for consistency. +replace_environment_placeholders :: proc(path: string, allocator := context.allocator) -> (res: string) { + path := path + + sb: strings.Builder + strings.builder_init_none(&sb, allocator) + for len(path) > 0 { + switch path[0] { + case '%': // Windows + when ODIN_OS == .Windows { + for r, i in path[1:] { + if r == '%' { + env_key := path[1:i+1] + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[i+1:] // % is part of key, so skip 1 character extra + } + } + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case '$': // Posix + when ODIN_OS != .Windows { + env_key := "" + dollar_loop: for r, i in path[1:] { + switch r { + case 'A'..='Z', 'a'..='z', '0'..='9', '_': // Part of key ident + case: + env_key = path[1:i+1] + break dollar_loop + } + } + if len(env_key) > 0 { + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[len(env_key):] + } + + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case: + strings.write_rune(&sb, rune(path[0])) + } + + path = path[1:] + } + return strings.to_string(sb) +} \ No newline at end of file diff --git a/core/os/os2/env.odin b/core/os/os2/env.odin index 13c107f3c..7d42b040d 100644 --- a/core/os/os2/env.odin +++ b/core/os/os2/env.odin @@ -1,6 +1,7 @@ package os2 import "base:runtime" +import "core:strings" // get_env retrieves the value of the environment variable named by the key // It returns the value, which will be empty if the variable is not present @@ -45,4 +46,55 @@ environ :: proc(allocator: runtime.Allocator) -> ([]string, Error) { return _environ(allocator) } +// Always allocates for consistency. +replace_environment_placeholders :: proc(path: string, allocator: runtime.Allocator) -> (res: string) { + path := path + sb: strings.Builder + strings.builder_init_none(&sb, allocator) + + for len(path) > 0 { + switch path[0] { + case '%': // Windows + when ODIN_OS == .Windows { + for r, i in path[1:] { + if r == '%' { + env_key := path[1:i+1] + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[i+1:] // % is part of key, so skip 1 character extra + } + } + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case '$': // Posix + when ODIN_OS != .Windows { + env_key := "" + dollar_loop: for r, i in path[1:] { + switch r { + case 'A'..='Z', 'a'..='z', '0'..='9', '_': // Part of key ident + case: + env_key = path[1:i+1] + break dollar_loop + } + } + if len(env_key) > 0 { + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[len(env_key):] + } + + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case: + strings.write_rune(&sb, rune(path[0])) + } + + path = path[1:] + } + return strings.to_string(sb) +} \ No newline at end of file diff --git a/core/os/os2/user_posix.odin b/core/os/os2/user_posix.odin index f271b8913..691745b7a 100644 --- a/core/os/os2/user_posix.odin +++ b/core/os/os2/user_posix.odin @@ -4,7 +4,6 @@ package os2 import "base:runtime" import "core:encoding/ini" import "core:strings" -import "core:sys/posix" _user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { #partial switch ODIN_OS { @@ -169,14 +168,7 @@ _xdg_user_dirs_lookup :: proc(xdg_key: string, allocator: runtime.Allocator) -> for k, v in ini.iterate(&it) { if k == xdg_key { - we: posix.wordexp_t - defer posix.wordfree(&we) - - if _err := posix.wordexp(strings.clone_to_cstring(v, temp_allocator), &we, nil); _err != nil || we.we_wordc != 1 { - return "", .Wordexp_Failed - } - - return strings.clone_from_cstring(we.we_wordv[0], allocator) + return replace_environment_placeholders(v, allocator), nil } } return diff --git a/core/os/os_js.odin b/core/os/os_js.odin index 4d02eef7c..adb0f8061 100644 --- a/core/os/os_js.odin +++ b/core/os/os_js.odin @@ -252,4 +252,9 @@ current_thread_id :: proc "contextless" () -> int { lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { return "", false +} + +get_env :: proc(key: string, allocator := context.allocator) -> string { + value, _ := lookup_env(key, allocator) + return value } \ No newline at end of file diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 28f470357..a0938e860 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -239,3 +239,12 @@ exit :: proc "contextless" (code: int) -> ! { runtime._cleanup_runtime_contextless() wasi.proc_exit(wasi.exitcode_t(code)) } + +lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + return "", false +} + +get_env :: proc(key: string, allocator := context.allocator) -> string { + value, _ := lookup_env(key, allocator) + return value +} \ No newline at end of file diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index 7dc49bcd1..dd7f0fa03 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -34,6 +34,7 @@ init_platform :: proc() { } else { os_version.platform = .MacOS switch version.majorVersion { + case 26: ws(&b, "macOS Tahoe") case 15: ws(&b, "macOS Sequoia") case 14: ws(&b, "macOS Sonoma") case 13: ws(&b, "macOS Ventura") diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 32210c23e..98a376895 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -540,6 +540,7 @@ gb_internal void report_os_info() { } switch (major) { + case 26: gb_printf("macOS Tahoe"); break; case 15: gb_printf("macOS Sequoia"); break; case 14: gb_printf("macOS Sonoma"); break; case 13: gb_printf("macOS Ventura"); break; diff --git a/src/types.cpp b/src/types.cpp index ce921796d..c7573173c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1203,6 +1203,7 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) { } gb_internal bool is_type_named(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return true; } @@ -1212,6 +1213,7 @@ gb_internal bool is_type_named(Type *t) { gb_internal bool is_type_boolean(Type *t) { // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Boolean) != 0; } @@ -1220,6 +1222,7 @@ gb_internal bool is_type_boolean(Type *t) { gb_internal bool is_type_integer(Type *t) { // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Integer) != 0; } @@ -1241,15 +1244,15 @@ gb_internal bool is_type_integer_like(Type *t) { gb_internal bool is_type_unsigned(Type *t) { t = base_type(t); - // t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Unsigned) != 0; } return false; } gb_internal bool is_type_integer_128bit(Type *t) { - // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Integer) != 0 && t->Basic.size == 16; } @@ -1258,6 +1261,7 @@ gb_internal bool is_type_integer_128bit(Type *t) { gb_internal bool is_type_rune(Type *t) { // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Rune) != 0; } @@ -1266,6 +1270,7 @@ gb_internal bool is_type_rune(Type *t) { gb_internal bool is_type_numeric(Type *t) { // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Numeric) != 0; } else if (t->kind == Type_Enum) { @@ -1279,6 +1284,7 @@ gb_internal bool is_type_numeric(Type *t) { } gb_internal bool is_type_string(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_String) != 0; } @@ -1286,6 +1292,7 @@ gb_internal bool is_type_string(Type *t) { } gb_internal bool is_type_cstring(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return t->Basic.kind == Basic_cstring; } @@ -1293,9 +1300,7 @@ gb_internal bool is_type_cstring(Type *t) { } gb_internal bool is_type_typed(Type *t) { t = base_type(t); - if (t == nullptr) { - return false; - } + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Untyped) == 0; } @@ -1303,9 +1308,7 @@ gb_internal bool is_type_typed(Type *t) { } gb_internal bool is_type_untyped(Type *t) { t = base_type(t); - if (t == nullptr) { - return false; - } + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Untyped) != 0; } @@ -1313,6 +1316,7 @@ gb_internal bool is_type_untyped(Type *t) { } gb_internal bool is_type_ordered(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } switch (t->kind) { case Type_Basic: return (t->Basic.flags & BasicFlag_Ordered) != 0; @@ -1325,6 +1329,7 @@ gb_internal bool is_type_ordered(Type *t) { } gb_internal bool is_type_ordered_numeric(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } switch (t->kind) { case Type_Basic: return (t->Basic.flags & BasicFlag_OrderedNumeric) != 0; @@ -1333,6 +1338,7 @@ gb_internal bool is_type_ordered_numeric(Type *t) { } gb_internal bool is_type_constant_type(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_ConstantType) != 0; } @@ -1346,6 +1352,7 @@ gb_internal bool is_type_constant_type(Type *t) { } gb_internal bool is_type_float(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Float) != 0; } @@ -1353,6 +1360,7 @@ gb_internal bool is_type_float(Type *t) { } gb_internal bool is_type_complex(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Complex) != 0; } @@ -1360,6 +1368,7 @@ gb_internal bool is_type_complex(Type *t) { } gb_internal bool is_type_quaternion(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Quaternion) != 0; } @@ -1367,6 +1376,7 @@ gb_internal bool is_type_quaternion(Type *t) { } gb_internal bool is_type_complex_or_quaternion(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & (BasicFlag_Complex|BasicFlag_Quaternion)) != 0; } @@ -1374,6 +1384,7 @@ gb_internal bool is_type_complex_or_quaternion(Type *t) { } gb_internal bool is_type_pointer(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Pointer) != 0; } @@ -1381,10 +1392,12 @@ gb_internal bool is_type_pointer(Type *t) { } gb_internal bool is_type_soa_pointer(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_SoaPointer; } gb_internal bool is_type_multi_pointer(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_MultiPointer; } gb_internal bool is_type_internally_pointer_like(Type *t) { @@ -1393,6 +1406,7 @@ gb_internal bool is_type_internally_pointer_like(Type *t) { gb_internal bool is_type_tuple(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Tuple; } gb_internal bool is_type_uintptr(Type *t) { @@ -1415,14 +1429,17 @@ gb_internal bool is_type_u8(Type *t) { } gb_internal bool is_type_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Array; } gb_internal bool is_type_enumerated_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_EnumeratedArray; } gb_internal bool is_type_matrix(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Matrix; } @@ -1566,22 +1583,27 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) { gb_internal bool is_type_dynamic_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_DynamicArray; } gb_internal bool is_type_slice(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Slice; } gb_internal bool is_type_proc(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Proc; } gb_internal bool is_type_asm_proc(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Proc && t->Proc.calling_convention == ProcCC_InlineAsm; } gb_internal bool is_type_simd_vector(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_SimdVector; } @@ -1621,11 +1643,13 @@ gb_internal Type *base_any_array_type(Type *t) { gb_internal bool is_type_generic(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Generic; } gb_internal bool is_type_u8_slice(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Slice) { return is_type_u8(t->Slice.elem); } @@ -1633,6 +1657,7 @@ gb_internal bool is_type_u8_slice(Type *t) { } gb_internal bool is_type_u8_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Array) { return is_type_u8(t->Array.elem); } @@ -1640,6 +1665,7 @@ gb_internal bool is_type_u8_array(Type *t) { } gb_internal bool is_type_u8_ptr(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Pointer) { return is_type_u8(t->Slice.elem); } @@ -1647,6 +1673,7 @@ gb_internal bool is_type_u8_ptr(Type *t) { } gb_internal bool is_type_u8_multi_ptr(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_MultiPointer) { return is_type_u8(t->Slice.elem); } @@ -1654,6 +1681,7 @@ gb_internal bool is_type_u8_multi_ptr(Type *t) { } gb_internal bool is_type_rune_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Array) { return is_type_rune(t->Array.elem); } @@ -1979,7 +2007,13 @@ gb_internal bool is_type_untyped_uninit(Type *t) { } gb_internal bool is_type_empty_union(Type *t) { + if (t == nullptr) { + return false; + } t = base_type(t); + if (t == nullptr) { + return false; + } return t->kind == Type_Union && t->Union.variants.count == 0; } @@ -2668,7 +2702,7 @@ gb_internal bool are_types_identical(Type *x, Type *y) { y = y->Named.base; } } - if (x->kind != y->kind) { + if (x == nullptr || y == nullptr || x->kind != y->kind) { return false; }