Skip to content

fix(hermes-base): harden switch jump-table normalization #4

fix(hermes-base): harden switch jump-table normalization

fix(hermes-base): harden switch jump-table normalization #4

name: Apply Hermes switch hardening
on:
pull_request:
branches:
- master
permissions:
contents: write
jobs:
apply-and-verify:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
with:
ref: automation/hermes-switch-release-20260823
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- name: Apply hardening
shell: bash
run: |
python3 - <<'PY'
from pathlib import Path
source_path = Path('src/utils/hermes-base.ts')
source = source_path.read_text()
replacements = [
(
r" m = /^(\s*(?:String|UInt)?SwitchImm r\d+, \d+, )\d+(, .*)$/.exec(line);",
r" m = /^(\s*StringSwitchImm r\d+, \d+, )\d+(, L\d+, \d+)$/.exec(line);",
),
(
r" m = /^(\s*(?:String|UInt)?SwitchImm r\d+, )\d+(, L\d+, .*)$/.exec(line);",
r" m = /^(\s*UIntSwitchImm r\d+, )\d+(, L\d+, \d+, \d+)$/.exec(line);",
),
]
for old, new in replacements:
count = source.count(old)
if count != 1:
raise SystemExit(f'expected one switch normalization line, found {count}: {old}')
source = source.replace(old, new)
source_path.write_text(source)
test_path = Path('tests/hermes-switch-normalization.test.ts')
if test_path.exists():
raise SystemExit(f'{test_path} already exists')
test_path.write_text("""import { describe, expect, test } from 'bun:test';
import { normalizeDisassemblyLine } from '../src/utils/hermes-base';
const normalize = (line: string) =>
normalizeDisassemblyLine(line, new Map<number, string>());
describe('Hermes switch jump-table normalization', () => {
test('normalizes only the StringSwitchImm jump-table offset', () => {
const baseline = normalize(' StringSwitchImm r13, 2, 4024, L146, 150');
expect(baseline).toBe(' StringSwitchImm r13, 2, <jt>, L146, 150');
expect(normalize(' StringSwitchImm r13, 2, 4025, L146, 150')).toBe(
baseline,
);
expect(normalize(' StringSwitchImm r13, 3, 4024, L146, 150')).not.toBe(
baseline,
);
expect(normalize(' StringSwitchImm r13, 2, 4024, L147, 150')).not.toBe(
baseline,
);
expect(normalize(' StringSwitchImm r13, 2, 4024, L146, 151')).not.toBe(
baseline,
);
});
test('normalizes only the UIntSwitchImm jump-table offset', () => {
const baseline = normalize(' UIntSwitchImm r40, 5937, L3, 0, 31');
expect(baseline).toBe(' UIntSwitchImm r40, <jt>, L3, 0, 31');
expect(normalize(' UIntSwitchImm r40, 5938, L3, 0, 31')).toBe(baseline);
expect(normalize(' UIntSwitchImm r40, 5937, L4, 0, 31')).not.toBe(
baseline,
);
expect(normalize(' UIntSwitchImm r40, 5937, L3, 1, 31')).not.toBe(
baseline,
);
expect(normalize(' UIntSwitchImm r40, 5937, L3, 0, 32')).not.toBe(
baseline,
);
});
test('does not fold unsupported or malformed switch shapes', () => {
expect(normalize(' SwitchImm r1, 2, 3, L4, 5')).toBe(
' SwitchImm r1, 2, 3, L4, 5',
);
expect(normalize(' UIntSwitchImm r40, 5937, 3, 0, 31')).toBe(
' UIntSwitchImm r40, 5937, 3, 0, 31',
);
});
});
""")
PY
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Lint and typecheck
run: bun run lint
- name: Test
run: bun test
- name: Build
run: bun run build
- name: Commit verified changes
shell: bash
run: |
rm .github/workflows/apply-hermes-switch-hardening.yml
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add src/utils/hermes-base.ts tests/hermes-switch-normalization.test.ts .github/workflows/apply-hermes-switch-hardening.yml
git commit -m "fix(hermes-base): harden switch jump-table normalization"
git push origin HEAD:automation/hermes-switch-release-20260823