fix(deps): take Electron 43.7.0 for the glibc environ use-after-free (#20089)

This commit is contained in:
Neil
2026-09-11 15:43:43 -07:00
committed by GitHub
parent da5d555259
commit 9c918b93a6
5 changed files with 121 additions and 32 deletions
@@ -0,0 +1,57 @@
import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
/**
* Why a floor and not just a pin: Electron 43.5.0/43.6.0 set and unset `GDK_GL`
* around `gtk_init()` while FontConfig warmed up on a pool thread, and below
* glibc 2.41 that frees `environ` under a concurrent `getenv()` — a launch-time
* use-after-free on every Ubuntu we support (stablyai/orca#20081). 43.7.0 stops
* freeing the published `environ`. A downgrade past it re-ships that crash, and
* nothing else in the tree would notice.
*/
const MINIMUM_ELECTRON_VERSION = '43.7.0'
function parseVersion(specifier: string): [number, number, number] {
const match = /(\d+)\.(\d+)\.(\d+)/.exec(specifier)
if (!match) {
throw new Error(`unparseable Electron version: ${specifier}`)
}
return [Number(match[1]), Number(match[2]), Number(match[3])]
}
function meetsRuntimeFloor(specifier: string): boolean {
const version = parseVersion(specifier)
const floor = parseVersion(MINIMUM_ELECTRON_VERSION)
for (const [index, part] of version.entries()) {
if (part !== floor[index]) {
return part > floor[index]
}
}
return true
}
describe('electron runtime floor', () => {
it.each([
['42.9.0', false],
['43.6.0', false],
['43.7.0', true],
['43.7.1', true],
['43.8.0', true],
['44.0.0', true]
])('reads %s as meeting the floor: %s', (specifier, expected) => {
expect(meetsRuntimeFloor(specifier)).toBe(expected)
})
it('pins Electron at or above the glibc environ-race fix', () => {
const packageJson = JSON.parse(
readFileSync(join(__dirname, '../../package.json'), 'utf-8')
) as { devDependencies: Record<string, string> }
const specifier = packageJson.devDependencies.electron
expect(
meetsRuntimeFloor(specifier),
`electron ${specifier} is below the ${MINIMUM_ELECTRON_VERSION} runtime floor`
).toBe(true)
})
})
@@ -131,3 +131,33 @@ a hole in the matrix.
No strong `GLIBC_` node may exceed `2.31`, and no `GLIBCXX_`/`CXXABI_` node may
exceed `3.4.28`/`1.3.12` — what stock Ubuntu 20.04 ships.
## Runtime floor: the `environ` race below glibc 2.41 (Electron ≥ 43.7.0)
Separate from the build floor above, one glibc runtime bug constrains which
Electron we may ship. Before glibc 2.41, `setenv`/`unsetenv` reallocate the
`environ` array and **free** the old one, so a concurrent `getenv()` on another
thread reads freed memory. Ubuntu 20.0424.04 (2.312.39) are all below that
line, so every Linux target we support is exposed.
Electron 43.5.0 made that latent race reachable on every launch: it started
setting `GDK_GL=disable` around `gtk_init()` and unsetting it right after, while
in the same change moving FontConfig warm-up onto a thread-pool thread that runs
concurrently and calls `getenv()` constantly
([electron#53070](https://github.com/electron/electron/pull/53070)). The result
is a browser-process use-after-free about a second into startup — no window, no
GPU child involved, and the corruption surfaces wherever the next allocation
lands, which is why reports name unrelated frames (`gtk_widget_realize`,
libxcb-dri3, FontConfig/expat). Orca 1.4.199/1.4.200 shipped that runtime and
died on launch on Ubuntu + NVIDIA/X11
([#20081](https://github.com/stablyai/orca/issues/20081)).
Electron 43.7.0 fixes it by overriding `setenv`/`unsetenv`/`putenv`/`clearenv`
so a published `environ` is never freed, deferring to glibc on 2.41+
([electron#53491](https://github.com/electron/electron/pull/53491), backported
to 42/43/44/45). **Do not downgrade Electron below 43.7.0, or move to another
line, without confirming that backport is in the target release** —
`config/scripts/electron-runtime-floor.test.ts` fails the suite if the pin drops
below the floor. Orca itself writes `process.env` during early startup
(`patchPackagedProcessPath`, `configureOrcaUserDataPathEnv`,
`hydrate-shell-path`), so it is a first-class trigger, not just a bystander.
+1 -1
View File
@@ -240,7 +240,7 @@
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"dompurify": "3.4.14",
"electron": "43.6.0",
"electron": "43.7.0",
"electron-builder": "^26.15.3",
"electron-builder-squirrel-windows": "^26.15.3",
"electron-vite": "^5.0.0",
+32 -31
View File
@@ -127,10 +127,10 @@ importers:
version: 0.3.251(@anthropic-ai/sdk@0.122.0(zod@4.5.4))(@modelcontextprotocol/sdk@1.30.0(supports-color@7.2.0)(zod@4.5.4))(zod@4.5.4)
'@electron-toolkit/preload':
specifier: ^3.0.2
version: 3.0.2(electron@43.6.0(supports-color@7.2.0))
version: 3.0.2(electron@43.7.0(supports-color@7.2.0))
'@electron-toolkit/utils':
specifier: ^4.0.0
version: 4.0.0(electron@43.6.0(supports-color@7.2.0))
version: 4.0.0(electron@43.7.0(supports-color@7.2.0))
'@floating-ui/dom':
specifier: 1.7.6
version: 1.7.6
@@ -224,7 +224,7 @@ importers:
version: 2.1.14(@playwright/test@1.59.1)(zod@4.5.4)
'@tailwindcss/vite':
specifier: ^4.2.4
version: 4.2.4(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
version: 4.2.4(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4))
'@tanstack/react-virtual':
specifier: ^3.14.10
version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@@ -314,7 +314,7 @@ importers:
version: 8.18.1
'@vitejs/plugin-react':
specifier: ^5.2.0
version: 5.2.0(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
version: 5.2.0(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4))
'@xterm/addon-fit':
specifier: 0.12.0-beta.300
version: 0.12.0-beta.300(@xterm/xterm@6.1.0-beta.303(patch_hash=1f36ce689bc50c703ae09aeda0e064f107e18e4a5ecba19e746fa5edc4b02ef4))
@@ -349,8 +349,8 @@ importers:
specifier: 3.4.14
version: 3.4.14
electron:
specifier: 43.6.0
version: 43.6.0(supports-color@7.2.0)
specifier: 43.7.0
version: 43.7.0(supports-color@7.2.0)
electron-builder:
specifier: ^26.15.3
version: 26.15.3(electron-builder-squirrel-windows@26.15.3)
@@ -359,7 +359,7 @@ importers:
version: 26.15.3(dmg-builder@26.15.3)
electron-vite:
specifier: ^5.0.0
version: 5.0.0(@swc/core@1.15.46)(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
version: 5.0.0(@swc/core@1.15.46)(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4))
emoji-picker-react:
specifier: ^4.19.1
version: 4.19.1(react@19.2.8)
@@ -497,10 +497,10 @@ importers:
version: 11.0.5
vite:
specifier: npm:rolldown-vite@7.3.1
version: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)
version: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4)
vitest:
specifier: ^4.1.11
version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.11.8)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.11.8)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4))
vscode-oniguruma:
specifier: ^2.0.1
version: 2.0.1
@@ -4330,8 +4330,8 @@ packages:
resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==}
engines: {node: '>=8.0.0'}
electron@43.6.0:
resolution: {integrity: sha512-DqVKYV+FXheMSLTxcMQ+NCo78BDgpnToSyIzXctlUtbP3lRGEuoo1P+C2n/90rJ7TvHgzP0bpP9fbbXxp4noIg==}
electron@43.7.0:
resolution: {integrity: sha512-m98FUehwnoo6q2D9Mr+n602Natb2CRFeKD81GhTdJlKh/Iyud0R1X8hChjpaMBLSsIX9r2ZEFnz0sdIALiO9ZQ==}
engines: {node: '>= 22.12.0'}
hasBin: true
@@ -7332,17 +7332,17 @@ snapshots:
'@electron-internal/extract-zip@1.0.4': {}
'@electron-toolkit/preload@3.0.2(electron@43.6.0(supports-color@7.2.0))':
'@electron-toolkit/preload@3.0.2(electron@43.7.0(supports-color@7.2.0))':
dependencies:
electron: 43.6.0(supports-color@7.2.0)
electron: 43.7.0(supports-color@7.2.0)
'@electron-toolkit/tsconfig@2.0.0(@types/node@25.9.5)':
dependencies:
'@types/node': 25.9.5
'@electron-toolkit/utils@4.0.0(electron@43.6.0(supports-color@7.2.0))':
'@electron-toolkit/utils@4.0.0(electron@43.7.0(supports-color@7.2.0))':
dependencies:
electron: 43.6.0(supports-color@7.2.0)
electron: 43.7.0(supports-color@7.2.0)
'@electron/asar@3.4.1':
dependencies:
@@ -7739,7 +7739,7 @@ snapshots:
eventsource: 3.0.7
eventsource-parser: 3.0.8
express: 5.2.1(supports-color@7.2.0)
express-rate-limit: 8.5.2(express@5.2.1)
express-rate-limit: 8.5.2(express@5.2.1(supports-color@7.2.0))
hono: 4.13.0
jose: 6.2.3
json-schema-typed: 8.0.2
@@ -7761,7 +7761,7 @@ snapshots:
eventsource: 3.0.7
eventsource-parser: 3.0.8
express: 5.2.1(supports-color@7.2.0)
express-rate-limit: 8.5.2(express@5.2.1)
express-rate-limit: 8.5.2(express@5.2.1(supports-color@7.2.0))
hono: 4.13.0
jose: 6.2.3
json-schema-typed: 8.0.2
@@ -9151,12 +9151,12 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.2.4
'@tailwindcss/oxide-win32-x64-msvc': 4.2.4
'@tailwindcss/vite@4.2.4(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))':
'@tailwindcss/vite@4.2.4(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4))':
dependencies:
'@tailwindcss/node': 4.2.4
'@tailwindcss/oxide': 4.2.4
tailwindcss: 4.2.4
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4)
'@tanstack/react-virtual@3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8)':
dependencies:
@@ -9767,7 +9767,7 @@ snapshots:
d3-selection: 3.0.0
d3-transition: 3.0.1(d3-selection@3.0.0)
'@vitejs/plugin-react@5.2.0(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))':
'@vitejs/plugin-react@5.2.0(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4))':
dependencies:
'@babel/core': 7.29.7
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.7)
@@ -9775,7 +9775,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-rc.3
'@types/babel__core': 7.20.5
react-refresh: 0.18.0
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4)
transitivePeerDependencies:
- supports-color
@@ -9788,14 +9788,14 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.1.0
'@vitest/mocker@4.1.11(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))':
'@vitest/mocker@4.1.11(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4))':
dependencies:
'@vitest/spy': 4.1.11
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.14.3(@types/node@25.9.5)(typescript@7.0.2)
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4)
'@vitest/pretty-format@4.1.11':
dependencies:
@@ -10662,7 +10662,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
electron-vite@5.0.0(@swc/core@1.15.46)(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)):
electron-vite@5.0.0(@swc/core@1.15.46)(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4)):
dependencies:
'@babel/core': 7.29.7
'@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.7)
@@ -10670,7 +10670,7 @@ snapshots:
esbuild: 0.25.12
magic-string: 0.30.21
picocolors: 1.1.1
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4)
optionalDependencies:
'@swc/core': 1.15.46
transitivePeerDependencies:
@@ -10688,7 +10688,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
electron@43.6.0(supports-color@7.2.0):
electron@43.7.0(supports-color@7.2.0):
dependencies:
'@electron-internal/extract-zip': 1.0.4
'@electron/get': 5.0.0(supports-color@7.2.0)
@@ -10862,7 +10862,7 @@ snapshots:
exponential-backoff@3.1.3: {}
express-rate-limit@8.5.2(express@5.2.1):
express-rate-limit@8.5.2(express@5.2.1(supports-color@7.2.0)):
dependencies:
express: 5.2.1(supports-color@7.2.0)
ip-address: 10.4.0
@@ -13077,7 +13077,7 @@ snapshots:
robust-predicates@3.0.3: {}
rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4):
rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4):
dependencies:
'@oxc-project/runtime': 0.101.0
fdir: 6.5.0(picomatch@4.0.4)
@@ -13088,6 +13088,7 @@ snapshots:
tinyglobby: 0.2.16
optionalDependencies:
'@types/node': 25.9.5
esbuild: 0.25.12
fsevents: 2.3.3
jiti: 2.7.0
yaml: 2.8.4
@@ -13717,10 +13718,10 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.3
vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.11.8)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)):
vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.11.8)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4)):
dependencies:
'@vitest/expect': 4.1.11
'@vitest/mocker': 4.1.11(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
'@vitest/mocker': 4.1.11(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4))
'@vitest/pretty-format': 4.1.11
'@vitest/runner': 4.1.11
'@vitest/snapshot': 4.1.11
@@ -13737,7 +13738,7 @@ snapshots:
tinyexec: 1.1.2
tinyglobby: 0.2.16
tinyrainbow: 3.1.0
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.8.4)
why-is-node-running: 2.3.0
optionalDependencies:
'@opentelemetry/api': 1.9.1
+1
View File
@@ -10,6 +10,7 @@ minimumReleaseAge: 4320
minimumReleaseAgeExclude:
- pdfjs-dist@6.3.289
- zod@4.5.4
- electron@43.7.0
shamefullyHoist: true
# Orca always launches the user's own resolved Claude CLI via