reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin -analyzer-output=text\
// RUN: -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues\
// RUN: -analyzer-checker=osx.coreFoundation.containers.OutOfBounds\
// RUN: -verify %s

typedef const struct __CFAllocator * CFAllocatorRef;
typedef const struct __CFString * CFStringRef;
typedef unsigned char Boolean;
typedef signed long CFIndex;
extern
const CFAllocatorRef kCFAllocatorDefault;
typedef const void * (*CFArrayRetainCallBack)(CFAllocatorRef allocator, const void *value);
typedef void (*CFArrayReleaseCallBack)(CFAllocatorRef allocator, const void *value);
typedef CFStringRef (*CFArrayCopyDescriptionCallBack)(const void *value);
typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2);
typedef struct {
    CFIndex version;
    CFArrayRetainCallBack retain;
    CFArrayReleaseCallBack release;
    CFArrayCopyDescriptionCallBack copyDescription;
    CFArrayEqualCallBack equal;
} CFArrayCallBacks;
typedef const struct __CFArray * CFArrayRef;
CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks);
typedef struct __CFArray * CFMutableArrayRef;
typedef const struct __CFString * CFStringRef;
enum {
    kCFNumberSInt8Type = 1,
    kCFNumberSInt16Type = 2,
    kCFNumberSInt32Type = 3,
    kCFNumberSInt64Type = 4,
    kCFNumberFloat32Type = 5,
    kCFNumberFloat64Type = 6,
    kCFNumberCharType = 7,
    kCFNumberShortType = 8,
    kCFNumberIntType = 9,
    kCFNumberLongType = 10,
    kCFNumberLongLongType = 11,
    kCFNumberFloatType = 12,
    kCFNumberDoubleType = 13,
    kCFNumberCFIndexType = 14,
    kCFNumberNSIntegerType = 15,
    kCFNumberCGFloatType = 16,
    kCFNumberMaxType = 16
};
typedef CFIndex CFNumberType;
typedef const struct __CFNumber * CFNumberRef;
typedef CFIndex CFComparisonResult;
typedef const struct __CFDictionary * CFDictionaryRef;
typedef const void * (*CFDictionaryRetainCallBack)(CFAllocatorRef allocator, const void *value);
typedef void (*CFDictionaryReleaseCallBack)(CFAllocatorRef allocator, const void *value);
typedef CFStringRef (*CFDictionaryCopyDescriptionCallBack)(const void *value);
typedef Boolean (*CFDictionaryEqualCallBack)(const void *value1, const void *value2);
typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2);
typedef Boolean (*CFSetEqualCallBack)(const void *value1, const void *value2);
typedef const void * (*CFSetRetainCallBack)(CFAllocatorRef allocator, const void *value);
typedef void (*CFSetReleaseCallBack)(CFAllocatorRef allocator, const void *value);
typedef CFStringRef (*CFSetCopyDescriptionCallBack)(const void *value);
typedef struct {
    CFIndex version;
    CFSetRetainCallBack retain;
    CFSetReleaseCallBack release;
    CFSetCopyDescriptionCallBack copyDescription;
    CFSetEqualCallBack equal;
} CFSetCallBacks;
typedef struct {
    CFIndex version;
    CFDictionaryRetainCallBack retain;
    CFDictionaryReleaseCallBack release;
    CFDictionaryCopyDescriptionCallBack copyDescription;
    CFDictionaryEqualCallBack equal;
} CFDictionaryKeyCallBacks;
typedef struct {
    CFIndex version;
    CFDictionaryRetainCallBack retain;
    CFDictionaryReleaseCallBack release;
    CFDictionaryCopyDescriptionCallBack copyDescription;
    CFDictionaryEqualCallBack equal;
} CFDictionaryValueCallBacks;
CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
extern
const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
typedef const struct __CFSet * CFSetRef;
extern
const CFSetCallBacks kCFTypeSetCallBacks;
extern
const CFDictionaryKeyCallBacks kCFCopyStringDictionaryKeyCallBacks;
extern
const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
extern
CFIndex CFArrayGetCount(CFArrayRef theArray);
CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const 
CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
extern
CFSetRef CFSetCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFSetCallBacks *callBacks);
#define CFSTR(cStr)  ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr ""))
#define NULL __null

