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