<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/56680>56680</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Retain count imbalanced when calling ObjC synthesized property getters for structs with ARC object pointer fields
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          patters
      </td>
    </tr>
</table>

<pre>
    In 2018 [Apple announced](https://devstreaming-cdn.apple.com/videos/wwdc/2018/409t8zw7rumablsh/409/409_whats_new_in_llvm.pdf) support for ARC object pointers in C structures in LLVM. We have observed that when such a `struct` is the type of a property with a **synthesized** getter, the implementation lacks any reference counting semantics. This leads to crashes when using the getter:

```objc
#import <Foundation/Foundation.h>

struct Box {
    NSObject *value;
};

@interface Container : NSObject
@property (nonatomic, readonly) struct Box box;
@end

@implementation Container

- (instancetype)init {
    self = [super init];
    if (self) {
        _box.value = [NSObject new];
    }
    return self;
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Container *c = [Container new];
        [c box];
        c = nil;
    }
    return 0;
}
```

Build and run on macOS, and observe the overrelease by enabling zombies:

```
% clang -fobjc-arc main.m   
% NSZombieEnabled=YES ./a.out 
2022-07-22 18:00:34.449 a.out[30814:150315661] *** -[NSObject release]: message sent to deallocated instance 0x600001004040
zsh: illegal hardware instruction  NSZombieEnabled=YES ./a.out
```

Here, we construct an Objective-C object that holds a struct with ARC fields, and allow a property getter to be synthesized. Callers of the getter assume copies are returned, so clean them up afterwards (calling `__destructor_8_s0`). As we nil the reference to the Objective-C object, it is deallocated, which attempts to release the struct fields again, and we crash.

If we implement the getter ourselves (e.g. `- (struct Box)box { return _box; }`), the compiled output **does** create a copy (via `__copy_constructor_8_8_s0`) of the `struct`, bumping the right retain counts, we don't overrelease and don't crash.

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJyFVl2vozYQ_TXkxQoiQL4e8pCbu1ddabsr7a1atS-RARPcgo1sk2zur-8ZAwm5u-2SKBAzno8zM2ec6eK6-6hYHC02LFg-7du2FowrpTuViyJYPgfxpnKutUGyD-IXfAtxts4I3kh1mueFCjntCXPd4OVZFkJbPFwuRY4b6cUtjbZu83ZZm67hWW2rfqn_PV4q7uxRictRqmNdn5uwLcog3jLbta02jpXasP3XA9PZ3yJ3rNVSOWEsk4odGHzpctcZ4f9_-vT7ryH7Q7CKnwU2WGHOomAOJtilEgo684pxFqyifiMemLQQEMxdW2wp8bY1uhXGXdlFOi8dI_a9vSqIWfkGXPwCOwkHR4L44PfLBjg0QjnupFas5vk_FlBemRGlMAJ4shywOuDGrGg4nnIbst8q2K8FL-CFZrnhFkZ6ZztLsqR7sIQcRM9BNP6uov4LYPJhKU7gBoEWJIcXWCu8M0D6_iesguTDVE-PBHvS31iwfurXGK7Pr196xBHrmdedCJLhbbB-vj_3v2nks1JyhHnQAEEqYeDF_qbmJniDF7WltOJONzInFFFVhVb11Sf_7lSmv92tpZFQxXvLj8jfzE_F5mRNKus4EkGphhGppHsM2Yq6hNPP1AsoP0RAMtQGyURKlqSMZMnTBwV0HeFw6AEbVd2QRJW_V0ZY3v4YgVJW3o0HsB_jfYcAgGcNAvYBOsbNyaOZa0TL8oobSiAtn-GKb-l3TkMl75w2AmVoRat1_X1Qk5zG-3wM7L76g8i86uVT7hP4g3e9FiXrn-IR_QCMsfinSDx1si7QcwUznWIohYbnX14JDFob6MA3lD4LM8TLsisTCrxEzfamm0wK-1-dNnbZkuU1h_i8pN6bc5P7DIQNBXCT-fz6l1f3gbSDNZLnPz-8shDdyEPduUEyjuJ4Hq3nccxAlsk-QrT7JA3TdMu8HDBMos0ixfJiGSWL5Wq1AJ4DLVFu59MaG8LyiO9ZI6zlJ4GSQmmAYArB61rn3IEWx3Zg0bdVhGsRRSk-vVtvoGnsl3UtTrwGoZriwo3wm6g1qdN-FuH_pOoXUCIl5iL6QvXdzhXrg5BnMb8RvmfvStdgSD7ygmdmGgqlFHgxpphiu0wZvCdOCjwDBncGD9kBsjRFwPh3hmXc2q4hl1pUAaN4-xIkzsewAUEDXEU7Gta1jJfYBFjgGrovh0oqIoR6PBaid1Wb4-ZoffjxNmR7SyGj6L3V-2iAh7TwffhkFzSFITFJnUeukjTL4HbTOj88xoImRQNOPTyMnzw_9CAR5DRmwmk-Ppa0fmPSKSa6MyCks_AxivAUUoCeT-8kjdiyfn6MPXvsadv3s499nJM4KbQSxQK9ru3cUMaFRtf11ZxjDjicQigLfkicJe8xpYXjrVw8sndsx0xOZzvZzDrYG-aokaeKOoRIq5_GdijCgqbk2j0QA4E1rk8RmxW7pNgmWz5z0tVi93WiDxBmvKauKvohPhYFMnuYVuD7GrX-nNN7bu_1_XjoGfI560y9ezyWnbChy4ZjGJ2ihtscZvoyepGobQL5BQSyiWbVbsOXHE9xlKSr5WZZLkW0yIp1sSlTwdfrYlbzTNR214-NmdwRVUXrmK5VvAzTIs3ibZmUabrELaLRBBqsQ3-K0-Y0MzvvQ9adLF7W0jp7f4lekyclxKgfM6jSZtdyD8fMu7vzvv4LJ-xUtA">