Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AutoCAD / RealDWG Memory Leak Instrumentation Skill

Install as a Claude Code Plugin

/plugin marketplace add https://github.com/ADN-DevTech/acad-memory-leak-skill.git
/plugin install acad-memory-leak@acad-memory-leak-skill
/reload-plugins

Verify with /plugin list. Once installed, the skill auto-triggers on prompts like "check for memory leak", "detect memory leak in AutoCAD", or "validate memory leak fix" (see SKILL.md for the full trigger list).


What This Is

A collection of instrumentation scripts and templates for validating memory leaks in AutoCAD or RealDWG C++ projects using real measurement data.

This skill was developed during the investigation of ACD-58279 (AcDbMText::text() GDI handle leak in RealDWG 27.0) and captures the exact toolchain used to confirm the bug and verify the fix.


Key Concepts

leaktest.exe — the repro executable

leaktest.exe is not a general tool. It is the reproduction executable built from the repro project (realdwg-mtext-text-leak). Its only job is to reproduce a known leak in a tight, measurable loop so instrumentation tools can observe it.

When adapting this skill to a new leak:

  • Build your own repro executable (or ARX plugin — see arx/) that triggers the suspected leaking code path in a loop.
  • Feed that exe path to the scripts in scripts/ in place of leaktest.exe.

Role of AI in This Workflow

This skill is about AI-assisted instrumentation, not just running scripts:

  1. Hypothesize — AI reads the symptom (Private Bytes grow ~0.9 MB/call) and narrows suspect components (Win32FontHandle, GDI pool).
  2. Instrument — scripts capture Private Bytes, ETW stacks, memory region snapshots.
  3. Validate — AI interprets results: is growth linear with iterations? which DLL tops the outstanding allocation stack?
  4. Verify fix — re-run same scripts against patched DLL; compare first/last MB.

Symbol Server

Symbols resolve Autodesk DLL stack frames (e.g. acdb26.dll!AcFontManager::getFontMetrics) to function names in WPA. Without them, WPA shows raw addresses — you can still see which DLL is allocating (by address range) but not the exact function.

Audience Symbol path
Autodesk internal srv*C:\symbols*http://<internal-server>/symbols
Public / external srv*C:\symbols*https://symbols.autodesk.com

If https://symbols.autodesk.com returns no symbols for your build: Autodesk may not yet have published stripped PDBs for that release. This skill is still useful — it confirms the leak exists, sizes it, and identifies the Autodesk DLL by address range. To get full stack resolution:

Raise a support ticket at https://aps.autodesk.com/get-help and attach the memory leak evidence (Private Bytes CSV + ETL or WPA screenshot). Include the exact DLL version (Get-Item acdb26.dll | Select VersionInfo). Autodesk support can reproduce internally with full symbols and identify the leaking call site.


Prerequisites

Tool Purpose Where
Windows Performance Toolkit wpr.exe, wpa.exe for ETW traces Windows SDK installer
Windows Debugging Tools gflags.exe for UST Windows SDK installer
xperf.exe Legacy heap+kernel trace Part of WPT
Python 3 + matplotlib Chart generation (plot_leak.py) pip install matplotlib
Admin PowerShell ETW and xperf require elevation

Configuration

Edit config.ps1 first — set paths for your environment:

# RealDWG target
$REALDWG_ROOT = "D:\RealDWG\RD27\RealDWG 2027"   # <-- PLACEHOLDER
$REALDWG_EXE  = "$REALDWG_ROOT\leaktest.exe"      # your repro exe

# AutoCAD target
$ACAD_EXE     = "C:\Program Files\Autodesk\AutoCAD 2027\acad.exe"  # <-- PLACEHOLDER
$ARX_PLUGIN   = "D:\dev\MyLeakRepro\x64\Release\MyLeakRepro.arx"   # <-- PLACEHOLDER

Instrumentation Workflow

Level 1 — Quick memory metering (no elevation)

Best first step. Measures Private Bytes every 200 ms. Confirms leak exists and sizes it.

# Set pauses so poller captures baseline + peak
$env:PAUSE_BEFORE_MS = "3000"
$env:PAUSE_AFTER_MS  = "5000"

