1*67e74705SXin Li// RUN: %clang_cc1 -analyze -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues,osx.coreFoundation.containers.OutOfBounds -analyzer-store=region -triple x86_64-apple-darwin -verify %s 2*67e74705SXin Li 3*67e74705SXin Litypedef const struct __CFAllocator * CFAllocatorRef; 4*67e74705SXin Litypedef const struct __CFString * CFStringRef; 5*67e74705SXin Litypedef unsigned char Boolean; 6*67e74705SXin Litypedef signed long CFIndex; 7*67e74705SXin Liextern 8*67e74705SXin Liconst CFAllocatorRef kCFAllocatorDefault; 9*67e74705SXin Litypedef const void * (*CFArrayRetainCallBack)(CFAllocatorRef allocator, const void *value); 10*67e74705SXin Litypedef void (*CFArrayReleaseCallBack)(CFAllocatorRef allocator, const void *value); 11*67e74705SXin Litypedef CFStringRef (*CFArrayCopyDescriptionCallBack)(const void *value); 12*67e74705SXin Litypedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2); 13*67e74705SXin Litypedef struct { 14*67e74705SXin Li CFIndex version; 15*67e74705SXin Li CFArrayRetainCallBack retain; 16*67e74705SXin Li CFArrayReleaseCallBack release; 17*67e74705SXin Li CFArrayCopyDescriptionCallBack copyDescription; 18*67e74705SXin Li CFArrayEqualCallBack equal; 19*67e74705SXin Li} CFArrayCallBacks; 20*67e74705SXin Litypedef const struct __CFArray * CFArrayRef; 21*67e74705SXin LiCFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks); 22*67e74705SXin Litypedef struct __CFArray * CFMutableArrayRef; 23*67e74705SXin Litypedef const struct __CFString * CFStringRef; 24*67e74705SXin Lienum { 25*67e74705SXin Li kCFNumberSInt8Type = 1, 26*67e74705SXin Li kCFNumberSInt16Type = 2, 27*67e74705SXin Li kCFNumberSInt32Type = 3, 28*67e74705SXin Li kCFNumberSInt64Type = 4, 29*67e74705SXin Li kCFNumberFloat32Type = 5, 30*67e74705SXin Li kCFNumberFloat64Type = 6, 31*67e74705SXin Li kCFNumberCharType = 7, 32*67e74705SXin Li kCFNumberShortType = 8, 33*67e74705SXin Li kCFNumberIntType = 9, 34*67e74705SXin Li kCFNumberLongType = 10, 35*67e74705SXin Li kCFNumberLongLongType = 11, 36*67e74705SXin Li kCFNumberFloatType = 12, 37*67e74705SXin Li kCFNumberDoubleType = 13, 38*67e74705SXin Li kCFNumberCFIndexType = 14, 39*67e74705SXin Li kCFNumberNSIntegerType = 15, 40*67e74705SXin Li kCFNumberCGFloatType = 16, 41*67e74705SXin Li kCFNumberMaxType = 16 42*67e74705SXin Li}; 43*67e74705SXin Litypedef CFIndex CFNumberType; 44*67e74705SXin Litypedef const struct __CFNumber * CFNumberRef; 45*67e74705SXin Litypedef CFIndex CFComparisonResult; 46*67e74705SXin Litypedef const struct __CFDictionary * CFDictionaryRef; 47*67e74705SXin Litypedef const void * (*CFDictionaryRetainCallBack)(CFAllocatorRef allocator, const void *value); 48*67e74705SXin Litypedef void (*CFDictionaryReleaseCallBack)(CFAllocatorRef allocator, const void *value); 49*67e74705SXin Litypedef CFStringRef (*CFDictionaryCopyDescriptionCallBack)(const void *value); 50*67e74705SXin Litypedef Boolean (*CFDictionaryEqualCallBack)(const void *value1, const void *value2); 51*67e74705SXin Litypedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2); 52*67e74705SXin Litypedef Boolean (*CFSetEqualCallBack)(const void *value1, const void *value2); 53*67e74705SXin Litypedef const void * (*CFSetRetainCallBack)(CFAllocatorRef allocator, const void *value); 54*67e74705SXin Litypedef void (*CFSetReleaseCallBack)(CFAllocatorRef allocator, const void *value); 55*67e74705SXin Litypedef CFStringRef (*CFSetCopyDescriptionCallBack)(const void *value); 56*67e74705SXin Litypedef struct { 57*67e74705SXin Li CFIndex version; 58*67e74705SXin Li CFSetRetainCallBack retain; 59*67e74705SXin Li CFSetReleaseCallBack release; 60*67e74705SXin Li CFSetCopyDescriptionCallBack copyDescription; 61*67e74705SXin Li CFSetEqualCallBack equal; 62*67e74705SXin Li} CFSetCallBacks; 63*67e74705SXin Litypedef struct { 64*67e74705SXin Li CFIndex version; 65*67e74705SXin Li CFDictionaryRetainCallBack retain; 66*67e74705SXin Li CFDictionaryReleaseCallBack release; 67*67e74705SXin Li CFDictionaryCopyDescriptionCallBack copyDescription; 68*67e74705SXin Li CFDictionaryEqualCallBack equal; 69*67e74705SXin Li} CFDictionaryKeyCallBacks; 70*67e74705SXin Litypedef struct { 71*67e74705SXin Li CFIndex version; 72*67e74705SXin Li CFDictionaryRetainCallBack retain; 73*67e74705SXin Li CFDictionaryReleaseCallBack release; 74*67e74705SXin Li CFDictionaryCopyDescriptionCallBack copyDescription; 75*67e74705SXin Li CFDictionaryEqualCallBack equal; 76*67e74705SXin Li} CFDictionaryValueCallBacks; 77*67e74705SXin LiCFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); 78*67e74705SXin Liextern 79*67e74705SXin Liconst CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; 80*67e74705SXin Litypedef const struct __CFSet * CFSetRef; 81*67e74705SXin Liextern 82*67e74705SXin Liconst CFSetCallBacks kCFTypeSetCallBacks; 83*67e74705SXin Liextern 84*67e74705SXin Liconst CFDictionaryKeyCallBacks kCFCopyStringDictionaryKeyCallBacks; 85*67e74705SXin Liextern 86*67e74705SXin Liconst void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx); 87*67e74705SXin Liextern 88*67e74705SXin LiCFIndex CFArrayGetCount(CFArrayRef theArray); 89*67e74705SXin LiCFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const 90*67e74705SXin LiCFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); 91*67e74705SXin LiCFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr); 92*67e74705SXin Liextern 93*67e74705SXin LiCFSetRef CFSetCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFSetCallBacks *callBacks); 94*67e74705SXin Li#define CFSTR(cStr) ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr "")) 95*67e74705SXin Li#define NULL __null 96*67e74705SXin Li 97*67e74705SXin Li// Done with the headers. 98*67e74705SXin Li// Test alpha.osx.cocoa.ContainerAPI checker. 99*67e74705SXin Livoid testContainers(int **xNoWarn, CFIndex count) { 100*67e74705SXin Li int x[] = { 1, 2, 3 }; 101*67e74705SXin Li CFArrayRef foo = CFArrayCreate(kCFAllocatorDefault, (const void **) x, sizeof(x) / sizeof(x[0]), 0);// expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}} 102*67e74705SXin Li 103*67e74705SXin Li CFArrayRef fooNoWarn = CFArrayCreate(kCFAllocatorDefault, (const void **) xNoWarn, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0); // no warning 104*67e74705SXin Li CFArrayRef fooNoWarn2 = CFArrayCreate(kCFAllocatorDefault, 0, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in 0 105*67e74705SXin Li CFArrayRef fooNoWarn3 = CFArrayCreate(kCFAllocatorDefault, NULL, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in NULL 106*67e74705SXin Li 107*67e74705SXin Li CFSetRef set = CFSetCreate(NULL, (const void **)x, 3, &kCFTypeSetCallBacks); // expected-warning {{The second argument to 'CFSetCreate' must be a C array of pointer-sized values}} 108*67e74705SXin Li CFArrayRef* pairs = new CFArrayRef[count]; 109*67e74705SXin Li CFSetRef fSet = CFSetCreate(kCFAllocatorDefault, (const void**) pairs, count - 1, &kCFTypeSetCallBacks);// no warning 110*67e74705SXin Li} 111*67e74705SXin Li 112*67e74705SXin Livoid CreateDict(int *elems) { 113*67e74705SXin Li const short days28 = 28; 114*67e74705SXin Li const short days30 = 30; 115*67e74705SXin Li const short days31 = 31; 116*67e74705SXin Li CFIndex numValues = 6; 117*67e74705SXin Li CFStringRef keys[6]; 118*67e74705SXin Li CFNumberRef values[6]; 119*67e74705SXin Li keys[0] = CFSTR("January"); values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31); 120*67e74705SXin Li keys[1] = CFSTR("February"); values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days28); 121*67e74705SXin Li keys[2] = CFSTR("March"); values[2] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31); 122*67e74705SXin Li keys[3] = CFSTR("April"); values[3] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days30); 123*67e74705SXin Li keys[4] = CFSTR("May"); values[4] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31); 124*67e74705SXin Li keys[5] = CFSTR("June"); values[5] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days30); 125*67e74705SXin Li 126*67e74705SXin Li const CFDictionaryKeyCallBacks keyCB = kCFCopyStringDictionaryKeyCallBacks; 127*67e74705SXin Li const CFDictionaryValueCallBacks valCB = kCFTypeDictionaryValueCallBacks; 128*67e74705SXin Li CFDictionaryRef dict1 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, numValues, &keyCB, &valCB); // no warning 129*67e74705SXin Li CFDictionaryRef dict2 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)elems[0], (const void**)values, numValues, &keyCB, &valCB); //expected-warning {{The second argument to 'CFDictionaryCreate' must be a C array of}} expected-warning {{cast to 'const void **' from smaller integer type 'int'}} 130*67e74705SXin Li CFDictionaryRef dict3 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)elems, numValues, &keyCB, &valCB); // expected-warning {{The third argument to 'CFDictionaryCreate' must be a C array of pointer-sized values}} 131*67e74705SXin Li} 132*67e74705SXin Li 133*67e74705SXin Livoid OutOfBoundsSymbolicOffByOne(const void ** input, CFIndex S) { 134*67e74705SXin Li CFArrayRef array; 135*67e74705SXin Li array = CFArrayCreate(kCFAllocatorDefault, input, S, 0); 136*67e74705SXin Li const void *s1 = CFArrayGetValueAtIndex(array, 0); // no warning 137*67e74705SXin Li const void *s2 = CFArrayGetValueAtIndex(array, S-1); // no warning 138*67e74705SXin Li const void *s3 = CFArrayGetValueAtIndex(array, S); // expected-warning {{Index is out of bounds}} 139*67e74705SXin Li} 140*67e74705SXin Li 141*67e74705SXin Livoid OutOfBoundsConst(const void ** input, CFIndex S) { 142*67e74705SXin Li CFArrayRef array; 143*67e74705SXin Li array = CFArrayCreate(kCFAllocatorDefault, input, 3, 0); 144*67e74705SXin Li const void *s1 = CFArrayGetValueAtIndex(array, 0); // no warning 145*67e74705SXin Li const void *s2 = CFArrayGetValueAtIndex(array, 2); // no warning 146*67e74705SXin Li const void *s3 = CFArrayGetValueAtIndex(array, 5); // expected-warning {{Index is out of bounds}} 147*67e74705SXin Li 148*67e74705SXin Li // TODO: The solver is probably not strong enough here. 149*67e74705SXin Li CFIndex sIndex; 150*67e74705SXin Li for (sIndex = 0 ; sIndex <= 5 ; sIndex += 3 ) { 151*67e74705SXin Li const void *s = CFArrayGetValueAtIndex(array, sIndex); 152*67e74705SXin Li } 153*67e74705SXin Li} 154*67e74705SXin Li 155*67e74705SXin Livoid OutOfBoundsZiro(const void ** input, CFIndex S) { 156*67e74705SXin Li CFArrayRef array; 157*67e74705SXin Li // The API allows to set the size to 0. Check that we don't undeflow when the size is 0. 158*67e74705SXin Li array = CFArrayCreate(kCFAllocatorDefault, 0, 0, 0); 159*67e74705SXin Li const void *s1 = CFArrayGetValueAtIndex(array, 0); // expected-warning {{Index is out of bounds}} 160*67e74705SXin Li} 161*67e74705SXin Li 162*67e74705SXin Livoid TestGetCount(CFArrayRef A, CFIndex sIndex) { 163*67e74705SXin Li CFIndex sCount = CFArrayGetCount(A); 164*67e74705SXin Li if (sCount > sIndex) 165*67e74705SXin Li const void *s1 = CFArrayGetValueAtIndex(A, sIndex); 166*67e74705SXin Li const void *s2 = CFArrayGetValueAtIndex(A, sCount);// expected-warning {{Index is out of bounds}} 167*67e74705SXin Li} 168*67e74705SXin Li 169*67e74705SXin Litypedef void* XX[3]; 170*67e74705SXin Livoid TestPointerToArray(int *elems, void *p1, void *p2, void *p3, unsigned count, void* fn[], char cp[]) { 171*67e74705SXin Li void* x[] = { p1, p2, p3 }; 172*67e74705SXin Li CFArrayCreate(0, (const void **) &x, count, 0); // no warning 173*67e74705SXin Li 174*67e74705SXin Li void* y[] = { p1, p2, p3 }; 175*67e74705SXin Li CFArrayCreate(0, (const void **) y, count, 0); // no warning 176*67e74705SXin Li XX *z = &x; 177*67e74705SXin Li CFArrayCreate(0, (const void **) z, count, 0); // no warning 178*67e74705SXin Li 179*67e74705SXin Li CFArrayCreate(0, (const void **) &fn, count, 0); // false negative 180*67e74705SXin Li CFArrayCreate(0, (const void **) fn, count, 0); // no warning 181*67e74705SXin Li CFArrayCreate(0, (const void **) cp, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}} 182*67e74705SXin Li 183*67e74705SXin Li char cc[] = { 0, 2, 3 }; 184*67e74705SXin Li CFArrayCreate(0, (const void **) &cc, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}} 185*67e74705SXin Li CFArrayCreate(0, (const void **) cc, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}} 186*67e74705SXin Li} 187*67e74705SXin Li 188*67e74705SXin Livoid TestUndef(CFArrayRef A, CFIndex sIndex, void* x[]) { 189*67e74705SXin Li unsigned undefVal; 190*67e74705SXin Li const void *s1 = CFArrayGetValueAtIndex(A, undefVal); 191*67e74705SXin Li 192*67e74705SXin Li unsigned undefVal2; 193*67e74705SXin Li CFArrayRef B = CFArrayCreate(0, (const void **) &x, undefVal2, 0); 194*67e74705SXin Li const void *s2 = CFArrayGetValueAtIndex(B, 2); 195*67e74705SXin Li} 196*67e74705SXin Li 197*67e74705SXin Livoid TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) { 198*67e74705SXin Li CFArrayRef B = CFArrayCreate(0, (const void **) &x, 4, 0); 199*67e74705SXin Li const void *s1 = CFArrayGetValueAtIndex(B, 2); 200*67e74705SXin Li 201*67e74705SXin Li} 202*67e74705SXin Li 203*67e74705SXin Livoid TestNullArray() { 204*67e74705SXin Li CFArrayGetValueAtIndex(0, 0); 205*67e74705SXin Li} 206*67e74705SXin Li 207*67e74705SXin Livoid ArrayRefMutableEscape(CFMutableArrayRef a); 208*67e74705SXin Livoid ArrayRefEscape(CFArrayRef a); 209*67e74705SXin Li 210*67e74705SXin Livoid TestCFMutableArrayRefEscapeViaMutableArgument(CFMutableArrayRef a) { 211*67e74705SXin Li CFIndex aLen = CFArrayGetCount(a); 212*67e74705SXin Li ArrayRefMutableEscape(a); 213*67e74705SXin Li 214*67e74705SXin Li // ArrayRefMutableEscape could mutate a to make it have 215*67e74705SXin Li // at least aLen + 1 elements, so do not report an error here. 216*67e74705SXin Li CFArrayGetValueAtIndex(a, aLen); 217*67e74705SXin Li} 218*67e74705SXin Li 219*67e74705SXin Livoid TestCFMutableArrayRefEscapeViaImmutableArgument(CFMutableArrayRef a) { 220*67e74705SXin Li CFIndex aLen = CFArrayGetCount(a); 221*67e74705SXin Li ArrayRefEscape(a); 222*67e74705SXin Li 223*67e74705SXin Li // ArrayRefEscape is declared to take a CFArrayRef (i.e, an immutable array) 224*67e74705SXin Li // so we assume it does not change the length of a. 225*67e74705SXin Li CFArrayGetValueAtIndex(a, aLen); // expected-warning {{Index is out of bounds}} 226*67e74705SXin Li} 227