// Done with the headers.
// Test alpha.osx.cocoa.ContainerAPI checker.
void testContainers(int **xNoWarn, CFIndex count) {
  int x[] = { 1, 2, 3 };
  CFArrayRef foo = CFArrayCreate(kCFAllocatorDefault, (const void **) x, sizeof(x) / sizeof(x[0]), 0);
  // expected-warning@-1 {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
  // expected-note@-2    {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}

  CFArrayRef fooNoWarn = CFArrayCreate(kCFAllocatorDefault, (const void **) xNoWarn, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0); // no warning
  CFArrayRef fooNoWarn2 = CFArrayCreate(kCFAllocatorDefault, 0, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in 0
  CFArrayRef fooNoWarn3 = CFArrayCreate(kCFAllocatorDefault, NULL, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in NULL

  CFSetRef set = CFSetCreate(NULL, (const void **)x, 3, &kCFTypeSetCallBacks);
  // expected-warning@-1 {{The second argument to 'CFSetCreate' must be a C array of pointer-sized values}}
  // expected-note@-2    {{The second argument to 'CFSetCreate' must be a C array of pointer-sized values}}
  CFArrayRef* pairs = new CFArrayRef[count];
  CFSetRef fSet = CFSetCreate(kCFAllocatorDefault, (const void**) pairs, count - 1, &kCFTypeSetCallBacks);// no warning
}

void CreateDict(int *elems) {
  const short days28 = 28;
  const short days30 = 30;
  const short days31 = 31;
  CFIndex numValues = 6;  
  CFStringRef keys[6];
  CFNumberRef values[6];
  keys[0] = CFSTR("January");  values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31);
  keys[1] = CFSTR("February"); values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days28);
  keys[2] = CFSTR("March"); values[2] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31);
  keys[3] = CFSTR("April"); values[3] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days30);
  keys[4] = CFSTR("May"); values[4] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31);
  keys[5] = CFSTR("June"); values[5] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days30);

  const CFDictionaryKeyCallBacks keyCB = kCFCopyStringDictionaryKeyCallBacks;
  const CFDictionaryValueCallBacks valCB = kCFTypeDictionaryValueCallBacks;
  CFDictionaryRef dict1 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, numValues, &keyCB, &valCB); // no warning
  CFDictionaryRef dict2 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)elems[0], (const void**)values, numValues, &keyCB, &valCB);
  // expected-warning@-1 {{The second argument to 'CFDictionaryCreate' must be a C array of}}
  // expected-note@-2    {{The second argument to 'CFDictionaryCreate' must be a C array of}}
  // expected-warning@-3{{cast to 'const void **' from smaller integer type 'int'}}
  CFDictionaryRef dict3 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)elems, numValues, &keyCB, &valCB);
  // expected-warning@-1 {{The third argument to 'CFDictionaryCreate' must be a C array of pointer-sized values}}
  // expected-note@-2    {{The third argument to 'CFDictionaryCreate' must be a C array of pointer-sized values}}
}

void OutOfBoundsSymbolicOffByOne(const void ** input, CFIndex S) {
  CFArrayRef array;
  array = CFArrayCreate(kCFAllocatorDefault, input, S, 0);
  const void *s1 = CFArrayGetValueAtIndex(array, 0);   // no warning
  const void *s2 = CFArrayGetValueAtIndex(array, S-1); // no warning
  const void *s3 = CFArrayGetValueAtIndex(array, S);   // expected-warning {{Index is out of bounds}}
                                                       // expected-note@-1 {{Index is out of bounds}}
}

void OutOfBoundsConst(const void ** input, CFIndex S) {
  CFArrayRef array;
  array = CFArrayCreate(kCFAllocatorDefault, input, 3, 0);
  const void *s1 = CFArrayGetValueAtIndex(array, 0); // no warning
  const void *s2 = CFArrayGetValueAtIndex(array, 2); // no warning
  const void *s3 = CFArrayGetValueAtIndex(array, 5); // expected-warning {{Index is out of bounds}}
                                                     // expected-note@-1 {{Index is out of bounds}}
  
  // TODO: The solver is probably not strong enough here.
  CFIndex sIndex;
  for (sIndex = 0 ; sIndex <= 5 ; sIndex += 3 ) {
    const void *s = CFArrayGetValueAtIndex(array, sIndex); 
  }  
}

void OutOfBoundsZiro(const void ** input, CFIndex S) {
  CFArrayRef array;
  // The API allows to set the size to 0. Check that we don't undeflow when the size is 0.
  array = CFArrayCreate(kCFAllocatorDefault, 0, 0, 0);
  const void *s1 = CFArrayGetValueAtIndex(array, 0); // expected-warning {{Index is out of bounds}}
                                                     // expected-note@-1 {{Index is out of bounds}}
}

void TestGetCount(CFArrayRef A, CFIndex sIndex) {
  CFIndex sCount = CFArrayGetCount(A); // expected-note{{'sCount' initialized here}}
  if (sCount > sIndex) // expected-note{{Assuming 'sCount' is <= 'sIndex'}}
                       // expected-note@-1{{Taking false branch}}
    const void *s1 = CFArrayGetValueAtIndex(A, sIndex);
  const void *s2 = CFArrayGetValueAtIndex(A, sCount);// expected-warning {{Index is out of bounds}}
                                                     // expected-note@-1 {{Index is out of bounds}}
}

typedef void* XX[3];
void TestPointerToArray(int *elems, void *p1, void *p2, void *p3, unsigned count, void* fn[], char cp[]) {
  void* x[] = { p1, p2, p3 };
  CFArrayCreate(0, (const void **) &x, count, 0); // no warning

  void* y[] = { p1, p2, p3 };
  CFArrayCreate(0, (const void **) y, count, 0); // no warning
  XX *z = &x;
  CFArrayCreate(0, (const void **) z, count, 0); // no warning

  CFArrayCreate(0, (const void **) &fn, count, 0); // false negative
  CFArrayCreate(0, (const void **) fn, count, 0); // no warning
  CFArrayCreate(0, (const void **) cp, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
                                                  // expected-note@-1 {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}

  char cc[] = { 0, 2, 3 };
  CFArrayCreate(0, (const void **) &cc, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
                                                   // expected-note@-1 {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
  CFArrayCreate(0, (const void **) cc, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
                                                  // expected-note@-1 {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
}

void TestUndef(CFArrayRef A, CFIndex sIndex, void* x[]) {
  unsigned undefVal;
  const void *s1 = CFArrayGetValueAtIndex(A, undefVal);

  unsigned undefVal2;
  CFArrayRef B = CFArrayCreate(0, (const void **) &x, undefVal2, 0); 
  const void *s2 = CFArrayGetValueAtIndex(B, 2);
}

void TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) {
  CFArrayRef B = CFArrayCreate(0, (const void **) &x, 4, 0); 
  const void *s1 = CFArrayGetValueAtIndex(B, 2);

}

void TestNullArray() {
  CFArrayGetValueAtIndex(0, 0);
}

void ArrayRefMutableEscape(CFMutableArrayRef a);
void ArrayRefEscape(CFArrayRef a);

void TestCFMutableArrayRefEscapeViaMutableArgument(CFMutableArrayRef a) {
  CFIndex aLen = CFArrayGetCount(a);
  ArrayRefMutableEscape(a);

  // ArrayRefMutableEscape could mutate a to make it have
  // at least aLen + 1 elements, so do not report an error here.
  CFArrayGetValueAtIndex(a, aLen);
}

void TestCFMutableArrayRefEscapeViaImmutableArgument(CFMutableArrayRef a) {
  CFIndex aLen = CFArrayGetCount(a); // expected-note{{'aLen' initialized here}}
  ArrayRefEscape(a);

  // ArrayRefEscape is declared to take a CFArrayRef (i.e, an immutable array)
  // so we assume it does not change the length of a.
  CFArrayGetValueAtIndex(a, aLen); // expected-warning {{Index is out of bounds}}
                                   // expected-note@-1 {{Index is out of bounds}}
}