Skip to content

[objective_c] 9.6.3 debug assert rejects valid ObjCProtocolBuilder instances on the iOS simulator #3786

Closed

Description

@tarrinneal

Summary

Since 9.6.3 ("Replace the expensive debug assert that blocks and objects are
valid with a cheaper and safer check"), ObjCProtocolBuilder.build() can fail in
debug mode on the iOS simulator with:

Unhandled Exception: 'package:objective_c/src/internal.dart': Failed assertion:
line 270 pos 12: '_isValid(_finalizable.ptr)': is not true.
#0 _ObjCReference (package:objective_c/src/internal.dart:270)
#1 ObjCObjectRef
#2 DartProtocol.fromPointer
#3 DartProtocolBuilder$Methods.buildInstance
#4 ObjCProtocolBuilder.build (package:objective_c/src/protocol_builder.dart:84)

The object is valid. 9.6.2 accepts it, and the same code passes there.

Cause

DOBJC_isValidObject reads the class pointer from a non-pointer isa using
objc_debug_isa_class_mask. On the iOS simulator (arm64, Xcode 26), that mask
is 0x0000000ffffffff8 (36 bits). ObjCProtocolBuilder creates its class with
objc_allocateClassPair, so the class lives on the heap at an address above
2^36 (for example 0x6000…), and the runtime packs that full address into the
isa anyway.

Values logged from inside DOBJC_isValidObject:

obj      = 0x6000002a4480
isa      = 0x100600000c7e161
objc_debug_isa_magic_mask  = 0x1
objc_debug_isa_magic_value = 0x1
objc_debug_isa_class_mask  = 0xffffffff8

isa & objc_debug_isa_class_mask = 0xc7e160        -> not readable -> returns false
isa & 0x00007ffffffffff8        = 0x600000c7e160  -> the actual heap-allocated class

Classes in the shared cache or the app binary fit in 36 bits, so the bug only
appears for runtime-allocated classes at high heap addresses. That makes it
depend on where the allocation happens to land. We hit it consistently in a
second FlutterEngine's isolate.

Repro

flutter/packages packages/pigeon (PR flutter/packages#13576):

cd packages/pigeon/platform_tests/test_plugin/example
flutter pub upgrade   # resolves objective_c 9.6.3
flutter build ios --simulator --no-codesign --debug
cd ios
xcodebuild test -workspace Runner.xcworkspace -scheme Runner \
  -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 16' \
  '-only-testing:RunnerTests/RunnerTests/liveSecondaryEnginesExecuteDartIsolatesAcrossOutOfOrderDestroy()'

This fails on 9.6.3 and passes on 9.6.2.

Suggested fix

Don't rely on objc_debug_isa_class_mask on the simulator. Some options:

  • Fall back to object_getClass once the isa is known to be readable and to
    have the right magic bits.
  • Accept the object if either the debug mask or the wider simulator/macOS mask
    gives a readable class.

Activity

  1. self-assigned this
    on Nov 8, 2026
  2. liamappelbe commented on Nov 11, 2026

    @liamappelbe
    Contributor

    Fix is published in v9.6.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions