Bläddra i källkod

Add `runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD` where appropriate

gingerBill 2 år sedan
förälder
incheckning
986cba584e

+ 2 - 0
core/compress/common.odin

@@ -212,6 +212,8 @@ read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int
 
 @(optimization_mode="speed")
 read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) {
+	// TODO: REMOVE ALL USE OF context.temp_allocator here
+	// the is literally no need for it
 	b := make([]u8, size, context.temp_allocator)
 	_, e := z.input->impl_read(b[:])
 	if e == .None {

+ 3 - 0
core/dynlib/lib_windows.odin

@@ -4,10 +4,12 @@ package dynlib
 
 import win32 "core:sys/windows"
 import "core:strings"
+import "core:runtime"
 
 _load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
 	// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	wide_path := win32.utf8_to_wstring(path, context.temp_allocator)
 	handle := cast(Library)win32.LoadLibraryW(wide_path)
 	return handle, handle != nil
@@ -19,6 +21,7 @@ _unload_library :: proc(library: Library) -> bool {
 }
 
 _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	c_str := strings.clone_to_cstring(symbol, context.temp_allocator)
 	ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str)
 	found = ptr != nil

+ 2 - 0
core/encoding/json/unmarshal.odin

@@ -346,6 +346,8 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
 			
 			fields := reflect.struct_fields_zipped(ti.id)
 			
+			runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
+
 			field_used := make([]bool, len(fields), context.temp_allocator)
 			
 			use_field_idx := -1

+ 3 - 1
core/encoding/xml/xml_reader.odin

@@ -33,6 +33,7 @@ import "core:intrinsics"
 import "core:mem"
 import "core:os"
 import "core:strings"
+import "core:runtime"
 
 likely :: intrinsics.expect
 
@@ -408,7 +409,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
 				next := scan(t)
 				#partial switch next.kind {
 				case .Ident:
-					if len(next.text) == 3 && strings.to_lower(next.text, context.temp_allocator) == "xml" {
+					if len(next.text) == 3 && strings.equal_fold(next.text, "xml") {
 						parse_prologue(doc) or_return
 					} else if len(doc.prologue) > 0 {
 						/*
@@ -614,6 +615,7 @@ parse_prologue :: proc(doc: ^Document) -> (err: Error) {
 			}
 
 		case "encoding":
+			runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 			switch strings.to_lower(attr.val, context.temp_allocator) {
 			case "utf-8", "utf8":
 				doc.encoding = .UTF_8

+ 3 - 0
core/image/netpbm/netpbm.odin

@@ -8,6 +8,7 @@ import "core:os"
 import "core:strconv"
 import "core:strings"
 import "core:unicode"
+import "core:runtime"
 
 Image        :: image.Image
 Format       :: image.Netpbm_Format
@@ -407,6 +408,8 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head
 	}
 	length = header_end_index + len(HEADER_END)
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
+
 	// string buffer for the tupltype
 	tupltype: strings.Builder
 	strings.builder_init(&tupltype, context.temp_allocator); defer strings.builder_destroy(&tupltype)

+ 17 - 14
core/image/png/helpers.odin

@@ -16,6 +16,7 @@ import coretime "core:time"
 import "core:strings"
 import "core:bytes"
 import "core:mem"
+import "core:runtime"
 
 /*
 	Cleanup of image-specific data.
@@ -91,6 +92,8 @@ core_time :: proc(c: image.PNG_Chunk) -> (t: coretime.Time, ok: bool) {
 }
 
 text :: proc(c: image.PNG_Chunk) -> (res: Text, ok: bool) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
+
 	assert(len(c.data) == int(c.header.length))
 	#partial switch c.header.type {
 	case .tEXt:
@@ -194,18 +197,18 @@ text_destroy :: proc(text: Text) {
 }
 
 iccp :: proc(c: image.PNG_Chunk) -> (res: iCCP, ok: bool) {
-	ok = true
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 
 	fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator)
 
 	if len(fields[0]) < 1 || len(fields[0]) > 79 {
 		// Invalid profile name
-		ok = false; return
+		return
 	}
 
 	if len(fields[1]) != 0 {
 		// Compression method should be a zero, which the split turned into an empty slice.
-		ok = false; return
+		return
 	}
 
 	// Set up ZLIB context and decompress iCCP payload
@@ -213,12 +216,12 @@ iccp :: proc(c: image.PNG_Chunk) -> (res: iCCP, ok: bool) {
 	zlib_error := zlib.inflate_from_byte_array(fields[2], &buf)
 	if zlib_error != nil {
 		bytes.buffer_destroy(&buf)
-		ok = false; return
+		return
 	}
 
 	res.name = strings.clone(string(fields[0]))
 	res.profile = bytes.buffer_to_bytes(&buf)
-
+	ok = true
 	return
 }
 
@@ -256,18 +259,18 @@ plte :: proc(c: image.PNG_Chunk) -> (res: PLTE, ok: bool) {
 
 splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) {
 	if c.header.type != .sPLT {
-		return {}, false
+		return
 	}
-	ok = true
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 
 	fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=2, allocator=context.temp_allocator)
 	if len(fields) != 2 {
-		return {}, false
+		return
 	}
 
 	res.depth = fields[1][0]
 	if res.depth != 8 && res.depth != 16 {
-		return {}, false
+		return
 	}
 
 	data := fields[1][1:]
@@ -275,21 +278,21 @@ splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) {
 
 	if res.depth == 8 {
 		if len(data) % 6 != 0 {
-			return {}, false
+			return
 		}
 		count = len(data) / 6
 		if count > 256 {
-			return {}, false
+			return
 		}
 
 		res.entries = mem.slice_data_cast([][4]u8, data)
 	} else { // res.depth == 16
 		if len(data) % 10 != 0 {
-			return {}, false
+			return
 		}
 		count = len(data) / 10
 		if count > 256 {
-			return {}, false
+			return
 		}
 
 		res.entries = mem.slice_data_cast([][4]u16, data)
@@ -297,7 +300,7 @@ splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) {
 
 	res.name = strings.clone(string(fields[0]))
 	res.used = u16(count)
-
+	ok = true
 	return
 }
 

+ 11 - 7
core/image/png/png.odin

@@ -23,6 +23,7 @@ import "core:bytes"
 import "core:io"
 import "core:mem"
 import "core:intrinsics"
+import "core:runtime"
 
 // Limit chunk sizes.
 // By default: IDAT = 8k x 8k x 16-bits + 8k filter bytes.
@@ -1247,6 +1248,8 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
 
 	// TODO: See about doing a Duff's #unroll where practicable
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
 	// Apron so we don't need to special case first rows.
 	up := make([]u8, row_stride, context.temp_allocator)
 	ok = true
@@ -1299,10 +1302,9 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
 }
 
 // @(optimization_mode="speed")
-defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_check {
+defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check {
 
 	using params
-	ok = true
 
 	row_stride_in  := ((channels * width * depth) + 7) >> 3
 	row_stride_out := channels * width
@@ -1314,6 +1316,8 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_ch
 
 	// TODO: See about doing a Duff's #unroll where practicable
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
 	// Apron so we don't need to special case first rows.
 	up := make([]u8, row_stride_out, context.temp_allocator)
 
@@ -1457,18 +1461,18 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_ch
 		}
 	}
 
-	return
+	return true
 }
 
 // @(optimization_mode="speed")
-defilter_16 :: proc(params: ^Filter_Params) -> (ok: bool) {
-
+defilter_16 :: proc(params: ^Filter_Params) -> bool {
 	using params
-	ok = true
 
 	stride := channels * 2
 	row_stride := width * stride
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
 	// TODO: See about doing a Duff's #unroll where practicable
 	// Apron so we don't need to special case first rows.
 	up := make([]u8, row_stride, context.temp_allocator)
@@ -1518,7 +1522,7 @@ defilter_16 :: proc(params: ^Filter_Params) -> (ok: bool) {
 		dest    = dest[row_stride:]
 	}
 
-	return
+	return true
 }
 
 defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IHDR, options: Options) -> (err: Error) {

+ 1 - 0
core/os/dir_darwin.odin

@@ -2,6 +2,7 @@ package os
 
 import "core:strings"
 import "core:mem"
+import "core:runtime"
 
 read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
 	dirp: Dir

+ 2 - 1
core/os/dir_freebsd.odin

@@ -1,6 +1,7 @@
 package os
 
 import "core:mem"
+import "core:runtime"
 
 read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
 	dirp: Dir
@@ -50,7 +51,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
 			continue
 		}
 
-		fullpath := make([]byte, len(dirpath)+1+len(filename))
+		fullpath := make([]byte, len(dirpath)+1+len(filename), context.temp_allocator)
 		copy(fullpath, dirpath)
 		copy(fullpath[len(dirpath):], "/")
 		copy(fullpath[len(dirpath)+1:], filename)

+ 2 - 0
core/os/dir_linux.odin

@@ -2,6 +2,7 @@ package os
 
 import "core:strings"
 import "core:mem"
+import "core:runtime"
 
 read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
 	dirp: Dir
@@ -51,6 +52,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
 			continue
 		}
 
+		runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 		fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
 		defer delete(fullpath, context.temp_allocator)
 

+ 6 - 2
core/os/dir_windows.odin

@@ -2,6 +2,7 @@ package os
 
 import win32 "core:sys/windows"
 import "core:strings"
+import "core:runtime"
 
 read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
 	find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
@@ -65,13 +66,16 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
 		n = -1
 		size = 100
 	}
-	dfi := make([dynamic]File_Info, 0, size)
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 
 	wpath: []u16
-	wpath, err = cleanpath_from_handle_u16(fd)
+	wpath, err = cleanpath_from_handle_u16(fd, context.temp_allocator)
 	if len(wpath) == 0 || err != ERROR_NONE {
 		return
 	}
+
+	dfi := make([dynamic]File_Info, 0, size)
+
 	wpath_search := make([]u16, len(wpath)+3, context.temp_allocator)
 	copy(wpath_search, wpath)
 	wpath_search[len(wpath)+0] = '\\'

+ 4 - 0
core/os/env_windows.odin

@@ -1,6 +1,7 @@
 package os
 
 import win32 "core:sys/windows"
+import "core:runtime"
 
 // lookup_env gets the value of the environment variable named by the key
 // If the variable is found in the environment the value (which can be empty) is returned and the boolean is true
@@ -18,6 +19,8 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
 			return "", false
 		}
 	}
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
+
 	b := make([dynamic]u16, n, context.temp_allocator)
 	n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
 	if n == 0 {
@@ -87,6 +90,7 @@ environ :: proc(allocator := context.allocator) -> []string {
 
 // clear_env deletes all environment variables
 clear_env :: proc() {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	envs := environ(context.temp_allocator)
 	for env in envs {
 		for j in 1..<len(env) {

+ 12 - 0
core/os/file_windows.odin

@@ -2,6 +2,7 @@ package os
 
 import win32 "core:sys/windows"
 import "core:intrinsics"
+import "core:runtime"
 import "core:unicode/utf16"
 
 is_path_separator :: proc(c: byte) -> bool {
@@ -327,6 +328,7 @@ get_std_handle :: proc "contextless" (h: uint) -> Handle {
 
 
 exists :: proc(path: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
 	attribs := win32.GetFileAttributesW(wpath)
 
@@ -334,6 +336,7 @@ exists :: proc(path: string) -> bool {
 }
 
 is_file :: proc(path: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
 	attribs := win32.GetFileAttributesW(wpath)
 
@@ -344,6 +347,7 @@ is_file :: proc(path: string) -> bool {
 }
 
 is_dir :: proc(path: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
 	attribs := win32.GetFileAttributesW(wpath)
 
@@ -359,6 +363,8 @@ is_dir :: proc(path: string) -> bool {
 get_current_directory :: proc(allocator := context.allocator) -> string {
 	win32.AcquireSRWLockExclusive(&cwd_lock)
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
+
 	sz_utf16 := win32.GetCurrentDirectoryW(0, nil)
 	dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator) // the first time, it _includes_ the NUL.
 
@@ -387,6 +393,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
 
 
 change_directory :: proc(path: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
 
 	if !win32.SetCurrentDirectoryW(wpath) {
@@ -396,6 +403,7 @@ change_directory :: proc(path: string) -> (err: Errno) {
 }
 
 make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	// Mode is unused on Windows, but is needed on *nix
 	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
 
@@ -407,6 +415,7 @@ make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) {
 
 
 remove_directory :: proc(path: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
 
 	if !win32.RemoveDirectoryW(wpath) {
@@ -479,12 +488,14 @@ fix_long_path :: proc(path: string) -> string {
 
 
 link :: proc(old_name, new_name: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	n := win32.utf8_to_wstring(fix_long_path(new_name))
 	o := win32.utf8_to_wstring(fix_long_path(old_name))
 	return Errno(win32.CreateHardLinkW(n, o, nil))
 }
 
 unlink :: proc(path: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
 
 	if !win32.DeleteFileW(wpath) {
@@ -496,6 +507,7 @@ unlink :: proc(path: string) -> (err: Errno) {
 
 
 rename :: proc(old_path, new_path: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	from := win32.utf8_to_wstring(old_path, context.temp_allocator)
 	to := win32.utf8_to_wstring(new_path, context.temp_allocator)
 

+ 5 - 12
core/os/os2/file_linux.odin

@@ -39,10 +39,8 @@ _file_allocator :: proc() -> runtime.Allocator {
 }
 
 _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) {
-	name_cstr, allocated := _name_to_cstring(name)
-	defer if allocated {
-		delete(name_cstr)
-	}
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+	name_cstr := _name_to_cstring(name)
 
 	flags_i: int
 	switch flags & O_RDONLY|O_WRONLY|O_RDWR {
@@ -411,12 +409,7 @@ _is_dir_fd :: proc(fd: int) -> bool {
 // defined as 512, however, it is well known that paths can exceed that limit.
 // So, in theory you could have a path larger than the entire temp_allocator's
 // buffer. Therefor, any large paths will use context.allocator.
-_name_to_cstring :: proc(name: string) -> (cname: cstring, allocated: bool) {
-	if len(name) > _CSTRING_NAME_HEAP_THRESHOLD {
-		cname = strings.clone_to_cstring(name)
-		allocated = true
-		return
-	}
-	cname = strings.clone_to_cstring(name, context.temp_allocator)
-	return
+@(private="file")
+_temp_name_to_cstring :: proc(name: string) -> (cname: cstring) {
+	return strings.clone_to_cstring(name, context.temp_allocator)
 }

+ 14 - 0
core/os/os_darwin.odin

@@ -353,6 +353,7 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno
 		flags = O_RDONLY
 	}
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	handle := _unix_open(cstr, i32(flags), u16(mode))
 	if handle == -1 {
@@ -508,24 +509,28 @@ is_file :: proc {is_file_path, is_file_handle}
 is_dir :: proc {is_dir_path, is_dir_handle}
 
 exists :: proc(path: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_access(cpath, O_RDONLY)
 	return res == 0
 }
 
 rename :: proc(old: string, new: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	old_cstr := strings.clone_to_cstring(old, context.temp_allocator)
 	new_cstr := strings.clone_to_cstring(new, context.temp_allocator)
 	return _unix_rename(old_cstr, new_cstr) != -1
 }
 
 remove :: proc(path: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	return _unix_remove(path_cstr) != -1
 }
 
 @private
 _stat :: proc(path: string) -> (OS_Stat, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	s: OS_Stat
@@ -538,6 +543,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
 
 @private
 _lstat :: proc(path: string) -> (OS_Stat, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	s: OS_Stat
@@ -603,6 +609,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
 
 @private
 _readlink :: proc(path: string) -> (string, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	bufsz : uint = 256
@@ -640,6 +647,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 		rel = "."
 	}
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 	rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
 
 	path_ptr := _unix_realpath(rel_cstr, nil)
@@ -655,6 +663,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 }
 
 access :: proc(path: string, mask: int) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	return _unix_access(cstr, mask) == 0
 }
@@ -679,6 +688,7 @@ heap_free :: proc(ptr: rawptr) {
 }
 
 lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 	path_str := strings.clone_to_cstring(key, context.temp_allocator)
 	cstr := _unix_getenv(path_str)
 	if cstr == nil {
@@ -710,6 +720,7 @@ get_current_directory :: proc() -> string {
 }
 
 set_current_directory :: proc(path: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_chdir(cstr)
 	if res == -1 {
@@ -719,6 +730,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
 }
 
 make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_mkdir(path_cstr, mode)
 	if res == -1 {
@@ -743,12 +755,14 @@ current_thread_id :: proc "contextless" () -> int {
 }
 
 dlopen :: proc(filename: string, flags: int) -> rawptr {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(filename, context.temp_allocator)
 	handle := _unix_dlopen(cstr, flags)
 	return handle
 }
 dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
 	assert(handle != nil)
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
 	proc_handle := _unix_dlsym(handle, cstr)
 	return proc_handle

+ 17 - 0
core/os/os_freebsd.odin

@@ -309,6 +309,7 @@ get_last_error :: proc "contextless" () -> int {
 }
 
 open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	handle := _unix_open(cstr, c.int(flags), c.int(mode))
 	if handle == -1 {
@@ -361,6 +362,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
 }
 
 rename :: proc(old_path, new_path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
 	new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
 	res := _unix_rename(old_path_cstr, new_path_cstr)
@@ -371,6 +373,7 @@ rename :: proc(old_path, new_path: string) -> Errno {
 }
 
 remove :: proc(path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_unlink(path_cstr)
 	if res == -1 {
@@ -380,6 +383,7 @@ remove :: proc(path: string) -> Errno {
 }
 
 make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_mkdir(path_cstr, mode)
 	if res == -1 {
@@ -389,6 +393,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
 }
 
 remove_directory :: proc(path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_rmdir(path_cstr)
 	if res == -1 {
@@ -474,6 +479,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
 
 @private
 _stat :: proc(path: string) -> (OS_Stat, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	s: OS_Stat = ---
 	result := _unix_lstat(cstr, &s)
@@ -485,6 +491,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
 
 @private
 _lstat :: proc(path: string) -> (OS_Stat, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	
 	// deliberately uninitialized
@@ -550,6 +557,8 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
 
 @private
 _readlink :: proc(path: string) -> (string, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
+
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	bufsz : uint = MAX_PATH
@@ -580,6 +589,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 	if rel == "" {
 		rel = "."
 	}
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 
 	rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
 
@@ -596,6 +606,8 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 }
 
 access :: proc(path: string, mask: int) -> (bool, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	result := _unix_access(cstr, c.int(mask))
 	if result == -1 {
@@ -626,6 +638,8 @@ heap_free :: proc(ptr: rawptr) {
 }
 
 lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
+
 	path_str := strings.clone_to_cstring(key, context.temp_allocator)
 	cstr := _unix_getenv(path_str)
 	if cstr == nil {
@@ -660,6 +674,7 @@ get_current_directory :: proc() -> string {
 }
 
 set_current_directory :: proc(path: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_chdir(cstr)
 	if res == -1 do return Errno(get_last_error())
@@ -676,12 +691,14 @@ current_thread_id :: proc "contextless" () -> int {
 }
 
 dlopen :: proc(filename: string, flags: int) -> rawptr {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(filename, context.temp_allocator)
 	handle := _unix_dlopen(cstr, c.int(flags))
 	return handle
 }
 dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
 	assert(handle != nil)
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
 	proc_handle := _unix_dlsym(handle, cstr)
 	return proc_handle

+ 17 - 0
core/os/os_linux.odin

@@ -463,6 +463,7 @@ fork :: proc() -> (Pid, Errno) {
 }
 
 open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	handle := _unix_open(cstr, flags, mode)
 	if handle < 0 {
@@ -513,22 +514,26 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
 }
 
 rename :: proc(old_path, new_path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
 	new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
 	return _get_errno(_unix_rename(old_path_cstr, new_path_cstr))
 }
 
 remove :: proc(path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	return _get_errno(_unix_unlink(path_cstr))
 }
 
 make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	return _get_errno(_unix_mkdir(path_cstr, mode))
 }
 
 remove_directory :: proc(path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	return _get_errno(_unix_rmdir(path_cstr))
 }
@@ -582,6 +587,7 @@ is_file :: proc {is_file_path, is_file_handle}
 is_dir :: proc {is_dir_path, is_dir_handle}
 
 exists :: proc(path: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_access(cpath, O_RDONLY)
 	return res == 0
@@ -617,6 +623,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
 
 @private
 _stat :: proc(path: string) -> (OS_Stat, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	// deliberately uninitialized; the syscall fills this buffer for us
@@ -630,6 +637,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
 
 @private
 _lstat :: proc(path: string) -> (OS_Stat, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	// deliberately uninitialized; the syscall fills this buffer for us
@@ -697,6 +705,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
 
 @private
 _readlink :: proc(path: string) -> (string, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	bufsz : uint = 256
@@ -732,6 +741,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 	if rel == "" {
 		rel = "."
 	}
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 
 	rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
 
@@ -748,6 +758,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 }
 
 access :: proc(path: string, mask: int) -> (bool, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	result := _unix_access(cstr, mask)
 	if result < 0 {
@@ -778,6 +789,7 @@ heap_free :: proc(ptr: rawptr) {
 }
 
 lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 	path_str := strings.clone_to_cstring(key, context.temp_allocator)
 	// NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults.
 	cstr := _unix_getenv(path_str)
@@ -793,6 +805,7 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string)
 }
 
 set_env :: proc(key, value: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	s := strings.concatenate({key, "=", value, "\x00"}, context.temp_allocator)
 	res := _unix_putenv(strings.unsafe_string_to_cstring(s))
 	if res < 0 {
@@ -802,6 +815,7 @@ set_env :: proc(key, value: string) -> Errno {
 }
 
 unset_env :: proc(key: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	s := strings.clone_to_cstring(key, context.temp_allocator)
 	res := _unix_putenv(s)
 	if res < 0 {
@@ -832,6 +846,7 @@ get_current_directory :: proc() -> string {
 }
 
 set_current_directory :: proc(path: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_chdir(cstr)
 	if res < 0 {
@@ -850,12 +865,14 @@ current_thread_id :: proc "contextless" () -> int {
 }
 
 dlopen :: proc(filename: string, flags: int) -> rawptr {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(filename, context.temp_allocator)
 	handle := _unix_dlopen(cstr, c.int(flags))
 	return handle
 }
 dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
 	assert(handle != nil)
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
 	proc_handle := _unix_dlsym(handle, cstr)
 	return proc_handle

+ 14 - 0
core/os/os_openbsd.odin

@@ -308,6 +308,7 @@ fork :: proc() -> (Pid, Errno) {
 }
 
 open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	handle := _unix_open(cstr, c.int(flags), c.int(mode))
 	if handle == -1 {
@@ -360,6 +361,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
 }
 
 rename :: proc(old_path, new_path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
 	new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
 	res := _unix_rename(old_path_cstr, new_path_cstr)
@@ -370,6 +372,7 @@ rename :: proc(old_path, new_path: string) -> Errno {
 }
 
 remove :: proc(path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_unlink(path_cstr)
 	if res == -1 {
@@ -379,6 +382,7 @@ remove :: proc(path: string) -> Errno {
 }
 
 make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_mkdir(path_cstr, mode)
 	if res == -1 {
@@ -388,6 +392,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
 }
 
 remove_directory :: proc(path: string) -> Errno {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_rmdir(path_cstr)
 	if res == -1 {
@@ -473,6 +478,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
 
 @private
 _stat :: proc(path: string) -> (OS_Stat, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	// deliberately uninitialized
@@ -486,6 +492,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
 
 @private
 _lstat :: proc(path: string) -> (OS_Stat, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	// deliberately uninitialized
@@ -552,6 +559,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
 
 @private
 _readlink :: proc(path: string) -> (string, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
 
 	bufsz : uint = MAX_PATH
@@ -583,6 +591,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 		rel = "."
 	}
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
 	rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
 
 	path_ptr := _unix_realpath(rel_cstr, nil)
@@ -598,6 +607,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 }
 
 access :: proc(path: string, mask: int) -> (bool, Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_access(cstr, c.int(mask))
 	if res == -1 {
@@ -628,6 +638,7 @@ heap_free :: proc(ptr: rawptr) {
 }
 
 lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 	path_str := strings.clone_to_cstring(key, context.temp_allocator)
 	cstr := _unix_getenv(path_str)
 	if cstr == nil {
@@ -658,6 +669,7 @@ get_current_directory :: proc() -> string {
 }
 
 set_current_directory :: proc(path: string) -> (err: Errno) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
 	res := _unix_chdir(cstr)
 	if res == -1 {
@@ -676,12 +688,14 @@ current_thread_id :: proc "contextless" () -> int {
 }
 
 dlopen :: proc(filename: string, flags: int) -> rawptr {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(filename, context.temp_allocator)
 	handle := _unix_dlopen(cstr, c.int(flags))
 	return handle
 }
 dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
 	assert(handle != nil)
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
 	proc_handle := _unix_dlsym(handle, cstr)
 	return proc_handle

+ 1 - 0
core/os/os_windows.odin

@@ -134,6 +134,7 @@ _processor_core_count :: proc() -> int {
 
 	thread_count := 0
 	if !result && win32.GetLastError() == 122 && length > 0 {
+		runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 		processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator)
 
 		result = win32.GetLogicalProcessorInformation(&processors[0], &length)

+ 7 - 3
core/os/stat_windows.odin

@@ -1,6 +1,7 @@
 package os
 
 import "core:time"
+import "core:runtime"
 import win32 "core:sys/windows"
 
 @(private)
@@ -11,6 +12,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
 	if name == "" {
 		name = "."
 	}
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 	p := win32.utf8_to_utf16(name, context.temp_allocator)
 	buf := make([dynamic]u16, 100)
 	defer delete(buf)
@@ -36,6 +38,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al
 
 	context.allocator = allocator
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 
 	wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator)
 	fa: win32.WIN32_FILE_ATTRIBUTE_DATA
@@ -132,14 +135,15 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
 
 @(private)
 cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) {
-	buf, err := cleanpath_from_handle_u16(fd)
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
+	buf, err := cleanpath_from_handle_u16(fd, context.temp_allocator)
 	if err != 0 {
 		return "", err
 	}
 	return win32.utf16_to_utf8(buf, context.allocator) or_else "", err
 }
 @(private)
-cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
+cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) {
 	if fd == 0 {
 		return nil, ERROR_INVALID_HANDLE
 	}
@@ -149,7 +153,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
 	if n == 0 {
 		return nil, Errno(win32.GetLastError())
 	}
-	buf := make([]u16, max(n, win32.DWORD(260))+1, context.temp_allocator)
+	buf := make([]u16, max(n, win32.DWORD(260))+1, allocator)
 	buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0)
 	return buf[:buf_len], ERROR_NONE
 }

+ 2 - 0
core/path/filepath/path_unix.odin

@@ -7,6 +7,7 @@ when ODIN_OS == .Darwin {
 	foreign import libc "system:c"
 }
 
+import "core:runtime"
 import "core:strings"
 
 SEPARATOR :: '/'
@@ -41,6 +42,7 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
 join :: proc(elems: []string, allocator := context.allocator) -> string {
 	for e, i in elems {
 		if e != "" {
+			runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 			p := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator)
 			return clean(p, allocator)
 		}

+ 15 - 12
core/path/filepath/path_windows.odin

@@ -1,6 +1,7 @@
 package filepath
 
 import "core:strings"
+import "core:runtime"
 import "core:os"
 import win32 "core:sys/windows"
 
@@ -60,25 +61,25 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Errno) {
 	}
 
 	p := win32.utf8_to_utf16(name, ta)
-	buf := make([dynamic]u16, 100, ta)
-	for {
-		n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
-		if n == 0 {
-			delete(buf)
-			return "", os.Errno(win32.GetLastError())
-		}
-		if n <= u32(len(buf)) {
-			return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE
-		}
-		resize(&buf, len(buf)*2)
+	n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
+	if n == 0 {
+		return "", os.Errno(win32.GetLastError())
 	}
 
-	return
+	buf := make([]u16, n, ta)
+	n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
+	if n == 0 {
+		delete(buf)
+		return "", os.Errno(win32.GetLastError())
+	}
+
+	return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE
 }
 
 
 
 abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
 	full_path, err := temp_full_path(path)
 	if err != 0 {
 		return "", false
@@ -99,6 +100,8 @@ join :: proc(elems: []string, allocator := context.allocator) -> string {
 
 join_non_empty :: proc(elems: []string, allocator := context.allocator) -> string {
 	context.allocator = allocator
+
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
 	
 	if len(elems[0]) == 2 && elems[0][1] == ':' {
 		i := 1

+ 3 - 1
core/path/slashpath/path.odin

@@ -5,6 +5,7 @@
 // To manipulate operating system specific paths, use the path/filepath package
 package slashpath
 
+import "core:runtime"
 import "core:strings"
 
 // is_separator checks whether the byte is a valid separator character
@@ -150,8 +151,9 @@ join :: proc(elems: []string, allocator := context.allocator) -> string {
 	context.allocator = allocator
 	for elem, i in elems {
 		if elem != "" {
+			runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
 			s := strings.join(elems[i:], "/", context.temp_allocator)
-			return clean(s)
+			return clean(s, allocator)
 		}
 	}
 	return ""

+ 9 - 6
core/runtime/default_temporary_allocator.odin

@@ -45,11 +45,10 @@ when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR
 
 	@(require_results)
 	default_temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: Arena_Temp) {
-		if context.temp_allocator.data != &global_default_temp_allocator_data {
-			return
+		if context.temp_allocator.data == &global_default_temp_allocator_data {
+			temp = arena_temp_begin(&global_default_temp_allocator_data.arena, loc)
 		}
-
-		return arena_temp_begin(&global_default_temp_allocator_data.arena, loc)
+		return
 	}
 
 	default_temp_allocator_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
@@ -58,8 +57,12 @@ when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR
 }
 
 @(deferred_out=default_temp_allocator_temp_end)
-DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD :: #force_inline proc(loc := #caller_location) -> (Arena_Temp, Source_Code_Location) {
-	return default_temp_allocator_temp_begin(loc), loc
+DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD :: #force_inline proc(ignore := false, loc := #caller_location) -> (Arena_Temp, Source_Code_Location) {
+	if ignore {
+		return {}, loc
+	} else {
+		return default_temp_allocator_temp_begin(loc), loc
+	}
 }
 
 

+ 3 - 0
core/strings/strings.odin

@@ -5,6 +5,7 @@ import "core:io"
 import "core:mem"
 import "core:slice"
 import "core:unicode"
+import "core:runtime"
 import "core:unicode/utf8"
 
 // returns a clone of the string `s` allocated using the `allocator`
@@ -1425,7 +1426,9 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator
 
 	// TODO maybe remove duplicate substrs
 	// sort substrings by string size, largest to smallest
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	temp_substrs := slice.clone(substrs, context.temp_allocator)
+	defer delete(temp_substrs)
 	slice.sort_by(temp_substrs, proc(a, b: string) -> bool {
 		return len(a) > len(b)	
 	})

+ 8 - 0
core/sys/darwin/xnu_system_call_helpers.odin

@@ -97,6 +97,7 @@ clone_to_cstring :: proc(s: string, allocator: runtime.Allocator, loc := #caller
 
 
 sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, bool) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	
 	cmode: u32 = 0
 	cflags: u32 = 0
@@ -132,30 +133,35 @@ sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, b
 }
 
 sys_mkdir :: proc(path: string, mode: Permission) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath: cstring = clone_to_cstring(path, context.temp_allocator)
 	cflags := _sys_permission_mode(mode)
 	return syscall_mkdir(cpath, cflags) != -1
 }
 
 sys_mkdir_at :: proc(fd: c.int, path: string, mode: Permission) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath: cstring = clone_to_cstring(path, context.temp_allocator)
 	cflags := _sys_permission_mode(mode)
 	return syscall_mkdir_at(fd, cpath, cflags) != -1
 }
 
 sys_rmdir :: proc(path: string, mode: Permission) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath: cstring = clone_to_cstring(path, context.temp_allocator)
 	cflags := _sys_permission_mode(mode)
 	return syscall_rmdir(cpath, cflags) != -1
 }
 
 sys_rename :: proc(path: string, new_path: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath: cstring = clone_to_cstring(path, context.temp_allocator)
 	cnpath: cstring = clone_to_cstring(new_path, context.temp_allocator)
 	return syscall_rename(cpath, cnpath) != -1
 }
 
 sys_rename_at :: proc(fd: c.int, path: string, to_fd: c.int, new_path: string) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath: cstring = clone_to_cstring(path, context.temp_allocator)
 	cnpath: cstring = clone_to_cstring(new_path, context.temp_allocator)
 	return syscall_rename_at(fd, cpath, to_fd, cnpath) != -1
@@ -166,12 +172,14 @@ sys_lseek :: proc(fd: c.int, offset: i64, whence: Offset_From) -> i64 {
 }
 
 sys_chmod :: proc(path: string, mode: Permission) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath: cstring = clone_to_cstring(path, context.temp_allocator)
 	cmode := _sys_permission_mode(mode)
 	return syscall_chmod(cpath, cmode) != -1
 }
 
 sys_lstat :: proc(path: string, status: ^stat) -> bool {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cpath: cstring = clone_to_cstring(path, context.temp_allocator)
 	return syscall_lstat(cpath, status) != -1
 }

+ 5 - 0
core/sys/info/platform_darwin.odin

@@ -4,6 +4,7 @@ package sysinfo
 import sys "core:sys/unix"
 import "core:strconv"
 import "core:strings"
+import "core:runtime"
 
 @(private)
 version_string_buf: [1024]u8
@@ -41,6 +42,8 @@ init_os_version :: proc () {
 
 		major_ok, minor_ok, patch_ok: bool
 
+		tmp := runtime.default_temp_allocator_temp_begin()
+
 		triplet := strings.split(string(cstring(&version_bits[0])), ".", context.temp_allocator)
 		if len(triplet) != 3 {
 			have_kernel_version = false
@@ -54,6 +57,8 @@ init_os_version :: proc () {
 			}
 		}
 
+		runtime.default_temp_allocator_temp_end(tmp)
+
 		if !have_kernel_version {
 			// We don't know the kernel version, but we do know the build
 			strings.write_string(&b, "macOS Unknown (build ")

+ 3 - 0
core/sys/info/platform_freebsd.odin

@@ -4,6 +4,7 @@ package sysinfo
 import sys "core:sys/unix"
 import "core:strings"
 import "core:strconv"
+import "core:runtime"
 
 @(private)
 version_string_buf: [1024]u8
@@ -47,6 +48,8 @@ init_os_version :: proc () {
 		return
 	}
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
 	// Parse kernel version
 	release := string(cstring(raw_data(kernel_version_buf[:])))
 	version_bits := strings.split_n(release, "-", 2, context.temp_allocator)

+ 3 - 0
core/sys/info/platform_linux.odin

@@ -4,6 +4,7 @@ package sysinfo
 import "core:c"
 import sys "core:sys/unix"
 import "core:intrinsics"
+import "core:runtime"
 import "core:os"
 import "core:strings"
 import "core:strconv"
@@ -69,6 +70,8 @@ init_os_version :: proc () {
 	l := strings.builder_len(b)
 	strings.write_string(&b, string(cstring(&uts.release[0])))
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
 	// Parse kernel version, as substrings of the version info in `version_string_buf`
 	version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator)
 	if len(version_bits) > 1 {

+ 4 - 1
core/sys/info/platform_openbsd.odin

@@ -4,6 +4,7 @@ package sysinfo
 import sys "core:sys/unix"
 import "core:strings"
 import "core:strconv"
+import "core:runtime"
 
 @(private)
 version_string_buf: [1024]u8
@@ -32,7 +33,9 @@ init_os_version :: proc () {
 	version := string(cstring(raw_data(kernel_version_buf[:])))
 	strings.write_string(&b, version)
 
-	// // Parse kernel version
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
+	// Parse kernel version
 	triplet := strings.split(version, ".", context.temp_allocator)
 	if len(triplet) == 2 {
 		major, major_ok := strconv.parse_int(triplet[0])

+ 3 - 0
core/sys/info/platform_windows.odin

@@ -7,6 +7,7 @@ import "core:strings"
 import "core:unicode/utf16"
 
 import "core:fmt"
+import "core:runtime"
 
 @(private)
 version_string_buf: [1024]u8
@@ -314,6 +315,8 @@ read_reg :: proc(hkey: sys.HKEY, subkey, val: string, $T: typeid) -> (res: T, ok
 		return {}, false
 	}
 
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
 	key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
 	val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)