Repository navigation
v3.3.0
What's changed
A full technical review of the project — library, platform backends, MCP server, app and CI — re-verified finding by finding. The headline fixes: generators that could keep using a released handle after close() (on Windows, possibly reading another process), a Linux crash that one oddly named process could trigger for every caller, and an MCP server whose self-protection missed the client that launched it under uvx. No public default changed; every fix comes with a test.
Fixed
- Scan and listing generators are bound to their process object. They captured the raw handle or task port and checked it only when created; after
p.close(), Windows can hand the same handle value to the nextOpenProcess, so a kept generator could read a different process. Resuming one afterclose()now raisesClosedProcess(#111) - Linux: non-UTF-8 names no longer break listings.
/proc/*/command/proc/<pid>/mapswere read in strict text mode, so a single process with a non-UTF-8 name (any process can set one) brokeOpenProcess(name=...)for everyone, and a non-UTF-8 mapped path broke scans of that target. They are decoded with replacement characters (#111) - Scan arguments are validated when the method is called —
search_by_value(int, value=2**40)or a malformed pattern raises immediately instead of on the firstnext()(#111) - Typed writes:
write_uint*truncated floats silently (write_uint(a, 3.7)wrote 3) and now raisesTypeErrorlikewrite_int; out-of-range NumPy integers are range-checked instead of wrapped;OpenProcess(pid=True)is rejected (#111) - Pattern and pointer scans: variable-width regexes no longer report a match twice across a chunk boundary; chunk overlaps no longer read past the end of a region; the unaligned pointer map finds pointers that straddle a chunk; intersecting pointer scans keeps 32- and 64-bit paths apart (#111)
resolve_pointer_chainraisesValueError— also anOSError, as before — for a hop outside the 64-bit address space instead of reading a silently wrapped address (#111)- Windows: a short read no longer leaves a zero-filled tail that could match a scan for 0;
get_modulesretries onERROR_BAD_LENGTHand raisesProcessIDNotExistsErrorfor an exited target; long mapped-file names are no longer truncated (#111) - macOS: writing to a protected page no longer leaves
WRITEin the page's maximum protection;close()reports a failed port release;get_modulesraisesProcessIDNotExistsErrorfor an exited target; the region walk no longer wraps or stops at a zero-size region (#111) - App: finished scan workers and closed tool dialogs are freed instead of accumulating; cancelling or failing a first scan no longer starts an automatic refresh; promoting results and refining large result sets are linear instead of quadratic (a 200k-row refine went from 18.7 s to 0.7 s); an inline edit on a frozen row is no longer overwritten by the old value, and one against an exited target is reverted with a message; pointer-scan Stop says it stopped, its results have back-pressure, and Compare no longer resolves a path through the previous run's base when its module is not loaded (#111)
- MCP:
bufflength="0"means "use the default" as documented;read_value/write_valueecho the normalized value type; a single huge region no longer overruns the scan deadline (#111)
Changed
- MCP: the whole launch chain is protected. Self-protection covered only the server and its parent — under
uvxthat isuv, leaving the MCP client attachable. Every ancestor is now refused, which also includes the shell or terminal the server was started from (#111) - MCP: approvals are scoped more tightly. Remembering an approval for a shared runtime (
python3,node, shells, …) covers only that running process (reported asapproval_scope), and a pid reused while the prompt is open is refused; a process whose name cannot be read always asks, even with--allow-any-process; more password managers are denied, and browsers and AI clients are flaggedsensitive(#111) - MCP: responses are size-capped. Text values of
str/bytesscans share a budget per response, reported through additive*_truncatedfields, and tool descriptions mark memory contents as untrusted (#111) - Faster with NumPy: pointer-map building (about 5x) and integer
NOT_EXACTscans use the vectorized path when NumPy is installed (#111) - Packaging:
psutil7.x is accepted (<8);PySide6is capped below 7 (#111)
Added
--confirm-writesfor the MCP server: it asks the user before everywrite_valuethrough an elicitation prompt — for clients that do not honour the per-tool confirmation hint. Off by default (#111)prepare_search_targetinPyMemoryEditor.utilto validate scan arguments up front (#111)- CI: CodeQL analysis; releases require a green test run on the release commit and build separately from the PyPI upload; macOS is tested on Python 3.10, 3.12 and 3.14; mypy checks each platform; the dependency audit covers only the extras and blocks on
main(#111)
Install
pip install --upgrade PyMemoryEditor📖 Full documentation: pymemoryeditor.readthedocs.io · MCP guide: pymemoryeditor.readthedocs.io/en/latest/mcp.html
Full Changelog: v3.2.0...v3.3.0