Skip to content

fix(error-tracking): correct frame addresses, ordering, and in-app detection#549

Open
hpouillot wants to merge 2 commits intomainfrom
fix/error-tracking-frame-correctness
Open

fix(error-tracking): correct frame addresses, ordering, and in-app detection#549
hpouillot wants to merge 2 commits intomainfrom
fix/error-tracking-frame-correctness

Conversation

@hpouillot
Copy link
Copy Markdown
Contributor

What

Four correctness fixes for iOS stack trace capture.

Fixes

Zero-padded addresses
Instruction addresses are now formatted as 16-digit zero-padded hex (0x%016llx), consistent with what cymbal expects for address lookup.

PAC bit stripping (arm64e)
Modern iPhones embed pointer authentication codes in the high bits of pointers. Addresses are now masked with 0x0000_000f_ffff_ffff before being stored, so dladdr lookups and cymbal symbolication work correctly on arm64e devices.

Frame ordering
Both PostHogExceptionProcessor and PostHogCrashReportProcessor were emitting frames in top-down order (crash site first). The Sentry event format that cymbal consumes expects bottom-up (outermost/main first, crash site last). Frames are now reversed before serialization.

System path detection
isInApp() was only checking a hardcoded list of module names for system frameworks. Private frameworks not in that list (e.g. Gestures, Accessibility from UIKitCore) were incorrectly marked as in-app. A new isSystemPath() helper checks the binary path against /System/ and /usr/lib/ prefixes, covering both device and Simulator paths.

…tection

Four correctness fixes for iOS stack trace capture:

- Zero-pad instruction addresses to 16 hex digits (0x%016llx) so the
  format is consistent and cymbal can always parse them reliably.

- Strip PAC bits from arm64e pointers (mask 0x0000_000f_ffff_ffff)
  before storing addresses. Modern iPhones embed pointer authentication
  codes in the high bits; without stripping, dladdr lookups and cymbal
  symbolication fail or produce wrong results.

- Reverse frames to bottom-up order (outermost/main first, crash site
  last) in both PostHogExceptionProcessor and PostHogCrashReportProcessor.
  callStackReturnAddresses and PLCrashReport both deliver frames top-down;
  the Sentry event format (which cymbal consumes) expects bottom-up.

- Add isSystemPath() helper to PostHogStackTraceProcessor to catch system
  binaries not in the hardcoded module-name list (e.g. private frameworks
  like 'Gestures', 'Accessibility' from UIKitCore) by checking their
  binary path against /System/ and /usr/lib/ prefixes. Pass package path
  to isInApp() so the path check is applied.
@hpouillot hpouillot requested a review from a team as a code owner April 3, 2026 17:05
…ked in-app

Two complementary fixes for frames that dladdr cannot resolve to a path:

1. When dladdr succeeds but dli_fname is nil (e.g. shared-cache private
   frameworks like Gestures/UIKitCore on Simulator, or on-device dyld
   shared cache binaries), inApp now defaults to false instead of
   falling through to inAppByDefault=true. We have no evidence that a
   frame with no resolvable binary path is user code.

2. Extend systemPrefixes with known private UIKit sub-frameworks
   (Gestures, UIKitCore, Accessibility, UpdateCycle, TextInput, etc.)
   and common system dylibs (libobjc, dyld, libsystem_c, etc.) so that
   frames from these modules are rejected by isSystemFramework() even
   when dladdr does return a path.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

posthog-ios Compliance Report

Date: 2026-04-03 17:34:24 UTC
Duration: 512ms

✅ All Tests Passed!

0/0 tests passed


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