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 3 typedef const struct __CFAllocator * CFAllocatorRef; 4 typedef const struct __CFString * CFStringRef; 5 typedef unsigned char Boolean; 6 typedef signed long CFIndex; 7 extern 8 const CFAllocatorRef kCFAllocatorDefault; 9 typedef const void * (*CFArrayRetainCallBack)(CFAllocatorRef allocator, const void *value); 10 typedef void (*CFArrayReleaseCallBack)(CFAllocatorRef allocator, const void *value); 11 typedef CFStringRef (*CFArrayCopyDescriptionCallBack)(const void *value); 12 typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2); 13 typedef struct { 14 CFIndex version; 15 CFArrayRetainCallBack retain; 16 CFArrayReleaseCallBack release; 17 CFArrayCopyDescriptionCallBack copyDescription; 18 CFArrayEqualCallBack equal; 19 } CFArrayCallBacks; 20 typedef const struct __CFArray * CFArrayRef; 21 CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks); 22 typedef struct __CFArray * CFMutableArrayRef; 23 typedef const struct __CFString * CFStringRef; 24 enum { 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 }; 43 typedef CFIndex CFNumberType; 44 typedef const struct __CFNumber * CFNumberRef; 45 typedef CFIndex CFComparisonResult; 46 typedef const struct __CFDictionary * CFDictionaryRef; 47 typedef const void * (*CFDictionaryRetainCallBack)(CFAllocatorRef allocator, const void *value); 48 typedef void (*CFDictionaryReleaseCallBack)(CFAllocatorRef allocator, const void *value); 49 typedef CFStringRef (*CFDictionaryCopyDescriptionCallBack)(const void *value); 50 typedef Boolean (*CFDictionaryEqualCallBack)(const void *value1, const void *value2); 51 typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2); 52 typedef Boolean (*CFSetEqualCallBack)(const void *value1, const void *value2); 53 typedef const void * (*CFSetRetainCallBack)(CFAllocatorRef allocator, const void *value); 54 typedef void (*CFSetReleaseCallBack)(CFAllocatorRef allocator, const void *value); 55 typedef CFStringRef (*CFSetCopyDescriptionCallBack)(const void *value); 56 typedef struct { 57 CFIndex version; 58 CFSetRetainCallBack retain; 59 CFSetReleaseCallBack release; 60 CFSetCopyDescriptionCallBack copyDescription; 61 CFSetEqualCallBack equal; 62 } CFSetCallBacks; 63 typedef struct { 64 CFIndex version; 65 CFDictionaryRetainCallBack retain; 66 CFDictionaryReleaseCallBack release; 67 CFDictionaryCopyDescriptionCallBack copyDescription; 68 CFDictionaryEqualCallBack equal; 69 } CFDictionaryKeyCallBacks; 70 typedef struct { 71 CFIndex version; 72 CFDictionaryRetainCallBack retain; 73 CFDictionaryReleaseCallBack release; 74 CFDictionaryCopyDescriptionCallBack copyDescription; 75 CFDictionaryEqualCallBack equal; 76 } CFDictionaryValueCallBacks; 77 CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); 78 extern 79 const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks; 80 typedef const struct __CFSet * CFSetRef; 81 extern 82 const CFSetCallBacks kCFTypeSetCallBacks; 83 extern 84 const CFDictionaryKeyCallBacks kCFCopyStringDictionaryKeyCallBacks; 85 extern 86 const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx); 87 extern 88 CFIndex CFArrayGetCount(CFArrayRef theArray); 89 CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const 90 CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks); 91 CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr); 92 extern 93 CFSetRef 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. 99 void 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 112 void 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 133 void 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 141 void 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 155 void 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 162 void 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 169 typedef void* XX[3]; 170 void 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 188 void 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 197 void 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 203 void TestNullArray() { 204 CFArrayGetValueAtIndex(0, 0); 205 } 206 207 void ArrayRefMutableEscape(CFMutableArrayRef a); 208 void ArrayRefEscape(CFArrayRef a); 209 210 void 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 219 void 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