2

The BOOL's signature is "B" normally in objective-c, Reference.

But on a 32-bit device. BOOL's signature is "c". Reference

Interesting finding

The interesting thing is that the BOOL in a swift closure is "B" on a 32-bit device (Should be "c").

For example, this is a swift closure.

let closure = {_ in        
} as @convention(block) (Bool) -> Void

The closure's signature is v8@?0B4 on 32-bit device. By right it should be v8@?0c4.

How to verify it?

sh_blockSignature(c code) is the function to get the signature from a block

test.m

enum {
    // Set to true on blocks that have captures (and thus are not true
    // global blocks) but are known not to escape for various other
    // reasons. For backward compatibility with old runtimes, whenever
    // BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a
    // non-escaping block returns the original block and releasing such a
    // block is a no-op, which is exactly how global blocks are handled.
    BLOCK_IS_NOESCAPE      =  (1 << 23),
    
    BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
    BLOCK_HAS_CTOR =          (1 << 26), // helpers have C++ code
    BLOCK_IS_GLOBAL =         (1 << 28),
    BLOCK_HAS_STRET =         (1 << 29), // IFF BLOCK_HAS_SIGNATURE
    BLOCK_HAS_SIGNATURE =     (1 << 30),
};

struct Block_literal_1 {
    void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor_1 {
        unsigned long int reserved;         // NULL
        unsigned long int size;         // sizeof(struct Block_literal_1)
        // optional helper functions
        void (*copy_helper)(void *dst, void *src);     // IFF (1<<25)
        void (*dispose_helper)(void *src);             // IFF (1<<25)
        // required ABI.2010.3.16
        const char *signature;                         // IFF (1<<30)
    } *descriptor;
    // imported variables
};

const char * _Nullable sh_blockSignature(id block)
{
    struct Block_literal_1 *layout = (__bridge void *)block;
    if (!(layout->flags & BLOCK_HAS_SIGNATURE))
        return nil;
    
    void *descRef = layout->descriptor;
    descRef += 2 * sizeof(unsigned long int);
    
    if (layout->flags & BLOCK_HAS_COPY_DISPOSE)
        descRef += 2 * sizeof(void *);
    
    if (!descRef) return nil;
    
    const char *signature = (*(const char **)descRef);
    return signature;
}

test2.swift

let closure = {_ in 
} as @convention(block) (Bool) -> Void
let p = sh_blockSignature(closure)!
let signature = String.init(cString: p)  
print(signature)  // "v8@?0B4"

Is this a swift bug on 32-bit device?

Yanni
  • 580
  • 2
  • 6
  • 21
  • 1
    The BOOL being "c" on 32-bit devices was for back compatibility with existing binaries (since historically there was no bool type in C, so char was used). If there was a new platform, say WKInterface, they might use "B" on 32-bit platforms. I don't think the difference should cause any compatibility issues -- B would still be one byte, just like char. Does the difference manifest itself as a problem somewhere? – Carl Lindberg Jan 02 '21 at 21:20
  • Thanks for your information, @CarlLindberg. Yes, I face a problem with this. I wrote a tool to hook in swift https://github.com/623637646/SwiftHook . I need to verify that a swift closure is matching with the method or not. So in 32-bite device. The BOOL in method is `c` but the BOOL in swift closure is `B`. They are not matching so my framework doesn't work well. I fixed this issue with this commit. https://github.com/623637646/SwiftHook/commit/fbfeb0e41685d2113f0b5de21ed429be6f936bcf – Yanni Jan 03 '21 at 05:17
  • Yup -- had to deal with that in OCMock years ago (see [this commit](https://github.com/erikdoe/ocmock/commit/77400c22b5bafd8aaaa75f90a1d997838204577a)), which was generalized more later in [this commit](https://github.com/erikdoe/ocmock/commit/65ee89744bc1fbb9461f26d83e08243068cb212b) to deal with comparing signatures where one had an opaque struct pointer, and the other had the details -- the same type really, but different text. Others have since fixed bugs and dealt with some C++ evilness, and it's even more complex today. – Carl Lindberg Jan 03 '21 at 08:00

0 Answers0