.\scripts\run_with_metering.ps1 `
    -ExePath "D:\RealDWG\RD27\RealDWG 2027\leaktest.exe" `
    -Iterations 50 -Mode writeread -Tag leak -OutDir .\evidence

Interpret output:

First Private MB:  10        <- baseline (before loop)
Peak  Private MB:  90        <- worst-case
Last  Private MB:  88        <- still held at exit = leak confirmed

If Last ~= First → no leak. If Last >> First → leak confirmed.

Run twice: once with leaking code, once with control (no-op or fixed). Compare.


Level 2 — xperf heap trace (interactive, elevation required)

Good when you need heap stack trace and can interactively control start/stop.

REM As Administrator:
memxperfex.bat <PID>
REM Exercise the target, then press any key.
REM Opens combined.etl in WPA automatically.

WPA: Memory → Heap Allocations Outstanding → Outstanding Heap Allocations by Stack Sort by Size descending. Top Autodesk frame = leaking site.


Level 3 — ETW/WPA automated trace (elevation required)

Wraps WPR + process launch + Private Bytes metering in one script. Captures VirtualAlloc stacks — finds non-heap pool allocator leaks.

# As Administrator:
.\scripts\run_with_wpa.ps1 `
    -ExePath "D:\RealDWG\RD27\RealDWG 2027\leaktest.exe" `
    -Iterations 10 -Mode writeread -Tag leak_etw -OutDir .\evidence `
    -AcadSymSrv -OpenWpa

WPA analysis:

  1. Memory → VirtualAlloc Commit Lifetime → Outstanding Commits by Stack
  2. Memory → Heap Allocations Outstanding → Outstanding Heap Allocations by Stack
  3. Filter Process = leaktest.exe, sort Size descending
  4. Top frame inside acdb*.dll / acpal.dll = allocator call site

Level 4 — Memory region snapshot (before / after)

Distinguishes heap leak vs VirtualAlloc pool leak. Take two snapshots bracketing the test loop, compare CSVs.

# 1. Start process (ensure PAUSE_BEFORE_MS is set so it doesn't exit)
# 2. Note PID from Task Manager or stdout
.\scripts\dump_regions.ps1 -ProcId <PID> -Tag before -OutDir .\evidence
# 3. Trigger leak iterations
.\scripts\dump_regions.ps1 -ProcId <PID> -Tag after  -OutDir .\evidence
# 4. Compare regions_before.csv vs regions_after.csv:
#    New large "Private" AllocBase entries = leaked pool region.

Visualize results

python scripts/plot_leak.py \
    --leak    evidence/run_leak.csv \
    --control evidence/run_fixed.csv \
    --out     evidence/compare.png \
    --title   "AcDbMText::text() — before vs after fix"

AutoCAD (ARX) Approach

Use when the leaking API is only reachable from inside a live AutoCAD session (not available in RealDWG standalone).

  1. Build templates/arx/leak_repro_arx.cpp as an ObjectARX plugin. Replace <ACAD_SDK_ROOT> in project properties with your ObjectARX SDK path.

  2. Load in AutoCAD:

    APPLOAD -> select MyLeakRepro.arx
    

    Or via script:

    (command "APPLOAD" "D:\\dev\\MyLeakRepro\\x64\\Release\\MyLeakRepro.arx")
    (command "LEAKTEST")
    
  3. Measure acad.exe memory externally:

    # Find acad.exe PID first
    $pid = (Get-Process acad).Id
    
    # Option A: snapshot regions before/after LEAKTEST command
    .\scripts\dump_regions.ps1 -ProcId $pid -Tag before -OutDir .\evidence
    # (run LEAKTEST in AutoCAD)
    .\scripts\dump_regions.ps1 -ProcId $pid -Tag after  -OutDir .\evidence
    
    # Option B: xperf heap trace (admin) — attach to acad.exe PID
    memxperfex.bat $pid
  4. For ETW trace wrapping acad.exe launch:

    .\scripts\run_with_wpa.ps1 `
        -ExePath "C:\Program Files\Autodesk\AutoCAD 2027\acad.exe" `
        -AcadScript "D:\dev\MyLeakRepro\run_leak.scr" `
        -Tag acad_leak -OutDir .\evidence -AcadSymSrv -OpenWpa

Verification Checklist (before / after fix)

Step Command Pass condition
1. Confirm leak run_with_metering.ps1 -Tag leak Last MB >> First MB
2. Apply fix Replace patched DLL
3. Confirm fix run_with_metering.ps1 -Tag fixed Last MB ≈ First MB
4. Visualize plot_leak.py --leak ... --control ... Fixed line is flat
5. ETL confirm run_with_wpa.ps1 -Tag fixed_etw No outstanding allocs in WPA

Example Repro Project (templates/example/)

templates/example/ contains a real repro project used to find and verify ACD-58279 (AcDbMText::text() GDI handle leak, RealDWG 27.0).

File Purpose
templates/example/leaktest.cpp Minimal C++ repro exe — 5 test modes, env-var controls, ~350 lines
templates/example/leaktest.vcxproj VS 2022 project, $(REALDWG_SDK) placeholder for SDK path

What a good repro project looks like

  • Single exe, one leaking call isolated — loop calls the suspect API N times, nothing else
  • Modesshared / newentity / newdb / readfile / writeread let you bisect which code path leaks
  • Env-var controlsITERATIONS, CONTENT_REPEATS, CONTENT_PLAIN, USE_RTF — no recompile to vary parameters
  • USE_RTF negative control — swap the leaking call for an equivalent non-leaking call to confirm the repro is not measuring noise
  • PAUSE_BEFORE_MS / PAUSE_AFTER_MS — pause before/after the loop so the metering script captures baseline and peak

Build

set REALDWG_SDK=D:\RealDWG\RD27\RealDWG 2027
msbuild example\leaktest.vcxproj /p:Configuration=Release /p:Platform=x64

Output: %REALDWG_SDK%\leaktest.exe. Copy to the same folder as acdb26.dll.


Real-World Example: ACD-58279

Run Iter First MB Peak MB Last MB
Leaked (acpal.dll original) 300 10.3 425+ 425+
Fixed (patched acpal.dll) 50 7.3 13.9 10.7

Root cause: Win32FontHandle destructor in PAL/Win32/font_utilities.cpp created HFONT via CreateFontIndirect() but never called DeleteObject(). Every call to AcDbMText::text() on a file-loaded entity orphaned 1–2 GDI kernel objects.

Fix: Deselect font (SelectObjectSYSTEM_FONT), then DeleteObject(mWin32Font) in destructor. Add releaseFont() for ownership transfer to HT_Font_Descriptor cache.


File Layout

acad-memory-leak-skill\
├── .claude-plugin\
│   ├── plugin.json              Claude Code plugin manifest
│   └── marketplace.json         Marketplace listing (single-plugin repo)
├── README.md                    this file
├── SKILL.md                     Claude Code skill — triggers + quick start
├── config.ps1                   path configuration (edit before use)
├── core\
│   ├── workflow.md              full instrumentation workflow + troubleshooting
│   └── output-format.md         how to interpret and present results
├── scripts\
│   ├── run_with_metering.ps1    Level 1: Private Bytes metering, no elevation
│   ├── memxperfex.bat           Level 2: xperf heap trace, interactive
│   ├── run_with_wpa.ps1         Level 3: ETW/WPA automated trace, elevation
│   ├── dump_regions.ps1         Level 4: VirtualQueryEx region snapshot
│   └── plot_leak.py             Chart: leak vs control/fixed curve
└── templates\
    ├── example\
    │   ├── leaktest.cpp         Real repro exe (ACD-58279, RealDWG 27.0)
    │   └── leaktest.vcxproj     VS 2022 project — set $(REALDWG_SDK) before building
    └── arx\
        └── leak_repro_arx.cpp   AutoCAD ARX plugin template

Credits

Built with Claude Skill Creator. Verified by a human on a real leak (ACD-58279).

About

AutoCAD / RealDWG memory leak instrumentation — measure, trace, and verify GDI & heap leaks in C++ plugins using ETW, WPA, and Private Bytes metering.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages