📜 ⬆️ ⬇️

Cyclic containers in Objective-C

Some time ago I wrote this code:

NSMutableArray *environments = [NSMutableArray new]; for (NSString *key in [dictionary allKeys]) { XCCEnvironment *environment = [[XCCEnvironment alloc] initWithName:key parameters:dictionary[key]]; [environments addObject:environments]; } return environments; 

Notice the problem? Me not.

Problem


After starting the program, I caught a crash:

 [__NSArrayM someSelector]: unrecognized selector sent to instance 0x100211d80 

The 'environments' handler expected 'XCCEnvironment', and got 'NSMutableArray'.
')
At first it was not clear why this happened, but when I looked at the code, I noticed that I just put the array in the same array:

 // ... NSMutableArray *environments = [NSMutableArray new]; // ... [environments addObject:environments]; // ... 

Documentation says nothing about the behavior of collections in such situations, the only useful material that I found on this subject is Mike Ash's article Let's break Cocoa .

The article states that mutable arrays, dictionaries and sets go crazy if you create a so-called cyclic container. In addition, when ARC is enabled, a memory leak appears - the collection keeps itself.

Decision


Usually, developers do not put the collection inside themselves. This is as true as the statement that programmers do not dereference null pointers — this is still happening and probably this is not what the programmer expects.

I was absolutely sure that clang can prevent this error, but did not find any parameters / settings that include this check.

In the end I decided to add this check. The implementation took a couple of nights, but now it is on the trunk .

The patch includes checking the following collections:


and shows a warning if you are trying to add the collection inside it.
The warning can be enabled / disabled by means of the flags '-wobjc-circular-container' / '- wno-objc-circular-container', respectively, although it is enabled by default.

Conclusion


The clang version of the trunk contains this functionality, but it is not yet available in Xcode, I believe that it will appear there after the next major release, maybe in a year.

Anyway, having an open source compiler is great: you can fix it, improve it and make your life and the lives of others a little easier.

Happy hacking!

Source: https://habr.com/ru/post/258249/


All Articles