mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 00:02:29 +00:00
fix(crash-reporting): stop discarding the whole module list on POSIX dumps (#16687)
This commit is contained in:
@@ -194,6 +194,22 @@ function buildDump(options: {
|
||||
return { dump: builder.build(streams) }
|
||||
}
|
||||
|
||||
/** Offset of a stream's directory entry: `{type, size, rva}`. */
|
||||
function streamEntry(dump: Buffer, type: number): number {
|
||||
const directoryRva = dump.readUInt32LE(12)
|
||||
for (let index = 0; index < dump.readUInt32LE(8); index += 1) {
|
||||
const entry = directoryRva + index * 12
|
||||
if (dump.readUInt32LE(entry) === type) {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
throw new Error(`no stream of type ${type}`)
|
||||
}
|
||||
|
||||
function moduleListRva(dump: Buffer): number {
|
||||
return dump.readUInt32LE(streamEntry(dump, STREAM_TYPE_MODULE_LIST) + 8)
|
||||
}
|
||||
|
||||
const FATAL_LINE =
|
||||
'[8104:1234:0815/143022.123456:FATAL:render_frame_impl.cc(4821)] Check failed: !is_detached_.'
|
||||
|
||||
@@ -340,6 +356,37 @@ describe('parseMinidumpCrashSignature', () => {
|
||||
expect(signature?.faultingModuleOffset).toBe('0x1234')
|
||||
})
|
||||
|
||||
it('resolves a faulting module past index 1024 on a real macOS image count', () => {
|
||||
// A measured macOS renderer carries 1042 loaded images; a cap below that
|
||||
// dropped the whole module list, so no macOS report could name a module.
|
||||
const modules = Array.from({ length: 1042 }, (_, index) => ({
|
||||
base: 0x1_0000_0000n + BigInt(index) * 0x1_0000n,
|
||||
size: 0x1000,
|
||||
name: `/Applications/Orca.app/Contents/Frameworks/lib${index}.dylib`
|
||||
}))
|
||||
const { dump } = buildDump({
|
||||
exception: { code: 11, address: 0x1_0000_0000n + 1030n * 0x1_0000n + 0x24n },
|
||||
modules
|
||||
})
|
||||
|
||||
const signature = parseMinidumpCrashSignature(dump)
|
||||
|
||||
expect(signature?.faultingModule).toBe('lib1030.dylib')
|
||||
expect(signature?.faultingModuleOffset).toBe('0x24')
|
||||
})
|
||||
|
||||
it('still drops the module list when the claimed module count is absurd', () => {
|
||||
const { dump } = buildDump({
|
||||
exception: { code: 11, address: 0x7ff7_0000_0010n },
|
||||
modules: [{ base: 0x7ff7_0000_0000n, size: 0x1000, name: '/opt/orca/orca' }]
|
||||
})
|
||||
const corrupt = Buffer.from(dump)
|
||||
corrupt.writeUInt32LE(0xffff_ffff, moduleListRva(corrupt))
|
||||
|
||||
expect(() => parseMinidumpCrashSignature(corrupt)).not.toThrow()
|
||||
expect(parseMinidumpCrashSignature(corrupt)?.faultingModule).toBeUndefined()
|
||||
})
|
||||
|
||||
it('omits the faulting module when no image range covers the address', () => {
|
||||
const { dump } = buildDump({
|
||||
exception: { code: 11, address: 0x10n },
|
||||
|
||||
@@ -11,13 +11,16 @@
|
||||
// rather than throwing: a truncated dump must degrade, not break crash
|
||||
// reporting.
|
||||
|
||||
import { findStream, isMinidump, MAX_MODULES, MinidumpView } from './minidump-stream-reader'
|
||||
import { findStream, isMinidump, MinidumpView } from './minidump-stream-reader'
|
||||
import { readCrashpadAnnotations } from './minidump-crashpad-annotations'
|
||||
|
||||
const STREAM_TYPE_MODULE_LIST = 4
|
||||
const STREAM_TYPE_EXCEPTION = 6
|
||||
|
||||
const MODULE_RECORD_SIZE = 108
|
||||
// 8x headroom over a measured 1042-image macOS renderer, whose whole list a
|
||||
// 1_024 cap dropped; a dump claiming more than this is corrupt.
|
||||
const MAX_MODULE_LIST_MODULES = 8_192
|
||||
const MODULE_BASE_OFFSET = 0
|
||||
const MODULE_SIZE_OFFSET = 8
|
||||
const MODULE_NAME_RVA_OFFSET = 20
|
||||
@@ -70,7 +73,7 @@ function readModules(view: MinidumpView): ModuleRecord[] {
|
||||
return []
|
||||
}
|
||||
const count = view.u32(stream.rva)
|
||||
if (count === null || count > MAX_MODULES) {
|
||||
if (count === null || count > MAX_MODULE_LIST_MODULES) {
|
||||
return []
|
||||
}
|
||||
const modules: ModuleRecord[] = []
|
||||
|
||||
@@ -13,7 +13,7 @@ const DIRECTORY_ENTRY_SIZE = 12
|
||||
// A dump claiming an absurd stream count is corrupt; cap before iterating.
|
||||
const MAX_STREAMS = 4_096
|
||||
export const MAX_ANNOTATION_VALUE_BYTES = 8_192
|
||||
// Shared cap: both the MINIDUMP_MODULE_LIST and Crashpad's per-module info list.
|
||||
// Cap for Crashpad's per-module info list; the MINIDUMP_MODULE_LIST is capped separately.
|
||||
export const MAX_MODULES = 1_024
|
||||
|
||||
export type LocationDescriptor = {
|
||||
|
||||
Reference in New Issue
Block a user