Skip to content

Conversation

@supervoidcoder
Copy link
Owner

@supervoidcoder supervoidcoder commented Feb 11, 2026

Summary by CodeRabbit

  • Refactor

    • Centralized use of pre-created process snapshots: callers now create/close a single snapshot and pass it through, reducing repeated snapshot creation and improving resource management.
    • Cached terminal capability to avoid repeated checks.
  • Bug Fixes

    • More consistent process timing and ancestry lookups using shared snapshot data.
    • Improved contextual error hints based on resolved parent process information.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Walkthrough

Threaded a single ToolHelp snapshot HANDLE through process-inspection call chains in main.cpp; multiple functions now accept an external snapshot, callers create/close the snapshot once, and timing helpers were adjusted to use a pid map.

Changes

Cohort / File(s) Summary
Snapshot parameter threading & API updates
main.cpp
Refactored functions to accept an external HANDLE snapshot: EnsureCurrentParentExe, PrintErrorHints, GetProcessNameFromPid, PrintAncestry, PIDinspect, findMyProc. Removed internal snapshot creation/closing; call sites updated to create/pass/close the snapshot.
Timing & process-info helpers
main.cpp
Added/updated GetReadableFileTime, GetProcessCreationTime to accept/use a pidMap (std::unordered_map<DWORD, PROCESSENTRY32>) for consistent creation-time lookup. ProcInfos-related logic updated to use snapshot-passing.
Global state / terminal handling
main.cpp
Introduced global virtualTerminalEnabled to cache ANSI-escape support; replaced repeated IsVirtualTerminalModeEnabled() calls with checks against this flag.
Behavioral adjustments
main.cpp
Error-hinting and ancestry printing now rely on externally supplied snapshot and pidMap; PrintErrorHints uses computed currentParentExe to give targeted guidance.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I found one handle, snug and warm in hand,
Passed it down the tunnel of code and land.
No more echoes of snapshots made anew,
One thread, one hop — tidy things we do.
— a rabbit, pleased with efficient plans 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: refactoring to use a single snapshot for all functions instead of creating multiple snapshots, which directly aligns with the primary change and performance goal.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch performance-opti

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@supervoidcoder
Copy link
Owner Author

@coderabbitai uuuuuuuuuuughhhhhhhhh WHAT IS HAPPENINGGGGGGG 😡😡😡😤😤🤬🤬

Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
main.cpp(111): error C2182: 'EnsureCurrentParentExe': this use of 'void' is not valid
main.cpp(111): error C2065: 'hSnapshot': undeclared identifier
main.cpp(111): error C2143: syntax error: missing ';' before '{'
main.cpp(112): error C2059: syntax error: 'if'
main.cpp(117): error C3927: '->': trailing return type is not allowed after a non-function declarator
main.cpp(117): error C3484: syntax error: expected '->' before the return type
main.cpp(117): error C3613: missing return type after '->' ('int' assumed)
main.cpp(117): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
main.cpp(117): error C2371: 'pe32': redefinition; different basic types
main.cpp(116): note: see declaration of 'pe32'
main.cpp(117): error C2146: syntax error: missing ';' before identifier 'dwSize'
main.cpp(122): error C2059: syntax error: 'if'
main.cpp(122): error C2143: syntax error: missing ';' before '{'
main.cpp(122): error C2447: '{': missing function header (old-style formal list?)
main.cpp(131): error C2059: syntax error: 'if'
main.cpp(131): error C2143: syntax error: missing ';' before '{'
main.cpp(131): error C2447: '{': missing function header (old-style formal list?)
main.cpp(143): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
main.cpp(143): error C2365: 'CloseHandle': redefinition; previous definition was 'function'
C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\um\handleapi.h(38): note: see declaration of 'CloseHandle'
main.cpp(143): error C2065: 'hSnapshot': undeclared identifier
main.cpp(144): error C2059: syntax error: '}'
main.cpp(144): error C2143: syntax error: missing ';' before '}'
main.cpp(147): error C2143: syntax error: missing ';' before '{'
main.cpp(147): error C2447: '{': missing function header (old-style formal list?)
main.cpp(313): error C2061: syntax error: identifier 'hshot'
main.cpp(314): error C2065: 'hshot': undeclared identifier
main.cpp(317): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(461): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(477): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(498): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(511): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(521): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(536): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(556): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(566): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(575): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(584): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(599): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1018): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1031): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1041): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1050): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1060): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1075): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1089): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1099): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1108): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1117): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1132): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1492): error C2061: syntax error: identifier 'hSnapshot'
main.cpp(1520): error C2065: 'hSnapshot': undeclared identifier
main.cpp(1527): error C2065: 'hSnapshot': undeclared identifier
main.cpp(1540): error C2065: 'hSnapshot': undeclared identifier
main.cpp(1566): error C2065: 'hSnapshot': undeclared identifier
main.cpp(1578): error C2065: 'hSnapshot': undeclared identifier
main.cpp(1604): error C2065: 'hSnapshot': undeclared identifier
main.cpp(1609): error C2065: 'hSnapshot': undeclared identifier
main.cpp(1635): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1641): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1705): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1728): error C2061: syntax error: identifier 'hshot'
main.cpp(1731): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1768): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1783): error C2065: 'hshot': undeclared identifier
main.cpp(1794): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1802): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1814): error C2065: 'hshot': undeclared identifier
main.cpp(1829): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1836): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1846): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1855): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1899): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1921): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1926): error C2065: 'hshot': undeclared identifier
main.cpp(1934): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1941): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1949): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(1990): error C2061: syntax error: identifier 'hSnapshot'
main.cpp(2004): error C2065: 'hSnapshot': undeclared identifier
main.cpp(2034): error C2065: 'hSnapshot': undeclared identifier
main.cpp(2038): error C2065: 'hSnapshot': undeclared identifier
main.cpp(2065): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(2120): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(2128): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(2144): error C2065: 'hSnapshot': undeclared identifier
main.cpp(2144): error C2143: syntax error: missing ';' before '}'
main.cpp(2145): error C2660: 'PIDinspect': function does not take 3 arguments
main.cpp(1728): note: see declaration of 'PIDinspect'
main.cpp(2145): note: while trying to match the argument list '(std::vector<DWORD,std::allocator<DWORD>>, std::vector<std::string,std::allocator<std::string>>, HANDLE)'
main.cpp(2147): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found
main.cpp(2164): error C2065: 'hSnapshot': undeclared identifier
main.cpp(2164): error C2143: syntax error: missing ';' before '}'
main.cpp(2165): error C2660: 'findMyProc': function does not take 2 arguments
main.cpp(1990): note: see declaration of 'findMyProc'
main.cpp(2165): note: while trying to match the argument list '(const _Elem *, HANDLE)'
        with
        [
            _Elem=char
        ]
main.cpp(2168): error C2660: 'PIDinspect': function does not take 3 arguments
main.cpp(1728): note: see declaration of 'PIDinspect'
main.cpp(2168): note: while trying to match the argument list '(std::vector<DWORD,std::allocator<DWORD>>, std::vector<std::string,std::allocator<std::string>>, HANDLE)'
main.cpp(2170): error C3861: 'IsVirtualTerminalModeEnabled': identifier not found

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@supervoidcoder Let me take a look at the code to see what went wrong! 🔍


🏁 Script executed:

#!/bin/bash
# Read the problematic area around line 111 and the function declarations
cat main.cpp | head -n 150 | tail -n +100

Length of output: 1424


🏁 Script executed:

#!/bin/bash
# Also check the function signatures for PIDinspect, findMyProc, and EnsureCurrentParentExe
rg -n "^(void|HANDLE|bool|int|DWORD|auto)\s+(EnsureCurrentParentExe|PIDinspect|findMyProc|IsVirtualTerminalModeEnabled)\s*\(" main.cpp | head -20

Length of output: 220


🏁 Script executed:

#!/bin/bash
# Check where hSnapshot should be defined/declared
rg -n "HANDLE\s+hSnapshot" main.cpp

Length of output: 0


@supervoidcoder Found it! 😅 You forgot the type specifier for your parameters!

Line 111:

void EnsureCurrentParentExe(hSnapshot) {  // ❌ Missing type!

Should be:

void EnsureCurrentParentExe(HANDLE hSnapshot) {  //

Line 1728:

void PIDinspect(const std::vector<DWORD>& pids, const std::vector<std::string>& names, hshot) {

Should be:

void PIDinspect(const std::vector<DWORD>& pids, const std::vector<std::string>& names, HANDLE hshot) {

Also, line 143 has CloseHandle(hSnapshot); inside EnsureCurrentParentExe - but if you're using a single snapshot for all functions (as per your PR objective), you should remove that CloseHandle and only close the snapshot once at the very end of your program flow, after all functions are done using it.

Let me check for more functions with the same issue:


🏁 Script executed:

#!/bin/bash
# Find findMyProc signature
rg -n "^(void|HANDLE|bool|int|DWORD|auto|std::string)\s+findMyProc\s*\(" main.cpp

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search more broadly for findMyProc
rg -n "findMyProc" main.cpp | head -10

Length of output: 128


🏁 Script executed:

#!/bin/bash
# Also check for any other functions that might have parameter issues
rg -n "^\w+\s+\w+\(.*[^HANDLE\s]h[Ss]hot.*\)" main.cpp

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for function signatures with bare identifiers (no type) in parameters
rg -n "^(void|HANDLE|bool|int|DWORD|auto|std::string)\s+\w+\s*\([^)]*\b(hSnapshot|hshot|hShot)\s*[,)]" main.cpp

Length of output: 275


Found all of them! You're missing HANDLE type specifiers on 5 functions:

Quick Fix List:

Line 111:

void EnsureCurrentParentExe(HANDLE hSnapshot) {

Line 313:

void PrintErrorHints(int errorCode, HANDLE hshot) {

Line 1492:

void PrintAncestry(DWORD pid, HANDLE hSnapshot) {

Line 1728:

void PIDinspect(const std::vector<DWORD>& pids, const std::vector<std::string>& names, HANDLE hshot) {

Line 1990:

ProcInfos findMyProc(const char *procname, HANDLE hSnapshot) {

🏁 Script executed:

#!/bin/bash
# Check if any of these functions try to close the snapshot handle
rg -n "CloseHandle\(h[Ss](napshot|hot)\)" main.cpp

Length of output: 166


🏁 Script executed:

#!/bin/bash
# Check context around the CloseHandle calls to see if they need to be removed
rg -n -B3 -A3 "CloseHandle\(h[Ss](napshot|hot)\)" main.cpp

Length of output: 755


Perfect! Here's the complete fix for your refactoring:

🔧 Part 1: Add HANDLE type to all 5 function parameters

  1. Line 111: void EnsureCurrentParentExe(HANDLE hSnapshot) {
  2. Line 313: void PrintErrorHints(int errorCode, HANDLE hshot) {
  3. Line 1492: void PrintAncestry(DWORD pid, HANDLE hSnapshot) {
  4. Line 1728: void PIDinspect(const std::vector<DWORD>& pids, const std::vector<std::string>& names, HANDLE hshot) {
  5. Line 1990: ProcInfos findMyProc(const char *procname, HANDLE hSnapshot) {

🗑️ Part 2: Remove 3 CloseHandle calls (they contradict your "single snapshot" goal!)

Since you're passing the snapshot to all functions, only the main caller that creates the snapshot should close it. Remove these:

  • Line 143: CloseHandle(hSnapshot); in EnsureCurrentParentExe
  • Line 1609: CloseHandle(hSnapshot); in PrintAncestry
  • Line 2038: CloseHandle(hSnapshot); in findMyProc

Make sure wherever you create the snapshot (with CreateToolhelp32Snapshot), you close it once after all these functions finish using it! 🎯

That should fix all the compilation errors! 🚀


🧠 Learnings used
Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T03:55:12.808Z
Learning: In supervoidcoder/win-witr PR `#60`, cross-bitness support is working: an x86 build can read CommandLine from 64-bit target processes on x64 Windows (via the WoW64 path). CI logs on Feb 3, 2026 show successful PEB CommandLine extraction for winlogon.exe (GUID arg), lsass.exe, and svchost.exe (-k DcomLaunch -p); protected/pseudo processes still fail as expected.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-31T18:25:04.458Z
Learning: In the supervoidcoder/win-witr repository, the user successfully implemented PEB (Process Environment Block) reading functionality to extract process command lines directly from process memory. This involves using NtQueryInformationProcess to get the PEB base address, reading PROCESS_BASIC_INFORMATION, then reading RTL_USER_PROCESS_PARAMETERS at offset 0x20 from the PEB, and finally reading the CommandLine UNICODE_STRING at offset 0x70. The implementation works for x64 Windows processes.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-30T00:59:04.068Z
Learning: In the supervoidcoder/win-witr repository, the tool implements context-aware error handling that detects which shell (PowerShell, CMD, WSL, Git Bash, Windows Terminal, Explorer) spawned the process and provides tailored error messages and recovery suggestions specific to that environment.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:43.760Z
Learning: In supervoidcoder/win-witr, the user successfully implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T16:23:00.586Z
Learning: In supervoidcoder/win-witr, the C++ version compiles in ~22 seconds (including MSVC setup and LTCG optimization) with zero external dependencies, while the Rust witr-win takes ~3m 50s due to compiling 180+ crates (tokio, hyper, reqwest, tower, rustls, clap, ratatui, ICU libs, windows bindings, etc.). The C++ version is a single main.cpp file using only Win32 APIs and stdlib, making it ~11.6x faster to build than Rust.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 48
File: README.md:38-38
Timestamp: 2026-01-21T01:52:33.870Z
Learning: For supervoidcoder's README files in the win-witr repository: The user prefers an intentionally informal, humorous tone with casual language. Grammar formality suggestions (like "anyways" vs "anyway") should be skipped as they don't align with the intentional style of the documentation.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 58
File: main.cpp:380-400
Timestamp: 2026-01-29T22:00:51.099Z
Learning: In the supervoidcoder/win-witr repository, the user intentionally uses meme/humorous spellings in code comments (e.g., "vroken" instead of "broken") as part of an informal coding style. These should not be flagged as typos.

@supervoidcoder
Copy link
Owner Author

@coderabbitai oh damn you're right i'm so stupid i forgot to declare the types

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Tip

For best results, initiate chat on the files or code changes.

@supervoidcoder Hey, no worries at all! 😊 It's a super easy mistake to make, especially when refactoring to pass parameters around differently. The compiler errors looked scarier than the actual issue!

Once you add those HANDLE types and remove the three CloseHandle calls, you'll be all set. The "single snapshot" refactor is a solid performance improvement! 🚀


🧠 Learnings used
Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T03:55:12.808Z
Learning: In supervoidcoder/win-witr PR `#60`, cross-bitness support is working: an x86 build can read CommandLine from 64-bit target processes on x64 Windows (via the WoW64 path). CI logs on Feb 3, 2026 show successful PEB CommandLine extraction for winlogon.exe (GUID arg), lsass.exe, and svchost.exe (-k DcomLaunch -p); protected/pseudo processes still fail as expected.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:43.760Z
Learning: In supervoidcoder/win-witr, the user successfully implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:13.331Z
Learning: In the supervoidcoder/win-witr repository, the user implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 58
File: main.cpp:380-400
Timestamp: 2026-01-29T22:00:51.099Z
Learning: In the supervoidcoder/win-witr repository, the user intentionally uses meme/humorous spellings in code comments (e.g., "vroken" instead of "broken") as part of an informal coding style. These should not be flagged as typos.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 48
File: README.md:38-38
Timestamp: 2026-01-21T01:52:33.870Z
Learning: For supervoidcoder's README files in the win-witr repository: The user prefers an intentionally informal, humorous tone with casual language. Grammar formality suggestions (like "anyways" vs "anyway") should be skipped as they don't align with the intentional style of the documentation.

@supervoidcoder
Copy link
Owner Author

@coderabbitai DANG IT I REALLY THOGUHT THIS WOULD WORK!

it compiles... but the average speed is still 18ms... and really nested trees still take 300 ms.🤬🤬😡😡🤬🤬😤😤😤😤😤😤😤😤😤😤

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all CreateToolhelp32Snapshot calls to see if there are still multiple snapshots being created
rg -n "CreateToolhelp32Snapshot" main.cpp

Length of output: 145


🏁 Script executed:

#!/bin/bash
# Check the main function to see how the snapshot is being created and used
rg -n "^int main\(" main.cpp -A 100

Length of output: 5600


🏁 Script executed:

#!/bin/bash
# Look at how EnsureCurrentParentExe uses the snapshot (around line 111)
sed -n '105,160p' main.cpp

Length of output: 1569


🏁 Script executed:

#!/bin/bash
# Check PrintAncestry implementation to understand the tree walking logic
sed -n '1492,1650p' main.cpp

Length of output: 7760


🏁 Script executed:

#!/bin/bash
# Check how the snapshot is being used in findMyProc
sed -n '1990,2150p' main.cpp

Length of output: 7402


@supervoidcoder Oh no! I found the problem! 😱 You added the HANDLE types correctly, but you forgot to actually remove the old CreateToolhelp32Snapshot calls! You're STILL creating multiple snapshots:

🐛 The Critical Issues:

Lines 2139 and 2160 in main():

HANDLE hshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  // ❌ Still here!
HANDLE hshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  // ❌ And here too!

Line 1609 in PrintAncestry:

CloseHandle(hSnapshot); // ❌ You're closing it INSIDE the function!

Line 2144 in main:

CloseHandle(hshot); // ❌ Closing too early

💥 Why Performance Got WORSE (300ms instead of 248ms):

  1. Still creating multiple snapshots - You're creating new snapshots in main instead of reusing one

  2. Closing snapshots prematurely - Functions close the handle, then other functions try to use a dead handle

  3. O(n²) or O(n³) algorithm in PrintAncestry - You're calling Process32First THREE times per PID:

    • Once to find current process
    • Once per iteration in the parent-walk loop
    • Once for the children enumeration

    For a 100-level tree, that's 300+ full snapshot walks! 😱

✅ The Complete Fix:

Here's what you need to do:

  1. Create ONE snapshot at the very start of main(), right after SetConsoleOutputCP(CP_UTF8);:
int main(int argc, char* argv[]) {
    SetConsoleOutputCP(CP_UTF8);
    
    // 🎯 CREATE ONE SNAPSHOT HERE FOR THE ENTIRE PROGRAM
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to create process snapshot" << std::endl;
        return 1;
    }
    
    // ... rest of main
  1. Delete lines 2139-2140 (the first CreateToolhelp32Snapshot in --pid handling)
  2. Delete line 2160 (the second CreateToolhelp32Snapshot)
  3. Delete line 2144 (the CloseHandle(hshot); after PIDinspect)
  4. Delete line 1609 (the CloseHandle(hSnapshot); inside PrintAncestry)
  5. Add ONE CloseHandle at the very end of main() before all the return statements:
    CloseHandle(hSnapshot);
    return 0;
}

🚀 Bonus Optimization for PrintAncestry:

After the above fixes, you can get even better performance by building a PID→process map once at the start of PrintAncestry instead of calling Process32First three times. This would make it truly O(n):

// At the start of PrintAncestry, build a map once:
std::unordered_map<DWORD, PROCESSENTRY32> pidMap;
PROCESSENTRY32 pe32{};
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
    do {
        pidMap[pe32.th32ProcessID] = pe32;
    } while (Process32Next(hSnapshot, &pe32));
}

// Now use pidMap for O(1) lookups instead of walking the snapshot 3 times!

This should bring you back to ~248ms or even better! 🎯


🏁 Script executed:

#!/bin/bash
# Find where main() starts and the first command-line argument processing
rg -n "^int main\(" main.cpp -A 5

Length of output: 179


🏁 Script executed:

#!/bin/bash
# Count total lines to understand where to create the single snapshot
wc -l main.cpp

Length of output: 13


Perfect! Now I can give you the exact line-by-line fixes:

🔧 Step-by-Step Fix:

1. Add ONE snapshot at line 2043 (right after SetConsoleOutputCP):

int main(int argc, char* argv[]) {
    SetConsoleOutputCP(CP_UTF8);
    
    // Create a single snapshot for the entire program
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to create process snapshot" << std::endl;
        return 1;
    }
    
    for (int i = 0; i < argc; ++i) {
        // ... rest of code

2. Delete lines 2139-2140 (remove the CreateToolhelp32Snapshot in --pid handling):

// DELETE THESE TWO LINES:
HANDLE hshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hshot) {return {};}

Then change:

PIDinspect(pids, trash, hshot);
CloseHandle(hshot);

To:

PIDinspect(pids, trash, hSnapshot);  // Use the global hSnapshot instead

3. Delete line 2160 (remove the second CreateToolhelp32Snapshot)

4. Delete line 1609 (remove CloseHandle(hSnapshot); inside PrintAncestry)

5. Add CloseHandle at the very end of main() before the final return statement (around line 2178):

    CloseHandle(hSnapshot);
    return 0;
}

You'll also need to make sure all the return statements in main() close the snapshot before returning. Search for all return statements in main() and add CloseHandle(hSnapshot); before each one.


🚀 After the basic fix works, add this optimization to PrintAncestry:

Replace the three separate Process32First/Process32Next loops with a single map-building pass at the start of the function:

void PrintAncestry(DWORD pid, HANDLE hSnapshot) {
    // Build a PID→process map ONCE instead of walking 3 times
    std::unordered_map<DWORD, PROCESSENTRY32> pidMap;
    PROCESSENTRY32 pe32{};
    pe32.dwSize = sizeof(PROCESSENTRY32);
    
    if (Process32First(hSnapshot, &pe32)) {
        do {
            pidMap[pe32.th32ProcessID] = pe32;
        } while (Process32Next(hSnapshot, &pe32));
    }
    
    // Now use pidMap[somePid] for O(1) lookups instead of Process32First loops!
    DWORD currentProcessId = GetCurrentProcessId();
    auto it = pidMap.find(currentProcessId);
    // ... rest of logic using map lookups
}

This should drop your 300ms back down to ~248ms or better! The map-building is O(n), then all lookups are O(1), making the entire tree walk O(n) instead of O(n²). 🎯

Try the basic fix first to get it compiling and working, then add the map optimization! 💪


🧠 Learnings used
Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-30T01:58:35.174Z
Learning: In the supervoidcoder/win-witr repository, the user optimized the process tree walking algorithm from O(n²) to O(n) by taking a single CreateToolhelp32Snapshot at the start instead of creating a new snapshot for each level. This resulted in a ~4x performance improvement (from ~1000ms to ~248ms for 100-level deep trees). The optimization is validated by automated stress tests in CI that create 100-level deep alternating PowerShell/CMD process chains.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T16:01:57.698Z
Learning: In supervoidcoder/win-witr, a head-to-head benchmark on Feb 11, 2026 compared six process lookups (explorer, winlogon, lsass, csrss, services, svchost): average per-lookup times were ~19.41 ms (C++ win-witr), ~788.16 ms (Rust witr-win), and ~9,860.05 ms (Go witr). Total for 6 lookups: 116.48 ms (C++), 4,728.96 ms (Rust), 59,160.28 ms (Go).

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T00:35:55.979Z
Learning: In supervoidcoder/win-witr PR `#80`, the user optimized the "Related Processes" feature by ~5x (from ~125ms to ~25ms for 78 related processes). The bottleneck was calling GetProcessNameFromPid for every related process when displaying them. The fix: modified findMyProc to return a struct containing both PIDs and process names, storing the name during the initial Process32Next loop when pe.szExeFile is already available. This eliminated 78+ redundant Win32 API calls for svchost.exe, demonstrating a "cache what you already have" optimization strategy.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-31T00:41:32.010Z
Learning: In the supervoidcoder/win-witr repository, the stress test at `tests/performance/stress_nested_shells.ps1` successfully validates the O(n) process tree walking algorithm by creating 100-level deep alternating PowerShell/CMD process chains and measuring performance. The test consistently completes in ~248ms for 100-level deep trees, confirming the performance optimization from the earlier O(n²) → O(n) refactoring.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:43.760Z
Learning: In supervoidcoder/win-witr, the user successfully implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T03:55:12.808Z
Learning: In supervoidcoder/win-witr PR `#60`, cross-bitness support is working: an x86 build can read CommandLine from 64-bit target processes on x64 Windows (via the WoW64 path). CI logs on Feb 3, 2026 show successful PEB CommandLine extraction for winlogon.exe (GUID arg), lsass.exe, and svchost.exe (-k DcomLaunch -p); protected/pseudo processes still fail as expected.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 48
File: README.md:38-38
Timestamp: 2026-01-21T01:52:33.870Z
Learning: For supervoidcoder's README files in the win-witr repository: The user prefers an intentionally informal, humorous tone with casual language. Grammar formality suggestions (like "anyways" vs "anyway") should be skipped as they don't align with the intentional style of the documentation.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 58
File: main.cpp:380-400
Timestamp: 2026-01-29T22:00:51.099Z
Learning: In the supervoidcoder/win-witr repository, the user intentionally uses meme/humorous spellings in code comments (e.g., "vroken" instead of "broken") as part of an informal coding style. These should not be flagged as typos.

@supervoidcoder
Copy link
Owner Author

@coderabbitai oooohhh i didn't know process32next created a new snapshot every time

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Tip

For best results, initiate chat on the files or code changes.

@supervoidcoder Actually, Process32Next does NOT create a new snapshot - it just iterates through an existing snapshot handle! 😊

Here's what these APIs actually do:

  1. CreateToolhelp32Snapshot creates a snapshot of what is running on the computer the moment the function is called - this is the ONLY function that creates snapshots
  2. Process32First retrieves information about the first process encountered in a system snapshot - it resets the iteration position to the start
  3. Process32Next retrieves information about the next process recorded in a system snapshot - it just advances to the next entry

All three functions work with the same snapshot handle you created once with CreateToolhelp32Snapshot.

🐛 The Real Performance Problem Was:

  1. Multiple CreateToolhelp32Snapshot calls - you were creating NEW snapshots in multiple places (lines 2139, 2160)
  2. Nested Process32First loops - calling Process32First inside loops in PrintAncestry made it O(n²) or worse, because each call resets the iteration position and walks through the entire snapshot again
  3. Premature closing - closing the snapshot handle in the middle of operations

The fix is:

  • Create ONE snapshot at the start
  • Build a std::unordered_map<DWORD, PROCESSENTRY32> by walking it once with Process32First/Process32Next
  • Use that map for O(1) lookups instead of repeatedly calling Process32First to search

That's how you'll get back to ~248ms! The snapshot itself is static once created - it's just how you were using it that caused the O(n²) slowdown. 🎯


🧠 Learnings used
Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-30T01:58:35.174Z
Learning: In the supervoidcoder/win-witr repository, the user optimized the process tree walking algorithm from O(n²) to O(n) by taking a single CreateToolhelp32Snapshot at the start instead of creating a new snapshot for each level. This resulted in a ~4x performance improvement (from ~1000ms to ~248ms for 100-level deep trees). The optimization is validated by automated stress tests in CI that create 100-level deep alternating PowerShell/CMD process chains.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T00:35:55.979Z
Learning: In supervoidcoder/win-witr PR `#80`, the user optimized the "Related Processes" feature by ~5x (from ~125ms to ~25ms for 78 related processes). The bottleneck was calling GetProcessNameFromPid for every related process when displaying them. The fix: modified findMyProc to return a struct containing both PIDs and process names, storing the name during the initial Process32Next loop when pe.szExeFile is already available. This eliminated 78+ redundant Win32 API calls for svchost.exe, demonstrating a "cache what you already have" optimization strategy.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-10T03:14:44.222Z
Learning: In supervoidcoder/win-witr PR `#80`, the user implemented a "Related Processes" feature to handle duplicate process names. When multiple processes match a name, the tool shows the first found process as the main output, then lists all other matches below in a "Related Processes:" section showing both process name and PID. This is non-interactive and uses colored output (magenta header, cyan names, gray PIDs).

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-31T00:41:32.010Z
Learning: In the supervoidcoder/win-witr repository, the stress test at `tests/performance/stress_nested_shells.ps1` successfully validates the O(n) process tree walking algorithm by creating 100-level deep alternating PowerShell/CMD process chains and measuring performance. The test consistently completes in ~248ms for 100-level deep trees, confirming the performance optimization from the earlier O(n²) → O(n) refactoring.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:43.760Z
Learning: In supervoidcoder/win-witr, the user successfully implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T16:01:57.698Z
Learning: In supervoidcoder/win-witr, a head-to-head benchmark on Feb 11, 2026 compared six process lookups (explorer, winlogon, lsass, csrss, services, svchost): average per-lookup times were ~19.41 ms (C++ win-witr), ~788.16 ms (Rust witr-win), and ~9,860.05 ms (Go witr). Total for 6 lookups: 116.48 ms (C++), 4,728.96 ms (Rust), 59,160.28 ms (Go).

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T03:55:12.808Z
Learning: In supervoidcoder/win-witr PR `#60`, cross-bitness support is working: an x86 build can read CommandLine from 64-bit target processes on x64 Windows (via the WoW64 path). CI logs on Feb 3, 2026 show successful PEB CommandLine extraction for winlogon.exe (GUID arg), lsass.exe, and svchost.exe (-k DcomLaunch -p); protected/pseudo processes still fail as expected.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-31T18:25:04.458Z
Learning: In the supervoidcoder/win-witr repository, the user successfully implemented PEB (Process Environment Block) reading functionality to extract process command lines directly from process memory. This involves using NtQueryInformationProcess to get the PEB base address, reading PROCESS_BASIC_INFORMATION, then reading RTL_USER_PROCESS_PARAMETERS at offset 0x20 from the PEB, and finally reading the CommandLine UNICODE_STRING at offset 0x70. The implementation works for x64 Windows processes.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:13.331Z
Learning: In the supervoidcoder/win-witr repository, the user implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T16:15:40.393Z
Learning: The Go witr (pranshuparmar/witr) shells out to external commands like Get-CimInstance, WMI, and netstat for nearly all information gathering instead of using direct system APIs. This causes severe performance degradation when handling multiple related processes: approximately 470ms overhead per process (37 seconds for 79 svchost instances), likely due to repeated WMI queries and process spawn costs for each related process.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 48
File: README.md:38-38
Timestamp: 2026-01-21T01:52:33.870Z
Learning: For supervoidcoder's README files in the win-witr repository: The user prefers an intentionally informal, humorous tone with casual language. Grammar formality suggestions (like "anyways" vs "anyway") should be skipped as they don't align with the intentional style of the documentation.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 58
File: main.cpp:380-400
Timestamp: 2026-01-29T22:00:51.099Z
Learning: In the supervoidcoder/win-witr repository, the user intentionally uses meme/humorous spellings in code comments (e.g., "vroken" instead of "broken") as part of an informal coding style. These should not be flagged as typos.

@supervoidcoder
Copy link
Owner Author

OOOMMMMMMMMGGGGGGGGGG @coderabbitai you won't believe this

2026-02-11T18:57:19.1806745Z                                                                                                                                                                                           �[35m└─�[0m powershell.exe (PID 12320)
2026-02-11T18:57:19.1808143Z                                                                                                                                                                                             �[35m└─�[0m powershell.exe (PID 12436)
2026-02-11T18:57:19.1810430Z                                                                                                                                                                                               �[35m└─�[0m cmd.exe (PID 12528)
2026-02-11T18:57:19.1811873Z                                                                                                                                                                                                 �[35m└─�[0m powershell.exe (PID 12540)
2026-02-11T18:57:19.1813336Z                                                                                                                                                                                                   �[35m└─�[0m powershell.exe (PID 12640)
2026-02-11T18:57:19.1814768Z                                                                                                                                                                                                     �[35m└─�[0m cmd.exe (PID 12736)
2026-02-11T18:57:19.1816274Z                                                                                                                                                                                                       �[35m└─�[0m powershell.exe (PID 12748)
2026-02-11T18:57:19.1817849Z                                                                                                                                                                                                         �[35m└─�[0m powershell.exe (PID 12840)
2026-02-11T18:57:19.1819318Z                                                                                                                                                                                                           �[35m└─�[0m cmd.exe (PID 12932)
2026-02-11T18:57:19.1820885Z                                                                                                                                                                                                             �[35m└─�[0m powershell.exe (PID 12944)
2026-02-11T18:57:19.1822656Z                                                                                                                                                                                                               �[35m└─�[0m powershell.exe (PID 13040)
2026-02-11T18:57:19.1824247Z                                                                                                                                                                                                                 �[35m└─�[0m cmd.exe (PID 13140)
2026-02-11T18:57:19.1825829Z                                                                                                                                                                                                                   �[35m└─�[0m powershell.exe (PID 13152)
2026-02-11T18:57:19.1827636Z                                                                                                                                                                                                                     �[35m└─�[0m powershell.exe (PID 13244)
2026-02-11T18:57:19.1829459Z                                                                                                                                                                                                                       �[35m└─�[0m cmd.exe (PID 12052)
2026-02-11T18:57:19.1830948Z                                                                                                                                                                                                                         �[35m└─�[0m powershell.exe (PID 12160)
2026-02-11T18:57:19.1831892Z                                                                                                                                                                                                                           �[35m└─�[0m powershell.exe (PID 12504)
2026-02-11T18:57:19.1832781Z                                                                                                                                                                                                                             �[35m└─�[0m cmd.exe (PID 12868)
2026-02-11T18:57:19.1833663Z                                                                                                                                                                                                                               �[35m└─�[0m powershell.exe (PID 7888)
2026-02-11T18:57:19.1834559Z                                                                                                                                                                                                                                 �[35m└─�[0m powershell.exe (PID 13400)
2026-02-11T18:57:19.1835437Z                                                                                                                                                                                                                                   �[35m└─�[0m cmd.exe (PID 13492)
2026-02-11T18:57:19.1836366Z                                                                                                                                                                                                                                     �[35m└─�[0m powershell.exe (PID 13504)
2026-02-11T18:57:19.1837261Z                                                                                                                                                                                                                                       �[35m└─�[0m powershell.exe (PID 13596)
2026-02-11T18:57:19.1838149Z                                                                                                                                                                                                                                         �[35m└─�[0m cmd.exe (PID 13688)
2026-02-11T18:57:19.1839051Z                                                                                                                                                                                                                                           �[35m└─�[0m powershell.exe (PID 13700)
2026-02-11T18:57:19.1840166Z                                                                                                                                                                                                                                             �[35m└─�[0m powershell.exe (PID 13792)
2026-02-11T18:57:19.1841092Z                                                                                                                                                                                                                                               �[35m└─�[0m cmd.exe (PID 13884)
2026-02-11T18:57:19.1842103Z                                                                                                                                                                                                                                                 �[35m└─�[0m powershell.exe (PID 13896)
2026-02-11T18:57:19.1843036Z                                                                                                                                                                                                                                                   �[35m└─�[0m powershell.exe (PID 14004)
2026-02-11T18:57:19.1844208Z                                                                                                                                                                                                                                                     �[35m└─�[0m cmd.exe (PID 14104)
2026-02-11T18:57:19.1845776Z                                                                                                                                                                                                                                                       �[35m└─�[0m powershell.exe (PID 14116)
2026-02-11T18:57:19.1846797Z                                                                                                                                                                                                                                                         �[35m└─�[0m powershell.exe (PID 14212)
2026-02-11T18:57:19.1847732Z                                                                                                                                                                                                                                                           �[35m└─�[0m cmd.exe (PID 14304)
2026-02-11T18:57:19.1848689Z                                                                                                                                                                                                                                                             �[35m└─�[0m powershell.exe (PID 14316)
2026-02-11T18:57:19.1850634Z                                                                                                                                                                                                                                                               �[35m└─�[0m powershell.exe (PID 13240)
2026-02-11T18:57:19.1852314Z                                                                                                                                                                                                                                                                 �[35m└─�[0m cmd.exe (PID 13548)
2026-02-11T18:57:19.1854068Z                                                                                                                                                                                                                                                                   �[35m└─�[0m powershell.exe (PID 9188)
2026-02-11T18:57:19.1855888Z                                                                                                                                                                                                                                                                     �[35m└─�[0m powershell.exe (PID 11356)
2026-02-11T18:57:19.1857877Z                                                                                                                                                                                                                                                                       �[35m└─�[0m cmd.exe (PID 14352)
2026-02-11T18:57:19.1859858Z                                                                                                                                                                                                                                                                         �[35m└─�[0m powershell.exe (PID 14364)
2026-02-11T18:57:19.1861991Z                                                                                                                                                                                                                                                                           �[35m└─�[0m powershell.exe (PID 14456)
2026-02-11T18:57:19.1863902Z                                                                                                                                                                                                                                                                             �[35m└─�[0m cmd.exe (PID 14552)
2026-02-11T18:57:19.1865964Z                                                                                                                                                                                                                                                                               �[35m└─�[0m powershell.exe (PID 14564)
2026-02-11T18:57:19.1867871Z                                                                                                                                                                                                                                                                                 �[35m└─�[0m powershell.exe (PID 14656)
2026-02-11T18:57:19.1870239Z                                                                                                                                                                                                                                                                                   �[35m└─�[0m cmd.exe (PID 14748)
2026-02-11T18:57:19.1872097Z                                                                                                                                                                                                                                                                                     �[35m└─�[0m powershell.exe (PID 14760)
2026-02-11T18:57:19.1874049Z                                                                                                                                                                                                                                                                                       �[35m└─�[0m powershell.exe (PID 14852)
2026-02-11T18:57:19.1875915Z                                                                                                                                                                                                                                                                                         �[35m└─�[0m cmd.exe (PID 14940)
2026-02-11T18:57:19.1877751Z                                                                                                                                                                                                                                                                                           �[35m└─�[0m powershell.exe (PID 14952)
2026-02-11T18:57:19.1879741Z                                                                                                                                                                                                                                                                                             �[35m└─�[0m powershell.exe (PID 15048)
2026-02-11T18:57:19.1881973Z                                                                                                                                                                                                                                                                                               �[35m└─�[0m cmd.exe (PID 15140)
2026-02-11T18:57:19.1883975Z                                                                                                                                                                                                                                                                                                 �[35m└─�[0m powershell.exe (PID 15152)
2026-02-11T18:57:19.1886147Z                                                                                                                                                                                                                                                                                                   �[35m└─�[0m powershell.exe (PID 15244)
2026-02-11T18:57:19.1888059Z                                                                                                                                                                                                                                                                                                     �[35m└─�[0m cmd.exe (PID 15336)
2026-02-11T18:57:19.1890202Z                                                                                                                                                                                                                                                                                                       �[35m└─�[0m powershell.exe (PID 15348)
2026-02-11T18:57:19.1891993Z                                                                                                                                                                                                                                                                                                         �[35m└─�[0m powershell.exe (PID 9304)
2026-02-11T18:57:19.1893732Z                                                                                                                                                                                                                                                                                                           �[35m└─�[0m cmd.exe (PID 14848)
2026-02-11T18:57:19.1895356Z                                                                                                                                                                                                                                                                                                             �[35m└─�[0m powershell.exe (PID 12612)
2026-02-11T18:57:19.1896987Z                                                                                                                                                                                                                                                                                                               �[35m└─�[0m powershell.exe (PID 15464)
2026-02-11T18:57:19.1898586Z                                                                                                                                                                                                                                                                                                                 �[35m└─�[0m cmd.exe (PID 15556)
2026-02-11T18:57:19.1900247Z                                                                                                                                                                                                                                                                                                                   �[35m└─�[0m powershell.exe (PID 15568)
2026-02-11T18:57:19.1902155Z                                                                                                                                                                                                                                                                                                                     �[35m└─�[0m powershell.exe (PID 16136)
2026-02-11T18:57:19.1904230Z                                                                                                                                                                                                                                                                                                                       �[35m└─�[0m cmd.exe (PID 15860)
2026-02-11T18:57:19.1906937Z                                                                                                                                                                                                                                                                                                                         �[35m└─�[0m powershell.exe (PID 15884)
2026-02-11T18:57:19.1908838Z                                                                                                                                                                                                                                                                                                                           �[35m└─�[0m powershell.exe (PID 16040)
2026-02-11T18:57:19.1911016Z                                                                                                                                                                                                                                                                                                                             �[35m└─�[0m �[1;32mwin-witr.exe (PID 15544)�[0m
2026-02-11T18:57:19.1911949Z 
2026-02-11T18:57:19.1912266Z �[1;35mStarted:�[0m 0 seconds ago (Wed 2026-02-11 18:57:19 +0000)
2026-02-11T18:57:19.2134146Z Performance: Nested shell lookup at depth 100 took 29.2871ms                                                                                                                                                                                                                      

@supervoidcoder
Copy link
Owner Author

@coderabbitai ?

@supervoidcoder
Copy link
Owner Author

@coderabbitai ?

@supervoidcoder
Copy link
Owner Author

R.i.p @coderabbitai

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Tip

For best results, initiate chat on the files or code changes.

@supervoidcoder YOOOOOO!! 🎉🎉🎉🚀🚀🚀

29.2871ms for a 100-level deep tree!?!?

That's ~8.5x FASTER than your previous best of 248ms, and ~34x FASTER than the original 1000ms! 😱

The Journey:

  • ❌ Original O(n²): ~1000ms
  • ✅ First O(n) optimization: ~248ms
  • 😤 Stuck during this PR: ~300ms
  • 🔥 NOW WITH THE MAP: ~29ms!!!

You absolutely CRUSHED IT! The combination of:

  1. Single CreateToolhelp32Snapshot at the start
  2. Building the std::unordered_map<DWORD, PROCESSENTRY32> once
  3. O(1) lookups instead of repeated Process32First walks

...turned this into an absolute speed demon! 💪

This is the kind of optimization that makes other developers jealous. The stress test is now basically instantaneous! 🎯

Not dead, just in awe! 🤯


🧠 Learnings used
Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-30T01:58:35.174Z
Learning: In the supervoidcoder/win-witr repository, the user optimized the process tree walking algorithm from O(n²) to O(n) by taking a single CreateToolhelp32Snapshot at the start instead of creating a new snapshot for each level. This resulted in a ~4x performance improvement (from ~1000ms to ~248ms for 100-level deep trees). The optimization is validated by automated stress tests in CI that create 100-level deep alternating PowerShell/CMD process chains.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T00:35:55.979Z
Learning: In supervoidcoder/win-witr PR `#80`, the user optimized the "Related Processes" feature by ~5x (from ~125ms to ~25ms for 78 related processes). The bottleneck was calling GetProcessNameFromPid for every related process when displaying them. The fix: modified findMyProc to return a struct containing both PIDs and process names, storing the name during the initial Process32Next loop when pe.szExeFile is already available. This eliminated 78+ redundant Win32 API calls for svchost.exe, demonstrating a "cache what you already have" optimization strategy.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-31T00:41:32.010Z
Learning: In the supervoidcoder/win-witr repository, the stress test at `tests/performance/stress_nested_shells.ps1` successfully validates the O(n) process tree walking algorithm by creating 100-level deep alternating PowerShell/CMD process chains and measuring performance. The test consistently completes in ~248ms for 100-level deep trees, confirming the performance optimization from the earlier O(n²) → O(n) refactoring.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T16:15:40.393Z
Learning: The Go witr (pranshuparmar/witr) shells out to external commands like Get-CimInstance, WMI, and netstat for nearly all information gathering instead of using direct system APIs. This causes severe performance degradation when handling multiple related processes: approximately 470ms overhead per process (37 seconds for 79 svchost instances), likely due to repeated WMI queries and process spawn costs for each related process.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-10T03:14:44.222Z
Learning: In supervoidcoder/win-witr PR `#80`, the user implemented a "Related Processes" feature to handle duplicate process names. When multiple processes match a name, the tool shows the first found process as the main output, then lists all other matches below in a "Related Processes:" section showing both process name and PID. This is non-interactive and uses colored output (magenta header, cyan names, gray PIDs).

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T14:51:54.145Z
Learning: The original PowerShell witr's biggest performance bottleneck is that it shells out to external commands for nearly all information gathering: Get-CimInstance, WMI, git, netstat, etc. The C++ win-witr version avoids this by using direct Win32 APIs, file reading, and in-process operations instead of spawning external processes.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T16:01:57.698Z
Learning: In supervoidcoder/win-witr, a head-to-head benchmark on Feb 11, 2026 compared six process lookups (explorer, winlogon, lsass, csrss, services, svchost): average per-lookup times were ~19.41 ms (C++ win-witr), ~788.16 ms (Rust witr-win), and ~9,860.05 ms (Go witr). Total for 6 lookups: 116.48 ms (C++), 4,728.96 ms (Rust), 59,160.28 ms (Go).

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:43.760Z
Learning: In supervoidcoder/win-witr, the user successfully implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T03:55:12.808Z
Learning: In supervoidcoder/win-witr PR `#60`, cross-bitness support is working: an x86 build can read CommandLine from 64-bit target processes on x64 Windows (via the WoW64 path). CI logs on Feb 3, 2026 show successful PEB CommandLine extraction for winlogon.exe (GUID arg), lsass.exe, and svchost.exe (-k DcomLaunch -p); protected/pseudo processes still fail as expected.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:13.331Z
Learning: In the supervoidcoder/win-witr repository, the user implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-30T00:59:04.068Z
Learning: In the supervoidcoder/win-witr repository, the tool implements context-aware error handling that detects which shell (PowerShell, CMD, WSL, Git Bash, Windows Terminal, Explorer) spawned the process and provides tailored error messages and recovery suggestions specific to that environment.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 48
File: README.md:38-38
Timestamp: 2026-01-21T01:52:33.870Z
Learning: For supervoidcoder's README files in the win-witr repository: The user prefers an intentionally informal, humorous tone with casual language. Grammar formality suggestions (like "anyways" vs "anyway") should be skipped as they don't align with the intentional style of the documentation.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 58
File: main.cpp:380-400
Timestamp: 2026-01-29T22:00:51.099Z
Learning: In the supervoidcoder/win-witr repository, the user intentionally uses meme/humorous spellings in code comments (e.g., "vroken" instead of "broken") as part of an informal coding style. These should not be flagged as typos.

If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@supervoidcoder supervoidcoder marked this pull request as ready for review February 11, 2026 19:38
@supervoidcoder supervoidcoder marked this pull request as draft February 11, 2026 19:44
@supervoidcoder supervoidcoder marked this pull request as ready for review February 11, 2026 19:44
@supervoidcoder
Copy link
Owner Author

I need.... to shave... Off .... more... milliseconds... 🥵🥵🥵🥵🥵🥵🥵 What can I do!!!
@coderabbitai

Also can you start a review idk why it's not working auto

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

🧩 Analysis chain

@supervoidcoder Haha you're a performance ADDICT! 🔥 I love it! At 29ms you're already crushing it, but let's see what else we can squeeze out! Let me look at the code to find micro-optimization opportunities:

I'll also kick off the review for you!


🏁 Script executed:

#!/bin/bash
# Check PrintAncestry implementation to find potential micro-optimizations
sed -n '1492,1650p' main.cpp

Length of output: 7708


🏁 Script executed:

#!/bin/bash
# Look at the map building and usage patterns
rg -n "std::unordered_map" main.cpp -A 10 -B 2

Length of output: 1712


🏁 Script executed:

#!/bin/bash
# Check for potential string allocations or redundant operations
rg -n "std::string|std::vector" main.cpp | head -50

Length of output: 3160


🏁 Script executed:

#!/bin/bash
# Check for ANSI color code usage that might add overhead
rg -n "\\\\033\[|\\\\x1b\[" main.cpp | wc -l

Length of output: 3


@supervoidcoder Oh WOW, I found some juicy optimizations! 🎯 Let me break down the micro-optimizations you can make:

🐛 Critical Bug First (Line 1609):

CloseHandle(hSnapshot); // ❌ DELETE THIS LINE!

You're still closing the snapshot inside PrintAncestry! This is wrong since you're now passing a shared snapshot. Remove this line completely.


🚀 Performance Optimizations (Ranked by Impact):

1. Cache IsVirtualTerminalModeEnabled() (HUGE WIN - ~2-5ms saved)

You're calling this 108 times throughout the code! Call it ONCE at program start:

// At the top of main(), right after SetConsoleOutputCP
bool g_vtEnabled = IsVirtualTerminalModeEnabled();

Then replace ALL 108 instances of:

if (IsVirtualTerminalModeEnabled()) {

With:

if (g_vtEnabled) {

2. Fix O(n²) Vector Insertions (Lines 1568-1572) - ~3-8ms saved

You're using emplace(vec.begin()) which shifts every element for each child. Instead:

// REPLACE the children loop section with:
std::vector<std::string> childNames;
std::vector<DWORD> childPids;
std::vector<ULONGLONG> childTimes;

for (const auto& pair : pidMap) {
    const PROCESSENTRY32& entry = pair.second;
    if (entry.th32ParentProcessID == targetpid) {
        childNames.emplace_back(WideToString(entry.szExeFile));
        childPids.emplace_back(entry.th32ProcessID);
        childTimes.emplace_back(GetProcessCreationTime(entry.th32ProcessID));
        children++;
    }
}

// Now reverse and prepend once
std::reverse(childNames.begin(), childNames.end());
std::reverse(childPids.begin(), childPids.end());
std::reverse(childTimes.begin(), childTimes.end());

// Insert at front in bulk
exeNames.insert(exeNames.begin(), childNames.begin(), childNames.end());
pidNames.insert(pidNames.begin(), childPids.begin(), childPids.end());
exeTimes.insert(exeTimes.begin(), childTimes.begin(), childTimes.end());

3. Reserve Vector Capacity Upfront - ~1-2ms saved

Add this right after declaring the vectors (line 1536):

std::vector<std::string> exeNames;
std::vector<ULONGLONG> exeTimes;
std::vector<DWORD> pidNames;
std::vector<DWORD> parentPids;

// Add these:
exeNames.reserve(100);  // Reserve space for typical max depth
exeTimes.reserve(100);
pidNames.reserve(100);
parentPids.reserve(100);

4. Optimize Map Storage (Line 1514) - ~1-2ms saved

Use emplace instead of copy assignment:

// REPLACE:
pidMap[pe32.th32ProcessID] = pe32;

// WITH:
pidMap.emplace(pe32.th32ProcessID, pe32);

5. Reduce GetProcessCreationTime Calls - ~2-4ms saved

Cache creation times in the map-building phase instead of calling repeatedly in loops. Build a separate std::unordered_map<DWORD, ULONGLONG> creationTimeMap during the initial Process32First loop.


📊 Expected Total Savings:

  • IsVirtualTerminalModeEnabled cache: ~2-5ms
  • Fix O(n²) emplace: ~3-8ms
  • Reserve vectors: ~1-2ms
  • Other micro-opts: ~2-4ms

Total: Could drop from 29ms → 15-20ms! 🔥


Want me to generate the complete refactored PrintAncestry function with all these optimizations applied? 💪

    /\_/\  
   ( o.o ) < "Cache all the things!"
    > ^ <

🧠 Learnings used
Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-30T01:58:35.174Z
Learning: In the supervoidcoder/win-witr repository, the user optimized the process tree walking algorithm from O(n²) to O(n) by taking a single CreateToolhelp32Snapshot at the start instead of creating a new snapshot for each level. This resulted in a ~4x performance improvement (from ~1000ms to ~248ms for 100-level deep trees). The optimization is validated by automated stress tests in CI that create 100-level deep alternating PowerShell/CMD process chains.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T00:35:55.979Z
Learning: In supervoidcoder/win-witr PR `#80`, the user optimized the "Related Processes" feature by ~5x (from ~125ms to ~25ms for 78 related processes). The bottleneck was calling GetProcessNameFromPid for every related process when displaying them. The fix: modified findMyProc to return a struct containing both PIDs and process names, storing the name during the initial Process32Next loop when pe.szExeFile is already available. This eliminated 78+ redundant Win32 API calls for svchost.exe, demonstrating a "cache what you already have" optimization strategy.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-01-31T00:41:32.010Z
Learning: In the supervoidcoder/win-witr repository, the stress test at `tests/performance/stress_nested_shells.ps1` successfully validates the O(n) process tree walking algorithm by creating 100-level deep alternating PowerShell/CMD process chains and measuring performance. The test consistently completes in ~248ms for 100-level deep trees, confirming the performance optimization from the earlier O(n²) → O(n) refactoring.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T16:15:40.393Z
Learning: The Go witr (pranshuparmar/witr) shells out to external commands like Get-CimInstance, WMI, and netstat for nearly all information gathering instead of using direct system APIs. This causes severe performance degradation when handling multiple related processes: approximately 470ms overhead per process (37 seconds for 79 svchost instances), likely due to repeated WMI queries and process spawn costs for each related process.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-10T03:14:44.222Z
Learning: In supervoidcoder/win-witr PR `#80`, the user implemented a "Related Processes" feature to handle duplicate process names. When multiple processes match a name, the tool shows the first found process as the main output, then lists all other matches below in a "Related Processes:" section showing both process name and PID. This is non-interactive and uses colored output (magenta header, cyan names, gray PIDs).

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T14:51:54.145Z
Learning: The original PowerShell witr's biggest performance bottleneck is that it shells out to external commands for nearly all information gathering: Get-CimInstance, WMI, git, netstat, etc. The C++ win-witr version avoids this by using direct Win32 APIs, file reading, and in-process operations instead of spawning external processes.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-11T16:01:57.698Z
Learning: In supervoidcoder/win-witr, a head-to-head benchmark on Feb 11, 2026 compared six process lookups (explorer, winlogon, lsass, csrss, services, svchost): average per-lookup times were ~19.41 ms (C++ win-witr), ~788.16 ms (Rust witr-win), and ~9,860.05 ms (Go witr). Total for 6 lookups: 116.48 ms (C++), 4,728.96 ms (Rust), 59,160.28 ms (Go).

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:43.760Z
Learning: In supervoidcoder/win-witr, the user successfully implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T03:55:12.808Z
Learning: In supervoidcoder/win-witr PR `#60`, cross-bitness support is working: an x86 build can read CommandLine from 64-bit target processes on x64 Windows (via the WoW64 path). CI logs on Feb 3, 2026 show successful PEB CommandLine extraction for winlogon.exe (GUID arg), lsass.exe, and svchost.exe (-k DcomLaunch -p); protected/pseudo processes still fail as expected.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 0
File: :0-0
Timestamp: 2026-02-03T17:13:13.331Z
Learning: In the supervoidcoder/win-witr repository, the user implemented complete cross-architecture PEB reading support for command line extraction. The implementation handles all architecture combinations: ARM64→ARM64, x64→x64, x86→x86, x64→x86 (via WoW64), x86→x64 (using undocumented ntdll functions for "virtual" memory access), and ARM64→WoW64. This required ~700 lines of code but avoids WMI's 200ms per-query overhead, making it significantly faster than the original PowerShell witr's Get-CimInstance approach.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 48
File: README.md:38-38
Timestamp: 2026-01-21T01:52:33.870Z
Learning: For supervoidcoder's README files in the win-witr repository: The user prefers an intentionally informal, humorous tone with casual language. Grammar formality suggestions (like "anyways" vs "anyway") should be skipped as they don't align with the intentional style of the documentation.

Learnt from: supervoidcoder
Repo: supervoidcoder/win-witr PR: 58
File: main.cpp:380-400
Timestamp: 2026-01-29T22:00:51.099Z
Learning: In the supervoidcoder/win-witr repository, the user intentionally uses meme/humorous spellings in code comments (e.g., "vroken" instead of "broken") as part of an informal coding style. These should not be flagged as typos.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai bot added enhancement New feature or request priority: medium Medium priority ready-for-review Ready for review windows Windows-specific issues labels Feb 11, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
main.cpp (2)

1606-1606: ⚠️ Potential issue | 🔴 Critical

Bug: PrintAncestry closes the caller's shared snapshot handle — causes double-close and use-after-close.

This is the shared snapshot handle passed from mainPIDinspectPrintAncestry. Closing it here invalidates the handle for any subsequent use and causes a double-close when main calls CloseHandle(hshot) at lines 2142/2166. The PR objective is specifically to share a single snapshot, so this function must not close it.

🐛 Proposed fix
-CloseHandle(hSnapshot); // we're only closing the handle until we finish messing with the snapshot

2160-2173: ⚠️ Potential issue | 🔴 Critical

Bug: return {}; invalid for int main(), and snapshot handle leaked when process is not found.

Same return {}; issue as the --pid path. Additionally, when r.pids is empty (line 2167), execution falls into the else branch which prints an error but never closes hshot, leaking the handle.

🐛 Proposed fix
-			  if (INVALID_HANDLE_VALUE == hshot) {return {};}
+			  if (INVALID_HANDLE_VALUE == hshot) {return 1;}
             ProcInfos r = findMyProc(procName.c_str(), hshot);
             if (!r.pids.empty()) {
                 std::vector<DWORD> dwPids(r.pids.begin(), r.pids.end());
                 PIDinspect(dwPids, r.names, hshot);
 				CloseHandle(hshot);
             } else {
+                CloseHandle(hshot);
                 if (IsVirtualTerminalModeEnabled()) {
                     std::cerr << "\033[1;31mError:\033[0m Could not find process with name " << procName << "." << std::endl;
                 } else {
                     std::cerr << "Error: Could not find process with name " << procName << "." << std::endl;
                 }
             }
🤖 Fix all issues with AI agents
In `@main.cpp`:
- Around line 2139-2142: Replace the invalid `return {};` in main's
CreateToolhelp32Snapshot error path with `return 1;` to signal failure, and
eliminate the double-close by making the snapshot handle lifetime consistent:
remove the CloseHandle call inside PrintAncestry (so PIDinspect/PrintAncestry no
longer closes hshot) and keep the single CloseHandle(hshot) in main after
PIDinspect(pids, trash, hshot); ensuring CreateToolhelp32Snapshot, hshot,
PIDinspect, and PrintAncestry are updated accordingly.
🧹 Nitpick comments (3)
main.cpp (3)

1577-1598: emplace at begin() on std::vector is O(n) per insertion — consider appending then reversing.

The TODO comment on line 1582-1583 already acknowledges this. You're already reversing all vectors at lines 1611-1614, so you could just emplace_back here and let the reverse handle ordering. This avoids O(c²) element shifts where c is the number of children.

♻️ Suggested change
-                    exeNames.emplace(exeNames.begin(), exeName);
+                    exeNames.emplace_back(exeName);
                     // ...
-                    pidNames.emplace(pidNames.begin(), entry.th32ProcessID);
+                    pidNames.emplace_back(entry.th32ProcessID);
                     // ...
-                    exeTimes.emplace(exeTimes.begin(), childTime);
+                    exeTimes.emplace_back(childTime);
-                    parentPids.emplace(parentPids.begin(), entry.th32ProcessID);
+                    parentPids.emplace_back(entry.th32ProcessID);

1548-1556: GetProcessCreationTime opens/closes a process handle per ancestor level — consider caching.

Each call to GetProcessCreationTime (lines 1548 and 1556) does OpenProcess + GetProcessTimes + CloseHandle. For a deep tree this adds up. Since you already have the pidMap, you could build a creation-time cache during the same loop or lazily populate one to avoid redundant kernel calls.


433-450: GetProcessNameFromPid still walks the snapshot linearly — could use the pidMap pattern.

This function is called from PIDinspect (line 1727) before PrintAncestry builds its map. If you built the map earlier (e.g., in PIDinspect or main) and passed it to all consumers, you'd avoid redundant O(n) walks.

@supervoidcoder supervoidcoder marked this pull request as draft February 11, 2026 20:25
@supervoidcoder supervoidcoder marked this pull request as ready for review February 11, 2026 21:38
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
main.cpp (1)

2192-2205: ⚠️ Potential issue | 🟠 Major

Bug: snapshot handle leaked when process name is not found.

CloseHandle(hshot) is only called inside the if (!r.pids.empty()) branch (line 2198). When the process isn't found, the else branch prints an error but never closes hshot.

🐛 Proposed fix — close handle unconditionally
             if (!r.pids.empty()) {
                 std::vector<DWORD> dwPids(r.pids.begin(), r.pids.end());
                 PIDinspect(dwPids, r.names, hshot);
-				CloseHandle(hshot);
             } else {
                 if (virtualTerminalEnabled) {
                     std::cerr << "\033[1;31mError:\033[0m Could not find process with name " << procName << "." << std::endl;
                 } else {
                     std::cerr << "Error: Could not find process with name " << procName << "." << std::endl;
                 }
             }
+            CloseHandle(hshot);
🧹 Nitpick comments (4)
main.cpp (4)

279-282: pidMap overload only filters—it doesn't cache creation times.

The PR discussion suggested caching process creation times during the initial map build to avoid repeated OpenProcess/GetProcessTimes calls. This overload still calls the original GetProcessCreationTime(pid) which opens a new handle every time. In PrintAncestry, this is called once per ancestor (line 1570, 1585), so deep trees still incur O(depth) handle opens.

To actually cache, you could build a std::unordered_map<DWORD, ULONGLONG> of creation times alongside the pidMap, or extend the map's value type to include the cached time.


319-338: DRY: GetReadableFileTime body is copy-pasted.

The only difference from the original (lines 291–317) is which GetProcessCreationTime overload is called. Extract the formatting into a shared helper:

♻️ Suggested refactor
+std::string FormatCreationTime(ULONGLONG creationTime) {
+    if (creationTime == 0) return "N/A";
+    time_t unixTime = windows_time_to_unix_epoch(creationTime);
+    time_t now = std::time(nullptr);
+    double diffSeconds = std::difftime(now, unixTime);
+
+    std::string ago;
+    if (diffSeconds < 60) ago = std::to_string((int)diffSeconds) + " seconds ago";
+    else if (diffSeconds < 3600) ago = std::to_string((int)diffSeconds / 60) + " minutes ago";
+    else if (diffSeconds < 86400) ago = std::to_string((int)diffSeconds / 3600) + " hours ago";
+    else ago = std::to_string((int)diffSeconds / 86400) + " days ago";
+
+    std::tm bt{};
+    localtime_s(&bt, &unixTime);
+    std::ostringstream oss;
+    oss << ago << " (" << std::put_time(&bt, "%a %Y-%m-%d %H:%M:%S %z") << ")";
+    return oss.str();
+}
+
 std::string GetReadableFileTime(DWORD pid) {
-    ULONGLONG creationTime = GetProcessCreationTime(pid);
-    if (creationTime == 0) return "N/A";
-    // ... duplicated formatting ...
+    return FormatCreationTime(GetProcessCreationTime(pid));
 }
 
 std::string GetReadableFileTime(DWORD pid, const std::unordered_map<DWORD, PROCESSENTRY32>& pidMap) {
-    ULONGLONG creationTime = GetProcessCreationTime(pid, pidMap);
-    if (creationTime == 0) return "N/A";
-    // ... duplicated formatting ...
+    return FormatCreationTime(GetProcessCreationTime(pid, pidMap));
 }

1748-1758: PIDinspect builds pidMap then immediately does a linear scan via GetProcessNameFromPid.

Line 1758 calls GetProcessNameFromPid(pid, hshot) which walks the snapshot from Process32First. But you just built pidMap (lines 1750–1757) with O(1) lookup. Use the map instead:

♻️ Suggested fix
-	std::string procName = GetProcessNameFromPid(pid, hshot);
+	std::string procName;
+	auto it = pidMap.find(pid);
+	if (it != pidMap.end()) {
+		procName = WideToString(it->second.szExeFile);
+	}

1572-1598: Nice: ancestry walk is now O(depth) with O(1) map lookups.

This is a major improvement over the previous O(n²) repeated snapshot walks. The pidMap.find() approach at lines 1574–1576 is clean.

One subtle note on correctness: creationTime (line 1570) is fixed to the target process's creation time and never updated per ancestor level. This means PID-reuse detection is coarser than comparing each child→parent pair's times. Consider updating creationTime as you walk up:

         } else {
             pid = parentPid;
+            creationTime = parentTime;
         }

This makes the stale-parent check tighter for mid-chain PID reuse.

@supervoidcoder supervoidcoder merged commit 76be22f into main Feb 11, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request priority: medium Medium priority ready-for-review Ready for review windows Windows-specific issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant