From a9af7d7095105a815c848488322f6ffb2e86b10c Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Mon, 18 Nov 2024 21:15:32 +0000 Subject: [PATCH 1/2] msgSend: Return `nil` if the dtable cannot be loaded Under some circumstances, apparently when two classes with the same name exist in two different modules, the dtable for a class can be null. This would cause a crash in `msgSend`. Update `msgSend` to return `nil` instead. --- objc_msgSend.x86-64.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/objc_msgSend.x86-64.S b/objc_msgSend.x86-64.S index 10ecd163..067016a0 100644 --- a/objc_msgSend.x86-64.S +++ b/objc_msgSend.x86-64.S @@ -35,6 +35,8 @@ mov (\receiver), %r10 # Load the dtable from the class 1: # classLoaded mov DTABLE_OFFSET(%r10), %r10 # Load the dtable from the class into r10 + test %r10, %r10 # If the dtable is nil + jz 4f # return nil mov %rax, -8(%rsp) # %rax contains information for variadic calls mov %rbx, -16(%rsp) # On the fast path, spill into the red zone mov (\sel), %eax # Load the selector index into %eax From 293ea14f9e5f6d65215d7ee35bcdaec2fca625a4 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Thu, 21 Nov 2024 12:52:51 +0000 Subject: [PATCH 2/2] Add benchmark --- benchmarks/CMakeLists.txt | 6 ++++++ benchmarks/TestClass.m | 10 ++++++++++ benchmarks/objc_msgSend.cpp | 23 +++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 benchmarks/CMakeLists.txt create mode 100644 benchmarks/TestClass.m create mode 100644 benchmarks/objc_msgSend.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 00000000..c6c20ac8 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,6 @@ +find_package(benchmark REQUIRED) + +add_executable(objc_msgSend objc_msgSend.cpp TestClass.m) + +target_compile_options(objc_msgSend PRIVATE "-fobjc-runtime=gnustep-2.0") +target_link_libraries(objc_msgSend benchmark::benchmark objc) diff --git a/benchmarks/TestClass.m b/benchmarks/TestClass.m new file mode 100644 index 00000000..d3d85a28 --- /dev/null +++ b/benchmarks/TestClass.m @@ -0,0 +1,10 @@ +@interface TestClass +- (int)answer; +@end + +@implementation TestClass +- (int)answer +{ + return 42; +} +@end diff --git a/benchmarks/objc_msgSend.cpp b/benchmarks/objc_msgSend.cpp new file mode 100644 index 00000000..5f073168 --- /dev/null +++ b/benchmarks/objc_msgSend.cpp @@ -0,0 +1,23 @@ +#include +#include "../objc/runtime.h" +#include + +static id testClass; +static SEL answerSel; + +static void objc_msgSendSetup(const benchmark::State& state) { + testClass = objc_getClass("TestClass"); + answerSel = sel_registerName("answer"); +} + +static void objc_msgSend(benchmark::State& state) { + for (auto _ : state) + { + id a = objc_msgSend(testClass, answerSel); + assert((uintptr_t)a == 42); + } + } + // Register the function as a benchmark + BENCHMARK(objc_msgSend)->Setup(objc_msgSendSetup)->Repetitions(25); + + BENCHMARK_MAIN();