From 0d7e6430ebe4cc5d30e5ec3a7cdaccd2d78b35c8 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sun, 25 Aug 2024 13:08:24 +1100 Subject: [PATCH 1/6] [os2/process]: Don't free process info fields in partial success scenarios --- core/os/os2/process_windows.odin | 38 ++------------------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index 47fd62401..f2e60bee4 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -93,10 +93,6 @@ read_memory_as_slice :: proc(h: win32.HANDLE, addr: rawptr, dest: []$T) -> (byte @(private="package") _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { info.pid = pid - defer if err != nil { - free_process_info(info, allocator) - } - // Data obtained from process snapshots if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) @@ -119,7 +115,6 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } ph := win32.INVALID_HANDLE_VALUE - if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} { // need process handle ph = win32.OpenProcess( win32.PROCESS_QUERY_LIMITED_INFORMATION | win32.PROCESS_VM_READ, @@ -134,7 +129,6 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator defer if ph != win32.INVALID_HANDLE_VALUE { win32.CloseHandle(ph) } - if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb process_info_size: u32 process_info: win32.PROCESS_BASIC_INFORMATION @@ -145,23 +139,15 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator err = Platform_Error(status) return } - if process_info.PebBaseAddress == nil { - // Not sure what the error is - err = General_Error.Unsupported - return - } + assert(process_info.PebBaseAddress != nil) process_peb: win32.PEB - _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return - process_params: win32.RTL_USER_PROCESS_PARAMETERS _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return - if selection >= {.Command_Line, .Command_Args} { TEMP_ALLOCATOR_GUARD() cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return - if .Command_Line in selection { info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return info.fields += {.Command_Line} @@ -176,7 +162,6 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator env_len := process_params.EnvironmentSize / 2 envs_w := make([]u16, env_len, temp_allocator()) or_return _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return - info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return info.fields += {.Environment} } @@ -184,7 +169,6 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator TEMP_ALLOCATOR_GUARD() cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return - info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return info.fields += {.Working_Dir} } @@ -202,10 +186,6 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { pid := process.pid info.pid = pid - defer if err != nil { - free_process_info(info, allocator) - } - // Data obtained from process snapshots if selection >= {.PPid, .Priority} { // snap process entry, entry_err := _process_entry_by_pid(info.pid) @@ -237,23 +217,15 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields err = Platform_Error(status) return } - if process_info.PebBaseAddress == nil { - // Not sure what the error is - err = General_Error.Unsupported - return - } - + assert(process_info.PebBaseAddress != nil) process_peb: win32.PEB _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return - process_params: win32.RTL_USER_PROCESS_PARAMETERS _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return - if selection >= {.Command_Line, .Command_Args} { TEMP_ALLOCATOR_GUARD() cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return - if .Command_Line in selection { info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return info.fields += {.Command_Line} @@ -269,7 +241,6 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields env_len := process_params.EnvironmentSize / 2 envs_w := make([]u16, env_len, temp_allocator()) or_return _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return - info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return info.fields += {.Environment} } @@ -278,7 +249,6 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields TEMP_ALLOCATOR_GUARD() cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return - info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return info.fields += {.Working_Dir} } @@ -294,10 +264,6 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields @(private="package") _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { info.pid = get_pid() - defer if err != nil { - free_process_info(info, allocator) - } - if selection >= {.PPid, .Priority} { // snap process entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { From fa84e86766d6abd51fd5c02e85912661b36fd2a8 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sun, 25 Aug 2024 13:21:02 +1100 Subject: [PATCH 2/6] [os2/process]: Allow for partial success scenarios --- core/os/os2/process_windows.odin | 98 +++++++++++++++----------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index f2e60bee4..1fc4d366d 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -94,7 +94,7 @@ read_memory_as_slice :: proc(h: win32.HANDLE, addr: rawptr, dest: []$T) -> (byte _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { info.pid = pid // Data obtained from process snapshots - if selection >= {.PPid, .Priority} { + snapshot_process: if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { err = General_Error.Not_Exist @@ -109,13 +109,12 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator info.priority = int(entry.pcPriClassBase) } } - if .Executable_Path in selection { // snap module - info.executable_path = _process_exe_by_pid(pid, allocator) or_return + snapshot_modules: if .Executable_Path in selection { + info.executable_path = _process_exe_by_pid(pid, allocator) or_break snapshot_modules info.fields += {.Executable_Path} } - ph := win32.INVALID_HANDLE_VALUE - if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} { // need process handle + if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} { ph = win32.OpenProcess( win32.PROCESS_QUERY_LIMITED_INFORMATION | win32.PROCESS_VM_READ, false, @@ -129,7 +128,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator defer if ph != win32.INVALID_HANDLE_VALUE { win32.CloseHandle(ph) } - if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb + read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} { process_info_size: u32 process_info: win32.PROCESS_BASIC_INFORMATION status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size) @@ -141,41 +140,40 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } assert(process_info.PebBaseAddress != nil) process_peb: win32.PEB - _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return + _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_break read_peb process_params: win32.RTL_USER_PROCESS_PARAMETERS - _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return + _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_break read_peb if selection >= {.Command_Line, .Command_Args} { TEMP_ALLOCATOR_GUARD() - cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return - _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return + cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_break read_peb + _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_break read_peb if .Command_Line in selection { - info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return + info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_break read_peb info.fields += {.Command_Line} } if .Command_Args in selection { - info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return + info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_break read_peb info.fields += {.Command_Args} } } if .Environment in selection { TEMP_ALLOCATOR_GUARD() env_len := process_params.EnvironmentSize / 2 - envs_w := make([]u16, env_len, temp_allocator()) or_return - _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return - info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return + envs_w := make([]u16, env_len, temp_allocator()) or_break read_peb + _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_break read_peb + info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_break read_peb info.fields += {.Environment} } if .Working_Dir in selection { TEMP_ALLOCATOR_GUARD() - cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return - _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return - info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return + cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_break read_peb + _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_break read_peb + info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_break read_peb info.fields += {.Working_Dir} } } - - if .Username in selection { - info.username = _get_process_user(ph, allocator) or_return + read_username: if .Username in selection { + info.username = _get_process_user(ph, allocator) or_break read_username info.fields += {.Username} } err = nil @@ -187,7 +185,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields pid := process.pid info.pid = pid // Data obtained from process snapshots - if selection >= {.PPid, .Priority} { // snap process + snapshot_process: if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { err = General_Error.Not_Exist @@ -202,12 +200,12 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields info.priority = int(entry.pcPriClassBase) } } - if .Executable_Path in selection { // snap module - info.executable_path = _process_exe_by_pid(pid, allocator) or_return + snapshot_module: if .Executable_Path in selection { + info.executable_path = _process_exe_by_pid(pid, allocator) or_break snapshot_module info.fields += {.Executable_Path} } ph := win32.HANDLE(process.handle) - if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb + read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} { process_info_size: u32 process_info: win32.PROCESS_BASIC_INFORMATION status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size) @@ -219,42 +217,40 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields } assert(process_info.PebBaseAddress != nil) process_peb: win32.PEB - _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return + _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_break read_peb process_params: win32.RTL_USER_PROCESS_PARAMETERS - _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return + _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_break read_peb if selection >= {.Command_Line, .Command_Args} { TEMP_ALLOCATOR_GUARD() - cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return - _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return + cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_break read_peb + _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_break read_peb if .Command_Line in selection { - info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return + info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_break read_peb info.fields += {.Command_Line} } if .Command_Args in selection { - info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return + info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_break read_peb info.fields += {.Command_Args} } } - if .Environment in selection { TEMP_ALLOCATOR_GUARD() env_len := process_params.EnvironmentSize / 2 - envs_w := make([]u16, env_len, temp_allocator()) or_return - _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return - info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return + envs_w := make([]u16, env_len, temp_allocator()) or_break read_peb + _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_break read_peb + info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_break read_peb info.fields += {.Environment} } - if .Working_Dir in selection { TEMP_ALLOCATOR_GUARD() - cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return - _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return - info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return + cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_break read_peb + _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_break read_peb + info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_break read_peb info.fields += {.Working_Dir} } } - if .Username in selection { - info.username = _get_process_user(ph, allocator) or_return + read_username: if .Username in selection { + info.username = _get_process_user(ph, allocator) or_break read_username info.fields += {.Username} } err = nil @@ -264,7 +260,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields @(private="package") _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { info.pid = get_pid() - if selection >= {.PPid, .Priority} { // snap process + snapshot_process: if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { err = General_Error.Not_Exist @@ -279,31 +275,31 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime info.priority = int(entry.pcPriClassBase) } } - if .Executable_Path in selection { + module_filename: if .Executable_Path in selection { exe_filename_w: [256]u16 path_len := win32.GetModuleFileNameW(nil, raw_data(exe_filename_w[:]), len(exe_filename_w)) - info.executable_path = win32_utf16_to_utf8(exe_filename_w[:path_len], allocator) or_return + info.executable_path = win32_utf16_to_utf8(exe_filename_w[:path_len], allocator) or_break module_filename info.fields += {.Executable_Path} } - if selection >= {.Command_Line, .Command_Args} { + command_line: if selection >= {.Command_Line, .Command_Args} { command_line_w := win32.GetCommandLineW() if .Command_Line in selection { - info.command_line = win32_wstring_to_utf8(command_line_w, allocator) or_return + info.command_line = win32_wstring_to_utf8(command_line_w, allocator) or_break command_line info.fields += {.Command_Line} } if .Command_Args in selection { - info.command_args = _parse_command_line(command_line_w, allocator) or_return + info.command_args = _parse_command_line(command_line_w, allocator) or_break command_line info.fields += {.Command_Args} } } - if .Environment in selection { + environment: if .Environment in selection { env_block := win32.GetEnvironmentStringsW() - info.environment = _parse_environment_block(env_block, allocator) or_return + info.environment = _parse_environment_block(env_block, allocator) or_break environment info.fields += {.Environment} } - if .Username in selection { + username: if .Username in selection { process_handle := win32.GetCurrentProcess() - info.username = _get_process_user(process_handle, allocator) or_return + info.username = _get_process_user(process_handle, allocator) or_break username info.fields += {.Username} } if .Working_Dir in selection { From 4737485f0978e9120fb3d33a7f51dbdb1a67de14 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 26 Aug 2024 07:19:39 +1100 Subject: [PATCH 3/6] [os2/process]: Force return on allocation errors and process not existing --- core/os/os2/process_windows.odin | 200 ++++++++++++++++++++++--------- 1 file changed, 141 insertions(+), 59 deletions(-) diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index 1fc4d366d..0104f3753 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -93,26 +93,9 @@ read_memory_as_slice :: proc(h: win32.HANDLE, addr: rawptr, dest: []$T) -> (byte @(private="package") _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { info.pid = pid - // Data obtained from process snapshots - snapshot_process: if selection >= {.PPid, .Priority} { - entry, entry_err := _process_entry_by_pid(info.pid) - if entry_err != nil { - err = General_Error.Not_Exist - return - } - if .PPid in selection { - info.fields += {.PPid} - info.ppid = int(entry.th32ParentProcessID) - } - if .Priority in selection { - info.fields += {.Priority} - info.priority = int(entry.pcPriClassBase) - } - } - snapshot_modules: if .Executable_Path in selection { - info.executable_path = _process_exe_by_pid(pid, allocator) or_break snapshot_modules - info.fields += {.Executable_Path} - } + // Note(flysand): Open the process handle right away to prevent some race + // conditions. Once the handle is open, the process will be kept alive by + // the OS. ph := win32.INVALID_HANDLE_VALUE if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} { ph = win32.OpenProcess( @@ -128,6 +111,36 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator defer if ph != win32.INVALID_HANDLE_VALUE { win32.CloseHandle(ph) } + snapshot_process: if selection >= {.PPid, .Priority} { + entry, entry_err := _process_entry_by_pid(info.pid) + if entry_err != nil { + err = entry_err + if entry_err == General_Error.Not_Exist { + return + } else { + break snapshot_process + } + } + if .PPid in selection { + info.fields += {.PPid} + info.ppid = int(entry.th32ParentProcessID) + } + if .Priority in selection { + info.fields += {.Priority} + info.priority = int(entry.pcPriClassBase) + } + } + snapshot_modules: if .Executable_Path in selection { + exe_path: string + exe_path, err = _process_exe_by_pid(pid, allocator) + if _, ok := err.(runtime.Allocator_Error); ok { + return + } else if err != nil { + break snapshot_modules + } + info.executable_path = exe_path + info.fields += {.Executable_Path} + } read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} { process_info_size: u32 process_info: win32.PROCESS_BASIC_INFORMATION @@ -136,44 +149,66 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator // TODO(flysand): There's probably a mismatch between NTSTATUS and // windows userland error codes, I haven't checked. err = Platform_Error(status) - return + break read_peb } assert(process_info.PebBaseAddress != nil) process_peb: win32.PEB - _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_break read_peb + _, err = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) + if err != nil { + break read_peb + } process_params: win32.RTL_USER_PROCESS_PARAMETERS - _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_break read_peb + _, err = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) + if err != nil { + break read_peb + } if selection >= {.Command_Line, .Command_Args} { TEMP_ALLOCATOR_GUARD() - cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_break read_peb - _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_break read_peb + cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return + _, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) + if err != nil { + break read_peb + } if .Command_Line in selection { - info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_break read_peb + info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return info.fields += {.Command_Line} } if .Command_Args in selection { - info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_break read_peb + info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return info.fields += {.Command_Args} } } if .Environment in selection { TEMP_ALLOCATOR_GUARD() env_len := process_params.EnvironmentSize / 2 - envs_w := make([]u16, env_len, temp_allocator()) or_break read_peb - _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_break read_peb - info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_break read_peb + envs_w := make([]u16, env_len, temp_allocator()) or_return + _, err = read_memory_as_slice(ph, process_params.Environment, envs_w) + if err != nil { + break read_peb + } + info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return info.fields += {.Environment} } if .Working_Dir in selection { TEMP_ALLOCATOR_GUARD() - cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_break read_peb - _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_break read_peb - info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_break read_peb + cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return + _, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) + if err != nil { + break read_peb + } + info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return info.fields += {.Working_Dir} } } read_username: if .Username in selection { - info.username = _get_process_user(ph, allocator) or_break read_username + username: string + username, err = _get_process_user(ph, allocator) + if _, ok := err.(runtime.Allocator_Error); ok { + return + } else if err != nil { + break read_username + } + info.username = username info.fields += {.Username} } err = nil @@ -188,8 +223,12 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields snapshot_process: if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = General_Error.Not_Exist - return + err = entry_err + if entry_err == General_Error.Not_Exist { + return + } else { + break snapshot_process + } } if .PPid in selection { info.fields += {.PPid} @@ -201,7 +240,14 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields } } snapshot_module: if .Executable_Path in selection { - info.executable_path = _process_exe_by_pid(pid, allocator) or_break snapshot_module + exe_path: string + exe_path, err = _process_exe_by_pid(pid, allocator) + if _, ok := err.(runtime.Allocator_Error); ok { + return + } else if err != nil { + break snapshot_module + } + info.executable_path = exe_path info.fields += {.Executable_Path} } ph := win32.HANDLE(process.handle) @@ -217,40 +263,62 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields } assert(process_info.PebBaseAddress != nil) process_peb: win32.PEB - _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_break read_peb + _, err = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) + if err != nil { + break read_peb + } process_params: win32.RTL_USER_PROCESS_PARAMETERS - _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_break read_peb + _, err = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) + if err != nil { + break read_peb + } if selection >= {.Command_Line, .Command_Args} { TEMP_ALLOCATOR_GUARD() - cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_break read_peb - _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_break read_peb + cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return + _, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) + if err != nil { + break read_peb + } if .Command_Line in selection { - info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_break read_peb + info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return info.fields += {.Command_Line} } if .Command_Args in selection { - info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_break read_peb + info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return info.fields += {.Command_Args} } } if .Environment in selection { TEMP_ALLOCATOR_GUARD() env_len := process_params.EnvironmentSize / 2 - envs_w := make([]u16, env_len, temp_allocator()) or_break read_peb - _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_break read_peb - info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_break read_peb + envs_w := make([]u16, env_len, temp_allocator()) or_return + _, err = read_memory_as_slice(ph, process_params.Environment, envs_w) + if err != nil { + break read_peb + } + info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return info.fields += {.Environment} } if .Working_Dir in selection { TEMP_ALLOCATOR_GUARD() - cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_break read_peb - _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_break read_peb - info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_break read_peb + cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return + _, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) + if err != nil { + break read_peb + } + info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return info.fields += {.Working_Dir} } } read_username: if .Username in selection { - info.username = _get_process_user(ph, allocator) or_break read_username + username: string + username, err = _get_process_user(ph, allocator) + if _, ok := err.(runtime.Allocator_Error); ok { + return + } else if err != nil { + break read_username + } + info.username = username info.fields += {.Username} } err = nil @@ -263,8 +331,12 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime snapshot_process: if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = General_Error.Not_Exist - return + err = entry_err + if entry_err == General_Error.Not_Exist { + return + } else { + break snapshot_process + } } if .PPid in selection { info.fields += {.PPid} @@ -278,28 +350,38 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime module_filename: if .Executable_Path in selection { exe_filename_w: [256]u16 path_len := win32.GetModuleFileNameW(nil, raw_data(exe_filename_w[:]), len(exe_filename_w)) - info.executable_path = win32_utf16_to_utf8(exe_filename_w[:path_len], allocator) or_break module_filename + assert(path_len > 0) + info.executable_path = win32_utf16_to_utf8(exe_filename_w[:path_len], allocator) or_return info.fields += {.Executable_Path} } command_line: if selection >= {.Command_Line, .Command_Args} { command_line_w := win32.GetCommandLineW() + assert(command_line_w != nil) if .Command_Line in selection { - info.command_line = win32_wstring_to_utf8(command_line_w, allocator) or_break command_line + info.command_line = win32_wstring_to_utf8(command_line_w, allocator) or_return info.fields += {.Command_Line} } if .Command_Args in selection { - info.command_args = _parse_command_line(command_line_w, allocator) or_break command_line + info.command_args = _parse_command_line(command_line_w, allocator) or_return info.fields += {.Command_Args} } } - environment: if .Environment in selection { + read_environment: if .Environment in selection { env_block := win32.GetEnvironmentStringsW() - info.environment = _parse_environment_block(env_block, allocator) or_break environment + assert(env_block != nil) + info.environment = _parse_environment_block(env_block, allocator) or_return info.fields += {.Environment} } - username: if .Username in selection { + read_username: if .Username in selection { process_handle := win32.GetCurrentProcess() - info.username = _get_process_user(process_handle, allocator) or_break username + username: string + username, err := _get_process_user(process_handle, allocator) + if _, ok := err.(runtime.Allocator_Error); ok { + return + } else if err != nil { + break read_username + } + info.username = username info.fields += {.Username} } if .Working_Dir in selection { From db94e646e03c40a0a2acd8d124bc924f61dd39a3 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 26 Aug 2024 07:21:54 +1100 Subject: [PATCH 4/6] [os2/process]: Adjust documentation for process info --- core/os/os2/process.odin | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index f7a542276..a43ebc8d7 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -166,15 +166,15 @@ Process_Info :: struct { This procedure obtains an information, specified by `selection` parameter of a process given by `pid`. - - Use `free_process_info` to free the memory allocated by this procedure. In - case the function returns an error it may only have been an error for one part - of the information and you would still need to call it to free the other parts. + + Use `free_process_info` to free the memory allocated by this procedure. The + `free_process_info` procedure needs to be called, even if this procedure + returned an error, as some of the fields have been allocated. **Note**: The resulting information may or may contain the fields specified by the `selection` parameter. Always check whether the returned `Process_Info` struct has the required fields before checking the error code - returned by this function. + returned by this procedure. */ @(require_results) process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) { @@ -188,14 +188,14 @@ process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: about a process that has been opened by the application, specified in the `process` parameter. - Use `free_process_info` to free the memory allocated by this procedure. In - case the function returns an error it may only have been an error for one part - of the information and you would still need to call it to free the other parts. + Use `free_process_info` to free the memory allocated by this procedure. The + `free_process_info` procedure needs to be called, even if this procedure + returned an error, as some of the fields have been allocated. **Note**: The resulting information may or may contain the fields specified by the `selection` parameter. Always check whether the returned `Process_Info` struct has the required fields before checking the error code - returned by this function. + returned by this procedure. */ @(require_results) process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) { @@ -208,14 +208,14 @@ process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, This procedure obtains the information, specified by `selection` parameter about the currently running process. - Use `free_process_info` to free the memory allocated by this procedure. In - case the function returns an error it may only have been an error for one part - of the information and you would still need to call it to free the other parts. + Use `free_process_info` to free the memory allocated by this procedure. The + `free_process_info` procedure needs to be called, even if this procedure + returned an error, as some of the fields have been allocated. **Note**: The resulting information may or may contain the fields specified by the `selection` parameter. Always check whether the returned `Process_Info` struct has the required fields before checking the error code - returned by this function. + returned by this procedure. */ @(require_results) current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) { From 3119e0489fbd9c9c2c4010c500d03c66128d177b Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 26 Aug 2024 07:23:59 +1100 Subject: [PATCH 5/6] [os2/process]: Fix vet errors --- core/os/os2/process_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index 0104f3753..edb321509 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -375,7 +375,7 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime read_username: if .Username in selection { process_handle := win32.GetCurrentProcess() username: string - username, err := _get_process_user(process_handle, allocator) + username, err = _get_process_user(process_handle, allocator) if _, ok := err.(runtime.Allocator_Error); ok { return } else if err != nil { From 1a4faff9c97594e5f2150dff42313779d760bbcc Mon Sep 17 00:00:00 2001 From: flysand7 Date: Tue, 27 Aug 2024 08:06:11 +1100 Subject: [PATCH 6/6] [os2/process]: Fix typo on doc comments --- core/os/os2/process.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index a43ebc8d7..428506c45 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -169,7 +169,7 @@ Process_Info :: struct { Use `free_process_info` to free the memory allocated by this procedure. The `free_process_info` procedure needs to be called, even if this procedure - returned an error, as some of the fields have been allocated. + returned an error, as some of the fields may have been allocated. **Note**: The resulting information may or may contain the fields specified by the `selection` parameter. Always check whether the returned @@ -190,7 +190,7 @@ process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: Use `free_process_info` to free the memory allocated by this procedure. The `free_process_info` procedure needs to be called, even if this procedure - returned an error, as some of the fields have been allocated. + returned an error, as some of the fields may have been allocated. **Note**: The resulting information may or may contain the fields specified by the `selection` parameter. Always check whether the returned @@ -210,7 +210,7 @@ process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, Use `free_process_info` to free the memory allocated by this procedure. The `free_process_info` procedure needs to be called, even if this procedure - returned an error, as some of the fields have been allocated. + returned an error, as some of the fields may have been allocated. **Note**: The resulting information may or may contain the fields specified by the `selection` parameter. Always check whether the returned