NSMutableDictionary count / allKeys / allValues inconsistencies on big collections

Originator:vbenony
Number:rdar://45605829 Date Originated:2018/10/26
Status:Open Resolved:
Product:Foundation Product Version:
Classification:bug Reproducible:always
 
Summary:
It appears that the value returned by the "count" method on NSMutableDictionary is truncated modulo 0x2000000. NSDictionary is not affected.
For instance, invoking "count" on a mutable dictionary which contains exactly 0x2000000 items will return 0. Also, in that case, the methods "allKeys" and "allValues" return empty arrays.
Enumerating the dictionary shows that items are still there, and it is possible to count them with a simple for loop.

Steps to Reproduce:
Take a look at the small attached Objective-C program.

-----------------------------------------------------------------------------------------
#import <Foundation/Foundation.h>


int main (int argc, char const *argv[]) {
    NSMutableArray *a = [NSMutableArray array];
    for (uint64_t x=1; x<=0x2123456; x++) {
        [a addObject:@(x)];
    }

    NSLog(@"Array count: 0x%lx (should be 0x2123456)", a.count);
    
    NSDictionary *d1 = [NSDictionary dictionaryWithObjects:a forKeys:a];
    NSMutableDictionary *d2 = [d1 mutableCopy];
    NSLog(@"Count on built NSDictionary:        0x%lx (should be 0x2123456)", d1.count);
    NSLog(@"Count on built NSMutableDictionary: 0x%lx (should be 0x2123456)", d2.count);
    
    NSMutableDictionary *d = [NSMutableDictionary dictionary];
    for (uint64_t x=1; x<=0x2123456; x++) {
        d[@(x)] = @(x);
        if (d.count != x) {
            NSLog(@"count = 0x%lx (should be 0x%llx)", d.count, x);
            NSLog(@"keys: %@", d.allKeys);
            NSLog(@"values: %@", d.allValues);

            __block uint64_t cnt1 = 0;
            [d enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) { cnt1++; }];
            NSLog(@"Counting by hand with enumerateKeysAndObjectsUsingBlock: = 0x%llx (should be 0x%llx)", cnt1, x);

            uint64_t cnt2 = 0;
            for (id k in d) { cnt2++; }
            NSLog(@"Counting by hand with a for loop = 0x%llx (should be 0x%llx)", cnt2, x);

            break;
        }
    }

    return 0;
}

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!