Hi, 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): 2020-04-13 16:08:47.544 Test[48495:1640682] Calling [a run] for <A: 0x7ffd99d01ae0> 2020-04-13 16:08:47.545 Test[48495:1640682] method: <null> with: 0x7ffedfc11798 2020-04-13 16:08:47.545 Test[48495:1640682] Calling [b run] for <B: 0x7ffd99d03a90> 2020-04-13 16:08:47.545 Test[48495:1640682] method: NSNull with: 0x7ffedfc11798 2020-04-13 16:08:47.545 Test[48495:1640682] Calling [c run] for <C: 0x7ffd99d03c20> 2020-04-13 16:08:47.545 Test[48495:1640682] method: <null> with: 0x7fffada0af60 but with clang and libobjc2 I get this: 2020-04-13 16:11:17.464 Test1[17213:17213] Calling [a run] for <A: 0x1ab1be8> 2020-04-13 16:11:17.465 Test1[17213:17213] method: <null> with: 0x7fff7219f738 2020-04-13 16:11:17.465 Test1[17213:17213] Calling [b run] for <B: 0x1ab3578> 2020-04-13 16:11:17.466 Test1[17213:17213] In base implementation of -method:with: 2020-04-13 16:11:17.466 Test1[17213:17213] Calling [c run] for <C: 0x1ab4f08> 2020-04-13 16:11:17.466 Test1[17213:17213] In base implementation of -method:with:
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. I would have expected an unrecognized selector exception to be raised instead, as happens with Apple's Foundation: 2020-04-13 16:13:34.742 Test[48512:1642397] -[D initWithObject:ptr:]: unrecognized selector sent to instance 0x7fecbb704a00 2020-04-13 16:13:34.743 Test[48512:1642397] Caught exception -[D initWithObject:ptr:]: unrecognized selector sent to instance 0x7fecbb704a00 2020-04-13 16:13:34.743 Test[48512:1642397] Calling [e run] for <E: 0x7fecbb407890> 2020-04-13 16:13:34.743 Test[48512:1642397] -[E method:pointer:]: unrecognized selector sent to instance 0x7fecbb407890 2020-04-13 16:13:34.743 Test[48512:1642397] Caught exception -[E method:pointer:]: unrecognized selector sent to instance 0x7fecbb407890 Just for reference here's the output with libobjc2 and GNUstep-base 2020-04-13 16:18:10.644 Test2[17264:17264] Calling [d run] for (null) 2020-04-13 16:18:10.645 Test2[17264:17264] Calling [e run] for <E: 0x1cc65c8> Wolfgang
GNUmakefile
Description: Binary data
Test1.m
Description: Binary data
Test2.m
Description: Binary data