Skip to content

emacs: pin clock_gettime in fixrand shim for reproducible .pdmp - #273

Merged
bryan-minimal merged 2 commits into
mainfrom
bryan/emacs-reproducible
Jun 22, 2026
Merged

emacs: pin clock_gettime in fixrand shim for reproducible .pdmp#273
bryan-minimal merged 2 commits into
mainfrom
bryan/emacs-reproducible

Conversation

@bryan-minimal

@bryan-minimal bryan-minimal commented Jun 18, 2026

Copy link
Copy Markdown
Member

What

Makes the emacs package reproducible by extending the existing fixrand.so LD_PRELOAD shim to also pin clock_gettime(CLOCK_REALTIME).

Why

After the current shim (which makes getrandom()//dev/urandom deterministic for hash-table seeding), the dumped emacs-*.pdmp still differed across builds — in exactly 11 bytes, in two clusters, both decoding to wall-clock timestamps captured at dump time via clock_gettime(CLOCK_REALTIME) (which the shim didn't intercept):

  1. *scratch* buffer's buffer-display-time — an Emacs (TICKS . HZ) timestamp cons set by Fcurrent_time() during make_initial_frame (src/window.c / src/emacs.c). The two builds decoded to 2026-06-16 04:01:42 vs 04:02:43 — exactly the ~61s gap between them.
  2. Vgc_elapsed — accumulated GC time (a float) in src/alloc.c, measured with current_timespec().

SOURCE_DATE_EPOCH doesn't help here because Emacs reads the live clock directly.

Fix

Add a clock_gettime interceptor to fixrand.c that returns SOURCE_DATE_EPOCH for CLOCK_REALTIME (and passes all other clocks, e.g. CLOCK_MONOTONIC, through untouched so timeouts/progress loops are unaffected). The build.sh compile line is unchanged — it already builds fixrand.c with -ldl.

This pins the display-time and makes GC start == end (elapsed 0.0), both deterministic. No literal SOURCE_DATE_EPOCH=0 (uses getenv + fallback), so it passes minimal-check.

Verification

Build-twice-and-diff on aarch64: two from-scratch builds are now byte-for-byte identical (repro-check diff, 4282/4282 files). Before, the .pdmp differed in 11 timestamp bytes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved reproducibility of Emacs builds by freezing system time readings during snapshot generation, ensuring consistent and deterministic output across different build environments and execution times.

After the existing fixrand.so shim (getrandom/urandom), the dumped .pdmp
still differed in 11 bytes — two wall-clock timestamps read via
clock_gettime(CLOCK_REALTIME), which the shim didn't cover: the *scratch*
buffer's buffer-display-time (Fcurrent_time in make_initial_frame) and
Vgc_elapsed GC timing (src/alloc.c). Extend the shim to return
SOURCE_DATE_EPOCH for CLOCK_REALTIME (other clocks pass through).

Verified on aarch64: two from-scratch builds are byte-identical
(repro-check diff, 4282/4282 files).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b80a25de-cd70-4399-ab7b-5133dc793bf6

📥 Commits

Reviewing files that changed from the base of the PR and between fe301db and e4ccc06.

📒 Files selected for processing (1)
  • packages/emacs/fixrand.c
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/emacs/fixrand.c

📝 Walkthrough

Walkthrough

fixrand.c gains a clock_gettime LD_PRELOAD interposer that intercepts CLOCK_REALTIME calls and returns a fixed timestamp sourced from SOURCE_DATE_EPOCH (defaulting to 0), making wall-clock reads during Emacs .pdmp generation reproducible. All other clock IDs delegate to the real function.

Changes

clock_gettime determinism shim

Layer / File(s) Summary
clock_gettime interposition: headers, docs, and implementation
packages/emacs/fixrand.c
File comment extended to document CLOCK_REALTIME freezing via SOURCE_DATE_EPOCH; <stdlib.h> and <time.h> headers added; new clock_gettime interposer lazily resolves the real function via dlsym, overrides CLOCK_REALTIME with SOURCE_DATE_EPOCH parsed as seconds (tv_nsec=0), and passes all other clock IDs through unchanged.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested reviewers

  • twitchyliquid64

Poem

🐇 Tick-tock, the clock stands still,
SOURCE_DATE_EPOCH bends time to my will.
No random wall-clock sneaking in,
The .pdmp dump can now begin!
Reproducible builds — a rabbit's thrill. 🕰️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: extending the fixrand shim to intercept clock_gettime for reproducible .pdmp files in Emacs builds.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bryan/emacs-reproducible

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/emacs/fixrand.c`:
- Around line 75-85: The real_clock_gettime function pointer can remain NULL if
dlsym fails to load the symbol, which will cause a NULL pointer dereference when
called for non-CLOCK_REALTIME clock IDs. Add a NULL check for real_clock_gettime
before calling it on the final return statement, and either log an error or
return an appropriate error code (such as -1 with errno set to ENOSYS) if the
symbol lookup failed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9567d1f9-d904-47db-ac7c-949595cb483a

📥 Commits

Reviewing files that changed from the base of the PR and between b265510 and fe301db.

📒 Files selected for processing (1)
  • packages/emacs/fixrand.c

Comment thread packages/emacs/fixrand.c
Defensive NULL check before deref of real_clock_gettime: if
dlsym(RTLD_NEXT, "clock_gettime") ever returns NULL, fail with ENOSYS
instead of segfaulting. The CLOCK_REALTIME path already returns before
this point, so this only affects pass-through clocks (CLOCK_MONOTONIC,
etc.) — but it makes the shim robust regardless. Folds in the one valid
point from the Edge Delta bot's #278.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bryan-minimal
bryan-minimal added this pull request to the merge queue Jun 22, 2026
Merged via the queue into main with commit 838b255 Jun 22, 2026
4 checks passed
@bryan-minimal
bryan-minimal deleted the bryan/emacs-reproducible branch June 22, 2026 17:29
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