[MacPorts] #74272: emacs-app: subprocesses crash with SIGABRT on TCC-gated frameworks (missing NS*UsageDescription keys)
MacPorts
noreply at macports.org
Fri Jul 31 17:35:20 UTC 2026
#74272: emacs-app: subprocesses crash with SIGABRT on TCC-gated frameworks (missing
NS*UsageDescription keys)
----------------------+-----------------------
Reporter: diekhans | Owner: (none)
Type: defect | Status: new
Priority: Normal | Milestone:
Component: ports | Version:
Keywords: haspatch | Port: emacs-app
----------------------+-----------------------
## Description
`Emacs.app` as built by the `emacs-app` subport declares usage-description
keys only for the
file-access TCC services and Apple Events:
{{{
$ plutil -p /Applications/MacPorts/Emacs.app/Contents/Info.plist | grep
UsageDescription
"NSAppleEventsUsageDescription" => "Emacs requires permission to
send AppleEvents to other applications."
"NSDesktopFolderUsageDescription" => "Emacs requires permission to
access the Desktop folder."
"NSDocumentsFolderUsageDescription" => "Emacs requires permission to
access the Documents folder."
"NSDownloadsFolderUsageDescription" => "Emacs requires permission to
access the Downloads folder."
"NSRemovableVolumesUsageDescription" => "Emacs requires permission to
access files on Removable Volumes."
}}}
None of the class-based services (Photos, Camera, Microphone, Contacts,
Calendars, Reminders,
Location, Speech Recognition, Bluetooth) are declared.
macOS TCC attributes a privacy check to the **responsible process** found
by walking up the parent
chain. For a command-line program started from a shell hosted inside Emacs
(`M-x shell`, `eshell`,
`vterm`, `M-x compile`, org-babel, …) that responsible process is
`Emacs.app`. So such a program is
killed with `SIGABRT` instead of getting the normal permission dialog —
even if its own bundle
declares the required key.
### Reproduction
Build a bundle-less probe that only touches `Photos.framework` (full
source in the linked PR):
{{{
clang -framework Photos -framework Foundation -o photo_probe photo_probe.m
}}}
Run it from a shell inside Emacs. Crash report:
{{{
procName => photo_probe
parentProc => bash
responsibleProc => Emacs
coalitionName => org.gnu.Emacs
exception => EXC_CRASH / SIGABRT (shell reports exit 134)
termination => namespace TCC, code 0:
"This app has crashed because it attempted to access privacy-sensitive
data without a
usage description. The app's Info.plist must contain an
NSPhotoLibraryUsageDescription
key with a string value explaining to the user how the app uses this
data."
}}}
Run from iTerm2 directly: works as expected.
This was originally hit running `osxphotos`/PyObjC scripts from a shell
inside Emacs, but it is not
Python-specific.
### Environment
* macOS 26.5.2 (25F84), Mac16,11 (Apple M4 Pro)
* `emacs-app @30.2_14+nativecomp+rsvg+treesitter`
* GNU Emacs 30.2 (build 2, aarch64-apple-darwin25.5.0, NS appkit-2685.60)
### Notes
Terminal.app is not a counterexample — it declares zero usage descriptions
and relies on the
Apple-private entitlement `com.apple.private.tcc.allow-prompting =
[kTCCServiceAll]`, which
third-party apps cannot use. iTerm2 3.6.8 is the applicable precedent: it
declares 14 such keys.
Declaring a usage description does not grant access; it only allows macOS
to prompt instead of
aborting.
### Fix
Pull request extends the existing `files/patch-Info.plist.in.diff` with 14
missing class-based keys,
skipping the ones upstream already declares (`NSAppleEvents*`, the
`*Folder*` and
`*RemovableVolumes*` keys in both trees, plus `NSSpeechRecognition*` which
emacs master has already
added). Verified to apply with zero fuzz against both the 30.2 tarball and
the emacs-master snapshot
used by `emacs-app-devel`, with no duplicate keys in either.
Also being reported upstream to GNU Emacs, since
`nextstep/templates/Info.plist.in` lives in the
Emacs source tree.
Prepared with the assistance of claude-code.
--
Ticket URL: <https://trac.macports.org/ticket/74272>
MacPorts <https://www.macports.org/>
Ports system for macOS
More information about the macports-tickets
mailing list