llvm / llvm/llvm-project

[clang-repl] Unexpected abortion in message sending

Open
#213,858 1 comment 0 reactions 0 assignees View on GitHub
clang-repl
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Summary

In `clang-repl`, any normal Objective-C message send (`[obj msg]`) aborts at runtime with `unrecognized selector` / `NSForwarding` abort. Objective-C++ parsing works, C framework functions (e.g. `NSLog`, `MTLCreateSystemDefaultDevice`) work, constant `@"..."` strings work, and C++ exceptions / static initializers work (with `--orc-runtime`). Only message sends fail.

Root cause appears to be that the JIT-emitted `__objc_selrefs` / `__objc_classrefs` are never uniqued/registered with the Objective-C runtime (the `_objc_map_images` / `_objc_load_image` image-registration that dyld performs at dylib load is not effective for the JITed image), so each selector reference still holds a JIT-range pointer instead of the runtime's uniqued `SEL`.

## Minimal reproducer

```console
$ clang-repl --version
Homebrew LLVM version 22.1.7
Optimized build.

$ ORC=$(dirname $(which clang-repl))/../lib/clang/22/lib/darwin/liborc_rt_osx.a
$ clang-repl --orc-runtime=$ORC --Xcc=-x --Xcc=objective-c++
```
```objectivec
clang-repl> #import
clang-repl> extern "C" int run(){ @autoreleasepool { NSString *s = [NSString stringWithUTF8String:"x"]; return (int)[s length]; } }
clang-repl> printf("len=%d\n", run());
```

### Actual behavior
```
*** NSForwarding: warning: selector (0x10e83100a) for message 'stringWithUTF8String:' does not match selector known to Objective C runtime (0x7ff82f74ae27) -- abort
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSString stringWithUTF8String:]: unrecognized selector sent to class 0x...'
```
(Process aborts.)

### Expected behavior
`len=1` printed; no abort. (Equivalent AOT-compiled program works.)

## Evidence that the cause is selref uniquing, not symbol resolution

1. `MTLCreateSystemDefaultDevice()` (a plain C function) returns a valid device from clang-repl — so framework symbols resolve and frameworks load; only message dispatch fails.
2. `SEL s = @selector(length);` yields a pointer in the JIT address range (`0x10f...`), not the runtime's uniqued selector (`0x7ff8...`).
3. Bypassing the compiler-emitted selref works:
```objectivec
Class c = objc_getClass("NSString");
id (*send)(id, SEL, const char*) = (id (*)(id, SEL, const char*))objc_msgSend;
id s = send((id)c, sel_registerName("stringWithUTF8String:"), "hi"); // OK
```
Explicitly uniquing the selector via `sel_registerName` and calling `objc_msgSend` directly succeeds, confirming the selref slots are simply
never registered.
4. It reproduces for a single self-contained input (one PTU), so it is not specific to incremental additions after JITDylib init — no ObjC input has its metadata registered.

## Environment

- LLVM/clang-repl 22.1.7 (Homebrew).
- macOS 26.5 (Darwin 25.5), running the x86_64 toolchain under Rosetta 2 on an Apple M1 Max. **Not yet confirmed on native arm64** — the mechanism (MachO ObjC section registration in the Orc JIT) is not arch-specific, so it is expected to affect native arm64 as well; maintainers should confirm.
- Launched with `--orc-runtime=liborc_rt_osx.a` (arch-matched x86_64); C++ exceptions confirm the MachO platform + orc runtime are active.

## Relevant code (pointers, not a diagnosis)

- `compiler-rt/lib/orc/macho_platform.cpp` — ObjC registration path: tracks `__llvm_jitlink_ObjCRuntimeRegistrationObject` (`~lines 606, 687`) and calls `_objc_map_images` / `_objc_load_image` (`~lines 1010-1030`); errors "Could not register Objective-C / Swift metadata" if those runtime symbols are absent (this error is NOT emitted in the failing case).
- `llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp` — `processObjCImageInfo` (`~line 1062`) handles `__objc_imageinfo`; the selref/classref uniquing does not appear to take effect for these graphs.
- `clang/lib/Interpreter/IncrementalExecutor.cpp:~308` — sets up `ExecutorNativePlatform(OrcRuntimePath)`.

Contributor guide

Open the contributing guide

Research direction

Reproduce the failure with the supplied clang-repl Objective-C++ input and --orc-runtime setup. Read llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp at processObjCImageInfo, then trace compiler-rt/lib/orc/macho_platform.cpp and clang/lib/Interpreter/IncrementalExecutor.cpp. Done means the same input prints len=1 without an Objective-C runtime abort, including the emitted selector references.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, objective-c
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.