Skip to content

Fix mutable default arguments across codebase#286

Open
williballenthin wants to merge 6 commits intomasterfrom
worktree-fix-mutable-defaults
Open

Fix mutable default arguments across codebase#286
williballenthin wants to merge 6 commits intomasterfrom
worktree-fix-mutable-defaults

Conversation

@williballenthin
Copy link
Collaborator

Summary

Systematic fix for Python's mutable default argument antipattern across the codebase:

  • Process.ldr_entries (active bug, same as Fix Process.ldr_entries shared across instances #271): class-level list = [] shared across all instances, causing PEB corruption in sequential emulations. Moved to __init__.
  • Process(user_modules=[]): mutable default aliased to self.modules — latent shared-state bug
  • Hook(ctx=[]) and 5 subclasses: mutable default list shared across hook instances
  • Speakeasy(argv=[]), Win32Emulator(argv=[]): mutable default list
  • File(config={}), Pipe(config={}): mutable default dict
  • ~1016 API handler methods with ctx={}: replaced with ctx: dict[str, str] | None = None and a ctx = ctx or {} guard

All mutable defaults replaced with None + materialization in the method body, following standard Python practice.

Test plan

  • Existing test suite passes
  • Verified 0 remaining ctx={} patterns in API handler directory
  • Verified all API handlers have the guard line

🤖 Generated with Claude Code

@google-cla
Copy link

google-cla bot commented Mar 10, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@williballenthin williballenthin force-pushed the worktree-fix-mutable-defaults branch from 9afa3e4 to 96d0471 Compare March 10, 2026 12:15
@williballenthin
Copy link
Collaborator Author

lgtm

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request implements a comprehensive refactor to eliminate mutable default arguments throughout the codebase. This change significantly enhances the reliability and predictability of the system by preventing unintended shared state modifications across object instances and function calls. The fixes target various core components and a large number of API handlers, aligning the code with best practices for Python default argument handling.

Highlights

  • Mutable Default Argument Fixes: Systematically addressed and fixed Python's mutable default argument antipattern across the codebase, preventing latent shared-state bugs.
  • Core Class Constructors Updated: Modified constructors for Process, Hook and its subclasses, Speakeasy, Win32Emulator, File, and Pipe to correctly handle default arguments for lists and dictionaries.
  • API Handler Context Standardization: Updated approximately 1016 API handler methods to use ctx: dict[str, str] | None = None and a ctx = ctx or {} guard, ensuring proper context initialization.
  • New Type Alias Introduced: Added an ApiContext type alias to standardize the type hint for API handler context dictionaries.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • speakeasy/common.py
    • Replaced mutable default list for ctx parameter in Hook class constructor.
    • Replaced mutable default list for ctx parameter in DynCodeHook, CodeHook, InterruptHook, InstructionHook, and InvalidInstructionHook constructors.
  • speakeasy/speakeasy.py
    • Replaced mutable default list for argv parameter in Speakeasy class constructor.
  • speakeasy/windows/fileman.py
    • Replaced mutable default dictionary for config parameter in File class constructor.
    • Replaced mutable default dictionary for config parameter in Pipe class constructor.
  • speakeasy/windows/objman.py
    • Moved ldr_entries from a class-level attribute to an instance attribute in Process class constructor.
    • Replaced mutable default list for user_modules parameter in Process class constructor.
  • speakeasy/windows/win32.py
    • Replaced mutable default list for argv parameter in Win32Emulator class constructor.
  • speakeasy/winenv/api/api.py
    • Added ApiContext type alias for API handler context dictionaries.
  • speakeasy/winenv/api/kernelmode/fwpkclnt.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/kernelmode/hal.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/kernelmode/ndis.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/kernelmode/netio.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/kernelmode/ntoskrnl.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in vsprintf_s and KeInitializeApc methods.
  • speakeasy/winenv/api/kernelmode/usbd.py
    • Updated ctx parameter in USBD_ValidateConfigurationDescriptor method to use api.ApiContext = None.
  • speakeasy/winenv/api/kernelmode/wdfldr.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/advapi32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in RegOpenKey, RegOpenKeyEx, RegQueryValueEx, RegSetValueEx, RegEnumKey, RegEnumKeyEx, RegCreateKey, RegCreateKeyEx, RegDeleteValue, RegQueryInfoKey, OpenProcessToken, OpenThreadToken, DuplicateTokenEx, SetTokenInformation, StartServiceCtrlDispatcher, RegisterServiceCtrlHandlerEx, SetServiceStatus, RevertToSelf, ImpersonateLoggedOnUser, OpenSCManager, CreateService, StartService, ControlService, QueryServiceStatus, QueryServiceConfig, CloseServiceHandle, ChangeServiceConfig, ChangeServiceConfig2, RtlGenRandom, CryptAcquireContext, CryptGenRandom, AllocateAndInitializeSid, CheckTokenMembership, FreeSid, CryptReleaseContext, GetCurrentHwProfile, GetUserName, LookupPrivilegeValue, AdjustTokenPrivileges, GetTokenInformation, EqualSid, GetSidIdentifierAuthority, GetSidSubAuthorityCount, GetSidSubAuthority, LookupAccountName, LookupAccountSid, CreateProcessAsUser, CryptCreateHash, CryptHashData, CryptGetHashParam, CryptDestroyHash, CryptDeriveKey, CryptDecrypt, RegGetValue, EnumServicesStatus, OpenService, and DeleteService methods.
  • speakeasy/winenv/api/usermode/advpack.py
    • Updated ctx parameter in IsNTAdmin method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/bcrypt.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in BCryptImportKeyPair, BCryptDestroyKey, and BCryptFreeObject methods.
  • speakeasy/winenv/api/usermode/com_api.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/comctl32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/crypt32.py
    • Updated ctx parameter in CryptStringToBinary method to use api.ApiContext = None.
    • Added ctx initialization guard in CryptStringToBinary method.
  • speakeasy/winenv/api/usermode/dnsapi.py
    • Updated ctx parameter in DnsQuery_ method to use api.ApiContext = None.
    • Added ctx initialization guard in DnsQuery_ method.
  • speakeasy/winenv/api/usermode/gdi32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/iphlpapi.py
    • Updated ctx parameter in GetAdaptersInfo method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/lz32.py
    • Updated ctx parameter in LZSeek method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/mpr.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in WNetGetConnection method.
  • speakeasy/winenv/api/usermode/mscoree.py
    • Updated ctx parameter in CorExitProcess method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/msi32.py
    • Updated ctx parameter in MsiDatabaseMergeA method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/msimg32.py
    • Updated ctx parameter in TransparentBlt method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/msvcrt.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/msvfw32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/ncrypt.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in NCryptImportKey, NCryptDeleteKey, and NCryptFreeObject methods.
  • speakeasy/winenv/api/usermode/netapi32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/netutils.py
    • Updated ctx parameter in NetApiBufferFree method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/ntdll.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/ole32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/oleaut32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/psapi.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in GetModuleBaseName and GetModuleFileNameEx methods.
  • speakeasy/winenv/api/usermode/rpcrt4.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/secur32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in GetUserNameEx method.
  • speakeasy/winenv/api/usermode/sfc.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/shell32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in SHCreateDirectoryEx, ShellExecute, ShellExecuteEx, SHGetFolderPath, and CommandLineToArgv methods.
  • speakeasy/winenv/api/usermode/shlwapi.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in PathIsRelative, StrStr, StrStrI, PathFindExtension, StrCmpI, PathFindFileName, PathRemoveExtension, PathStripPath, wnsprintf, PathAppend, PathRemoveFileSpec, PathAddBackslash, and PathRenameExtension methods.
  • speakeasy/winenv/api/usermode/urlmon.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in URLDownloadToFile and URLDownloadToCacheFile methods.
  • speakeasy/winenv/api/usermode/user32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in RegisterClassEx, MessageBox, MessageBoxEx, LoadString, RegisterWindowMessage, wsprintf, DialogBoxParam, OpenDesktop, CharLowerBuff, CharUpperBuff, CharLower, CharUpper, CharPrev, and wvsprintf methods.
  • speakeasy/winenv/api/usermode/winhttp.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/wininet.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in InternetOpen, InternetConnect, HttpOpenRequest, InternetCrackUrl, HttpSendRequest, and HttpQueryInfo methods.
  • speakeasy/winenv/api/usermode/winmm.py
    • Updated ctx parameter in timeGetTime method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/wkscli.py
    • Updated ctx parameter in NetGetJoinInformation method to use api.ApiContext = None.
  • speakeasy/winenv/api/usermode/ws2_32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in WSAConnect method.
  • speakeasy/winenv/api/usermode/wtsapi32.py
    • Updated ctx parameter in all apihook methods to use api.ApiContext = None.
    • Added ctx initialization guard in WTSEnumerateSessions method.
Activity
  • The existing test suite was run and all tests passed, confirming no regressions were introduced.
  • A scan of the API handler directory confirmed that all ctx={} patterns have been successfully eliminated.
  • All API handlers were verified to include the necessary guard line for proper context initialization.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request systematically addresses the mutable default argument anti-pattern across the codebase, which is a significant improvement for code correctness and predictability. The changes are largely correct and adhere to standard Python practices. I've identified one minor issue in DynCodeHook where the ctx parameter is not passed to its superclass constructor, which could lead to unexpected behavior. My review includes a suggestion to fix this. Overall, this is a solid and valuable refactoring effort.

Note: Security Review did not run due to the size of the PR.

@mr-tz
Copy link
Contributor

mr-tz commented Mar 24, 2026

can you rebase, please?

Process.ldr_entries was a class-level mutable list shared across all
instances, causing PEB corruption in sequential emulations. Move it to
__init__. Also fix Process(user_modules=[]) and Hook(ctx=[]) family
of mutable default arguments.
Replace argv=[], config={} defaults with None and materialize fresh
collections in __init__ bodies.
All ~1016 API handler methods used ctx={} as a mutable default argument.
Replace with ctx: dict[str, str] | None = None and guard with
ctx = ctx or {} in each method body.
Define ApiContext = dict[str, str] | None in api.py and reference it
as api.ApiContext in all 1016 handler signatures, replacing the verbose
inline dict[str, str] | None annotation.
852 of the 1016 handlers never reference ctx after the guard line.
Remove the dead `ctx = ctx or {}` assignment in those methods, keeping
it only in the 164 that actually use ctx downstream.
@williballenthin williballenthin force-pushed the worktree-fix-mutable-defaults branch from 4d09769 to a1fb393 Compare March 25, 2026 08:39
@williballenthin williballenthin requested a review from mr-tz March 25, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants