Skip to content

macOS: every mutant reports segfault when tests touch urllib.request.getproxies() (SystemConfiguration is not fork-safe) #618

Open

Description

@roberstreams

Environment: mutmut 3.8.1 (also current main), Python 3.12 and 3.14 (Homebrew), macOS 27 on Apple Silicon.

What happens: if the code under test or the tests call urllib.request.getproxies() (which requests, httpx and aiohttp do when they create a client), every mutant is reported as segfault. macOS shows a crash report for each child. This is not #446: use_setproctitle already defaults to off on macOS.

Minimal reproduction:

src/demo/__init__.py

def is_adult(age):
    return age >= 18

tests/test_demo.py

import urllib.request
from demo import is_adult

def test_is_adult():
    urllib.request.getproxies()   # what HTTP clients do on setup
    assert is_adult(18)
    assert not is_adult(17)

setup.cfg

[mutmut]
source_paths=src/demo
pythonpath=src
$ mutmut run && mutmut results --all true
    demo.x_is_adult__mutmut_1: segfault
    demo.x_is_adult__mutmut_2: segfault

Cause: with no *_proxy environment variable set, getproxies() on macOS falls back to _scproxy.get_proxies(), which calls SCDynamicStoreCopyProxiesWithOptions (SystemConfiguration / CoreFoundation). That code isn't safe in a forked child. The crash reports show two shapes, both ending in "crashed on child side of fork pre-exec":

  • SIGABRT from performForkChildInitialize (objc +initialize after fork)
  • SIGSEGV in os_log_type_enabled under CFPreferences, with "multi-threaded process forked"

Both stacks go through get_proxies → SCDynamicStoreCopyProxiesWithOptions. Background: CPython bpo-31818.

Workaround: no_proxy='*' mutmut run. That gives killed for both mutants.

Proposed fix (#619): query the system proxy settings once in the main process, before forking, and replace urllib's two _scproxy lookups with the cached answers. Forked children inherit them, so proxy and bypass results stay identical and the environment isn't changed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions