On 13/04/2020 15:23, Wolfgang Lux wrote:
I've just recently come across a strange issue where the MySQL interface in the SQLClient library had stopped working with a weird error when using the libobjc2 runtime. In particular, the code was complaining that the backendQuery:recordType:listType: method was called without a loaded bundle. A debugging session later it was clear that the MySQL backend bundle was actually loaded into the program and that the backendQuery:recordType:listType: was available inside the bundle, but that the runtime simply refused to call the override and just called the implementation in the SQLClient base class instead, which emits the error message. A more careful look at the code revealed a subtle difference between the definition of the backendQuery:recordType:listType: method in the SQLClient class and its MySQL bundle subclass: While the former (and all other backend bundles) uses id parameters for the record and list type arguments, the MySQL bundle was using Class parameters instead. This resulted in slightly different method signatures (@40@0:8@16@32 vs. @40@0:8#16#32 on a 64-bit architecture) and the libobjc2 method dispatch apparently is rather picky about those signatures. As I've already changed the SQLClient library to use consistent types, I've condensed the issue into a little test program (Test1.m) below. The output for this on macOS with Apple's Foundation looks like this (and for GNUstep with gcc and the gcc runtime it looks similar):
Calling a method with the wrong signature is undefined behaviour in Objective-C. The Apple runtime just ignores the type entirely and will happily corrupt your stack in a few cases. We try to allow it in benign cases, which probably should include `Class` vs `id`, though I'm not entirely convinced: it's fine to pass a `Class` to something that expects an `id`, but passing an arbitrary object to something that expects a `Class` can cause exciting breakage.
And while I was writing that test program, I accidentally uncovered another bug in the libobjc2 runtime (see Test2.m): When calling super with a method that isn't implemented by the super class (or its own ancestors) libobjc2 simply does nothing, as if the method was called against nil.
This is a bug. Please open an issue on GitHub so that I can track it. David