NSDictionary == NSMutableDictionary #pragma


yetanothermeagain
 

Xcode (tested with 10, and Xcode 11 Betas) allows a pointer to NSDictionary* (a pointer to a pointer) be used instead of a pointer to NSMutableDictionary*, which leads to a runtime crash instead of expected compilation error. I submitted a bug about it, but the bug returned with "works with clang-1001.0.46.3 which is part of Xcode 10.2". i wonder what that means to me as I do not use clang in terminal, only via Xcode. Can / should I somehow change the clang version that is used by Xcode?

 

a side question, are there several versions of clang installed with Xcode and for whatever reason Xcode is not using the latest one?

 

void foo(NSMutableDictionary** mutableDictionary) {

    (*mutableDictionary)[@"hello"] = @"world";

}

 

...

    NSDictionary* dictionary = [NSDictionary new];

    foo(&dictionary); // no compilation error here!

 

    // runtime error:

    // *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionary0 setObject:forKeyedSubscript:]: unrecognized selector sent to instance

....

 

originally rdar://49775697

plus FB6447069, this time against Xcode


 

They mean that the bug is fixed (or not reproducible) in the newer Clang in Xcode 12.

You cannot change the version of Clang in Xcode. You’ll have to download the Xcode 12 beta.

—Jens


Jack Brindle
 

Is this really a bug? NSMutableDictionary is based on NSDictionary, so if you have an NSMutableDictionary, an NSDictionary * pointing to it is valid. This is true for all objects derived from other objects. To put it another way, you could point at all of your objects with NSObject *pointers, just don’t ask me to debug it for you. If you referenced all of your objects as [object method], including the properties, then theoretically it would work just fine, as long as the objects actually implemented the method you are invoking.

You might want to check to make sure the methods are implemented in the object if you are going to use an NSDictionary as a pointer to an NSMutableDictionary, or check to make sure what kind of object you are actually working with before using it.

One other thing - when you alloc/init a cluster class such as an NSString, you most likely will not get an NSString back. Instead you may get an NSConcreteString, or a wide array of other variances. This is just another example for why this is really not  bug, but a feature of the language.

Just make sure you keep track of your objects and you will do well.


Xcode uses the currently selected version of Xcode. DO a man on xcodeselect for details.

Jack

On Jul 6, 2019, at 2:19 PM, yetanothermeagain <gofennex@...> wrote:

Xcode (tested with 10, and Xcode 11 Betas) allows a pointer to NSDictionary* (a pointer to a pointer) be used instead of a pointer to NSMutableDictionary*, which leads to a runtime crash instead of expected compilation error. I submitted a bug about it, but the bug returned with "works with clang-1001.0.46.3 which is part of Xcode 10.2". i wonder what that means to me as I do not use clang in terminal, only via Xcode. Can / should I somehow change the clang version that is used by Xcode?

 

a side question, are there several versions of clang installed with Xcode and for whatever reason Xcode is not using the latest one?

 

void foo(NSMutableDictionary** mutableDictionary) {

    (*mutableDictionary)[@"hello"] = @"world";

}

 

...

    NSDictionary* dictionary = [NSDictionary new];

    foo(&dictionary); // no compilation error here!

 

    // runtime error:

    // *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionary0 setObject:forKeyedSubscript:]: unrecognized selector sent to instance

....

 

originally rdar://49775697

plus FB6447069, this time against Xcode



Steve Mills
 

On Jul 6, 2019, at 18:04, Jack Brindle via Groups.Io <jackbrindle@...> wrote:

Is this really a bug?
Yes. Re-read the example. If the function takes NSMutableDictionary**, it should complain when you pass it an NSDictionary**, same as if it wants NSMutableDictionary* and you pass it NSDictionary*.

The opposite, however, is perfectly fine and correct; passing an NSMutableDictionary (with any number of splats) to a function that wants an NSDictionary. That’s how subclassing works.

Steve via iPad


yetanothermeagain
 


but when i build this exact source from terminal i am getting the warning (or error if warnings are treated as errors) as expected!


clang main.m -Werror

> main.m:10:13: error: incompatible pointer types passing 'NSDictionary **' to parameter of type

      'NSMutableDictionary **' [-Werror,-Wincompatible-pointer-types]

        foo(&dictionary);

            ^~~~~~~~~~~

main.m:3:32: note: passing argument to parameter 'mutableDictionary' here

void foo(NSMutableDictionary** mutableDictionary) {

                               ^

1 error generated.


clang version is this:

> clang -v
> Apple LLVM version 10.0.0 (clang-1000.11.45.5)

Target: x86_64-apple-darwin18.6.0

Thread model: posix

InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin


and when I compile with Xcode i see the same path:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang


====================

#import <Foundation/Foundation.h>

 

void foo(NSMutableDictionary** mutableDictionary) {

    (*mutableDictionary)[@"hello"] = @"world";

}

 

int main(int argc, const char* argv[]) {

    @autoreleasepool {

        NSDictionary* dictionary = [NSDictionary new];

        foo(&dictionary);

    }

    return 0;

}

 


yetanothermeagain
 


i tracked the difference down to this: "clang main.m -Werror -fobjc-arc"
the "-fobjc-arc" is the one that causes the trouble. and we can't create modern apps without using arc these days.

it looks like the apple responder to my bug report just didn't use the "-fobjc-arc" key, so it worked for him and thus he replied with "it works in" whatever version of Xcode / clang he happened to have on his machine without properly investigating the cause of the problem... i can see the same happening with Xcode 11 beta 2 (clang-1100.0.20.17). will update my bug report with this information.

is Xcode 12 beta already out?


 

On Jul 7, 2019, at 5:01 AM, yetanothermeagain <gofennex@...> wrote:

is Xcode 12 beta already out?
Yes, it’s been out since WWDC a month ago. You can download beta 3 now; it’s pretty solid.

—Jens


Marco S Hyman
 

is Xcode 12 beta already out?
Yes, it’s been out since WWDC a month ago. You can download beta 3 now; it’s pretty solid.
You’re off a digit. Current Xcode is 10.2.1. Beta Xcode is 11.0. 12 is still in the future.

Marc


 

On Jul 7, 2019, at 11:05 PM, Marco S Hyman <marc@...> wrote:


is Xcode 12 beta already out?
Yes, it’s been out since WWDC a month ago. You can download beta 3 now; it’s pretty solid.
You’re off a digit. Current Xcode is 10.2.1. Beta Xcode is 11.0. 12 is still in the future.
*facepalm*
That’s what I get for emailing on my iPad. Sorry!

—Jens


yetanothermeagain
 

Fast forward 2022 Xcode 13 - This is still unfixed, I still see no warning/error - and then the crash with ARC enabled (the crash is expected in this case, the absence of error or warning - not).


Ben Kennedy
 

Interesting find.

Because this amuses me, particularly as it's so easily reproducible yet symptomatic of Apple's incapacity to address basic bugs, I've filed my own bug using your code sample: FB10228325.

(What's your bug number? Could add a cross-reference from mine.)

-ben

On 13 Jun 2022, at 9:17 am, yetanothermeagain <gofennex@...> wrote:

Fast forward 2022 Xcode 13 - This is still unfixed, I still see no warning/error - and then the crash with ARC enabled (the crash is expected in this case, the absence of error or warning - not).


yetanothermeagain
 

Thank you for filing the bug!
Mine was "originally rdar://49775697 plus FB6447069, this time against Xcode"

Apple's incapacity to address basic bugs

Understandably Obj-C is not the focus anymore for a number of years.


Alex Zavatone
 

What’s the specific error?

I don’t see the explanation in the email thread.  It’s possible my coffee levels are too low.  Do I need another cup?

Thanks, 
Alex Zavatone

On Jun 13, 2022, at 12:00 PM, yetanothermeagain <gofennex@...> wrote:

Thank you for filing the bug!
Mine was "originally rdar://49775697 plus FB6447069, this time against Xcode"

Apple's incapacity to address basic bugs

Understandably Obj-C is not the focus anymore for a number of years.


Alex Zavatone
 


Thanks for the explanation, Ben.

Silly question.  Does this fall under the case of “yes, Apple, fix this” or “OK, now you know.  Don’t do that.”  

Or both?

Sort of a “yes you can do this but you should know better” or does this actually fall under a valid use of the language?

Curious.  

TIA,
Alex Zavaotne

On Jun 13, 2022, at 12:53 PM, Alex Zavatone via groups.io <zav@...> wrote:

What’s the specific error?

I don’t see the explanation in the email thread.  It’s possible my coffee levels are too low.  Do I need another cup?

Thanks, 
Alex Zavatone

On Jun 13, 2022, at 12:00 PM, yetanothermeagain <gofennex@...> wrote:

Thank you for filing the bug!
Mine was "originally rdar://49775697 plus FB6447069, this time against Xcode"

Apple's incapacity to address basic bugs

Understandably Obj-C is not the focus anymore for a number of years.



Ben Kennedy
 

On 13 Jun 2022, at 12:15 pm, Alex Zavatone via groups.io <zav@...> wrote:

Silly question. Does this fall under the case of “yes, Apple, fix this” or “OK, now you know. Don’t do that.”

Or both?

Sort of a “yes you can do this but you should know better” or does this actually fall under a valid use of the language?
Whose opinion are you seeking?

At least two of us participating in this discussion feel that this demonstrates an obvious compiler bug, which is why we've filed reports. I haven't seen a contrary argument (unless I missed it).

-ben


Alex Zavatone
 

On Jun 13, 2022, at 2:48 PM, Ben Kennedy <ben-groups@...> wrote:



On 13 Jun 2022, at 12:15 pm, Alex Zavatone via groups.io <zav@...> wrote:

Silly question. Does this fall under the case of “yes, Apple, fix this” or “OK, now you know. Don’t do that.”

Or both?

Sort of a “yes you can do this but you should know better” or does this actually fall under a valid use of the language?
Whose opinion are you seeking?

At least two of us participating in this discussion feel that this demonstrates an obvious compiler bug, which is why we've filed reports. I haven't seen a contrary argument (unless I missed it).

-ben
Just any of the list members. The fact that two of us feel it is a compiler bug and not a valid use certainly matters. I was just thinking that it was worth asking since I’ve never even tried pointers to pointers because from what I’ve learned, it’s just asking for trouble.

Cheers,
Alex Zavatone


Ben Kennedy
 

On 13 Jun 2022, at 1:22 pm, Alex Zavatone via groups.io <zav@...> wrote:

Just any of the list members. The fact that two of us feel it is a compiler bug and not a valid use certainly matters. I was just thinking that it was worth asking since I’ve never even tried pointers to pointers because from what I’ve learned, it’s just asking for trouble.
I'm not sure I'm following your line of inquiry (surely, the language and the compiler are supposed to be well-specified and deterministic). But I feel it's worth pointing out that double indirection is often used in Obj-C API, typically for returning things by reference; you've probably used it a bunch yourself, particularly in `NSError **` arguments.

-ben


Alex Zavatone
 

On Jun 13, 2022, at 4:23 PM, Ben Kennedy <ben-groups@...> wrote:


On 13 Jun 2022, at 1:22 pm, Alex Zavatone via groups.io <zav@...> wrote:

Just any of the list members. The fact that two of us feel it is a compiler bug and not a valid use certainly matters. I was just thinking that it was worth asking since I’ve never even tried pointers to pointers because from what I’ve learned, it’s just asking for trouble.
I'm not sure I'm following your line of inquiry (surely, the language and the compiler are supposed to be well-specified and deterministic). But I feel it's worth pointing out that double indirection is often used in Obj-C API, typically for returning things by reference; you've probably used it a bunch yourself, particularly in `NSError **` arguments.

-ben
Perhaps I should have said “I’ve never implemented methods in that manner myself.”


yetanothermeagain
 

Ben, the original "radar" I filed was converted to FB6064383. Current status - open.


Ben Kennedy
 

To my shock and surprise, I received a response from Apple on Friday, a mere 11 days after filing it (FB10228325) !

For reference, my report included the following code (lifted from the original thread):

@import Foundation;

void foo(NSMutableDictionary** mutableDictionary)
{
(*mutableDictionary)[@"hello"] = @"world";
}

int main(int argc, const char * argv[])
{
NSDictionary* dictionary = [[NSDictionary alloc] init];
foo(&dictionary); // no compilation error here!
return 0;
}
The Apple reply is as follows:

Is it necessary for foo to take parameter NSMutableDictionary**? Can you change it to NSMutableDictionary*`?

void foo(NSMutableDictionary* mutableDictionary)
{
mutableDictionary[@"hello"] = @"world";
}

We don’t think clang should reject the code just because it is passing a NSDictionary** to a function expecting a NSMutableDictionary**. We don’t want to reject the following code, for example:

void foo(NSMutableDictionary** mutableDictionary)
{
NSMutableDictionary* md = [[NSMutableDictionary alloc] init];
*mutableDictionary = md;
}

foo is assigning a pointer to a newly created NSMutableDictionary object to dictionary, which is an NSDictionary pointer, in main.
I don't think I understand the reasoning offered by the Apple respondent, but before I reply, I wanted to see if it's meaningful to anyone else.

Whether or not foo() takes a double indirection, and despite what it might do in its body, I don't see how the suggested change remedies the error of passing an immutable dictionary reference at the call site in main().

-ben