[Bug]: signal.alarm() returns corrupted (sign-flipped) value in x86_64 Linux guest running under Rosetta translation
- Dominant language
- Swift
- Stars
- 49.9k
- Forks
- 1.8k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 22
Description
### I have done the following
- [x] I have searched the existing issues
- [ ] If possible, I've reproduced the issue using the 'main' branch of this project
### Steps to reproduce
`container build --platform linux/amd64 -t rosetta-alarm-repro`
`container run --platform linux/amd64 --rm rosetta-alarm-repro`
```
### Containerfile
# Minimal, standalone reproduction of a signal.alarm() integer-corruption bug
# seen under Apple's `container` CLI on Apple Silicon (Rosetta 2 x86_64
# translation).
#
# Two bare signal.alarm() calls, no forking, no
# multiprocessing. On an affected host the second call returns a corrupted
# value; on a correctly-functioning host it prints a value close to
# expected_remaining.
#
# Not expected to reproduce on native amd64 hardware/VMs - it is specific to
# Rosetta 2 binary translation of x86_64 guests on Apple Silicon.
#
# Build (must target amd64 so Apple's `container` CLI runs it under Rosetta):
# container build --platform linux/amd64 -t rosetta-alarm-repro .
# Run (--platform is required again here - `container run` doesn't infer it
# from the image and defaults to the host's native arm64 otherwise):
# container run --platform linux/amd64 --rm rosetta-alarm-repro
FROM python:3.12-slim
COPY alarm_probe.py /alarm_probe.py
CMD ["python3", "/alarm_probe.py"]
```
### `alarm_probe.py`
[alarm_probe.py](https://github.com/user-attachments/files/32060754/alarm_probe.py)
### Problem description
## Current behavior
signal.alarm() returns a corrupted value when called a second time on an armed alarm, inside an
x86_64 Linux guest run via `container run --platform linux/amd64` on Apple Silicon.
Concretely: arm an alarm for abort_after=10800 seconds, sleep ~16s, then call
signal.alarm(abort_after) again (the standard idiom for querying "seconds remaining" while
re-arming). The return value should be the number of seconds left on the previous alarm
(~10784), but instead comes back as 4294956512.
4294956512 == 2**32 - 10784 — i.e. the correct remaining time, sign-flipped and reinterpreted
as an unsigned 32-bit integer.
Passing that corrupted value into a subsequent signal.alarm() call (which is exactly what real
code does when reusing the "seconds left" return value to re-arm) raises:
OverflowError: Python int too large to convert to C int
(Under Python 2.7 the same corrupted value instead raises OverflowError: signed integer is
greater than maximum.)
## Expected behavior
Per the POSIX/glibc alarm() contract, calling alarm() on an already-armed alarm should return
the number of seconds remaining on the previous alarm — a value in [0, abort_after] for
abort_after seconds previously armed. It should never return a value outside that range, and
never a value that doesn't fit back into alarm()'s own C long argument.
Confirmed this reproduces identically under both Python 3.12.14 and Python 2.7.18 with nothing
but two bare signal.alarm() calls — no forking, multiprocessing, or third-party code involved —
which points to the corruption happening in the raw alarm() syscall return value itself (i.e.,
in the Rosetta 2 x86_64→arm64 translation), not in CPython.
## Relevant logs
Minimal repro output on the affected host (see attached Containerfile):
```
elapsed=16.006 expected_remaining~=10784 actual_return=4294956512 as_signed32=-10784
Second variant (alarm_probe.py, no sleep, two back-to-back calls):
re-arm alarm() return (should be ~3600): 4294967295
OverflowError: Python int too large to convert to C int
```
Host environment: macOS 26.6.2 (build 25G83), Command Line Tools 26.6.0.0.1781586589, Rosetta
1.0.0.0.1786586848; guest is Debian trixie, glibc 2.41, systemd-detect-virt reports
container-other.
### Environment
```markdown
- macOS: 26.6.2 (build 25G83)
- Command Line Tools: 26.6.0.0.1781586589
- Rosetta: 1.0.0.0.1786586848
- Xcode.app: not installed (CLT-only xcode-select path), so no xcodebuild -version to report
- Container: container CLI version 1.3.1 (build: release, commit: unspeci)
```
### Code of Conduct
- [x] I agree to follow this project's Code of Conduct
Contributor guide
Research direction
Start by building and running the attached Containerfile and alarm_probe.py with the documented amd64 platform commands. Compare signal.alarm() behavior in the reported x86_64 Linux guest with native or non-Rosetta execution, then determine whether the container project can address the corrupted return value or needs an upstream Rosetta report; done means the repro is explained and the expected alarm value no longer overflows.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- linux, python, swift
- Domain
- infrastructure, operating-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100