Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion process/process_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ func (p *Process) PpidWithContext(_ context.Context) (int32, error) {
}

func (p *Process) NameWithContext(ctx context.Context) (string, error) {
if p.name != "" {
return p.name, nil
}
if p.Pid == 0 {
return "System Idle Process", nil
}
Expand All @@ -333,7 +336,9 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
return "", fmt.Errorf("could not get Name: %w", err)
}

return filepath.Base(exe), nil
name := filepath.Base(exe)
p.name = name
return name, nil
}

func (*Process) TgidWithContext(_ context.Context) (int32, error) {
Expand Down Expand Up @@ -587,6 +592,9 @@ func (p *Process) NumFDsWithContext(_ context.Context) (int32, error) {
}

func (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) {
if p.numThreads != 0 {
return p.numThreads, nil
}
ppid, ret, _, err := getFromSnapProcess(p.Pid)
if err != nil {
return 0, err
Expand All @@ -598,6 +606,8 @@ func (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) {
p.setPpid(ppid)
}

p.numThreads = ret

return ret, nil
}

Expand Down Expand Up @@ -900,6 +910,32 @@ func getFromSnapProcess(pid int32) (int32, int32, string, error) { //nolint:unpa
return 0, 0, "", fmt.Errorf("couldn't find pid: %d", pid)
}

func buildSnapProcessMap() (map[uint32]windows.ProcessEntry32, error) {
snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer windows.CloseHandle(snap)

var pe32 windows.ProcessEntry32
pe32.Size = uint32(unsafe.Sizeof(pe32))
if err := windows.Process32First(snap, &pe32); err != nil {
return nil, err
}

snapMap := make(map[uint32]windows.ProcessEntry32)
for {
snapMap[pe32.ProcessID] = pe32
if err := windows.Process32Next(snap, &pe32); err != nil {
if errors.Is(err, windows.ERROR_NO_MORE_FILES) {
break
}
return nil, err
}
}
Comment on lines +927 to +935
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildSnapProcessMap breaks out of the loop on any Process32Next error and returns the map, which can silently return an incomplete snapshot if Process32Next fails for reasons other than "no more files". Please explicitly treat windows.ERROR_NO_MORE_FILES (or the appropriate sentinel) as the normal termination condition, and return the error for any other failure.

Copilot uses AI. Check for mistakes.
return snapMap, nil
}

func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
out := []*Process{}

Expand All @@ -908,11 +944,23 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
return out, fmt.Errorf("could not get Processes %w", err)
}

snapMap, err := buildSnapProcessMap()
if err != nil {
return out, fmt.Errorf("could not build process snapshot: %w", err)
}

for _, pid := range pids {
p, err := NewProcessWithContext(ctx, pid)
if err != nil {
continue
}

if entry, ok := snapMap[uint32(pid)]; ok {
p.name = windows.UTF16ToString(entry.ExeFile[:])
p.setPpid(int32(entry.ParentProcessID))
p.numThreads = int32(entry.Threads)
}

out = append(out, p)
}

Expand Down
Loading