brintos

brintos / llvm-project-archived public Read only

0
0
Text · 34.7 KiB · 63fd784 Raw
821 lines · cpp
1// RUN: %clang_analyze_cc1 -std=c++14 -fblocks -analyzer-output=text\2// RUN:   -analyzer-checker=core,osx,debug.ExprInspection -verify %s3 4#include "os_object_base.h"5#include "os_smart_ptr.h"6 7void clang_analyzer_eval(bool);8 9struct OSIterator : public OSObject {10  static const OSMetaClass * const metaClass;11};12 13struct OSArray : public OSObject {14  unsigned int getCount();15 16  OSIterator * getIterator();17 18  OSObject *identity() override;19 20  virtual OSObject *generateObject(OSObject *input);21 22  virtual void consumeReference(OS_CONSUME OSArray *other);23 24  void putIntoArray(OSArray *array) OS_CONSUMES_THIS;25 26  template <typename T>27  void putIntoT(T *owner) OS_CONSUMES_THIS;28 29  static OSArray *generateArrayHasCode() {30    return new OSArray;31  }32 33  static OSArray *withCapacity(unsigned int capacity);34  static void consumeArray(OS_CONSUME OSArray * array);35 36  static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) { // expected-note{{Parameter 'array' starts at +1, as it is marked as consuming}}37    return nullptr; // expected-warning{{Potential leak of an object of type 'OSArray'}}38// expected-note@-1{{Object leaked: allocated object of type 'OSArray' is not referenced later in this execution path and has a retain count of +1}}39  }40 41 42  static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();43  static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();44 45  static const OSMetaClass * const metaClass;46};47 48struct MyArray : public OSArray {49  void consumeReference(OSArray *other) override;50 51  OSObject *identity() override;52 53  OSObject *generateObject(OSObject *input) override;54};55 56struct OtherStruct {57  static void doNothingToArray(OSArray *array);58  OtherStruct(OSArray *arr);59};60 61bool test_meta_cast_no_leak(OSMetaClassBase *arg) {62  return arg && arg->metaCast("blah") != nullptr;63}64 65static void consumedMismatch(OS_CONSUME OSObject *a,66                             OSObject *b) { // expected-note{{Parameter 'b' starts at +0}}67  a->release();68  b->retain(); // expected-note{{Reference count incremented. The object now has a +1 retain count}}69} // expected-warning{{Potential leak of an object of type 'OSObject'}}70// expected-note@-1{{Object leaked: allocated object of type 'OSObject' is not referenced later in this execution path and has a retain count of +1}}71 72void escape(void *);73void escape_with_source(void *p) {}74bool coin();75 76typedef int kern_return_t;77typedef kern_return_t IOReturn;78typedef kern_return_t OSReturn;79#define kOSReturnSuccess  080#define kIOReturnSuccess 081 82bool write_into_out_param_on_success(OS_RETURNS_RETAINED OSObject **obj);83 84void use_out_param() {85  OSObject *obj;86  if (write_into_out_param_on_success(&obj)) {87    obj->release();88  }89}90 91void use_out_param_leak() {92  OSObject *obj;93  write_into_out_param_on_success(&obj); // expected-note-re{{Call to function 'write_into_out_param_on_success' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj' (assuming the call returns non-zero){{$}}}}94} // expected-warning{{Potential leak of an object stored into 'obj'}}95 // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}96 97bool write_into_out_param_on_failure(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);98 99void use_out_param_leak2() {100  OSObject *obj;101  write_into_out_param_on_failure(&obj); // expected-note-re{{Call to function 'write_into_out_param_on_failure' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj' (assuming the call returns zero){{$}}}}102} // expected-warning{{Potential leak of an object stored into 'obj'}}103 // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}104 105void use_out_param_on_failure() {106  OSObject *obj;107  if (!write_into_out_param_on_failure(&obj)) {108    obj->release();109  }110}111 112IOReturn write_into_out_param_on_nonzero(OS_RETURNS_RETAINED_ON_NONZERO OSObject **obj);113 114void use_out_param_on_nonzero() {115  OSObject *obj;116  if (write_into_out_param_on_nonzero(&obj) != kIOReturnSuccess) {117    obj->release();118  }119}120 121bool write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,122                               OS_RETURNS_RETAINED OSObject **b);123 124void use_write_into_two_out_params() {125  OSObject *obj1;126  OSObject *obj2;127  if (write_into_two_out_params(&obj1, &obj2)) {128    obj1->release();129    obj2->release();130  }131}132 133void use_write_two_out_params_leak() {134  OSObject *obj1;135  OSObject *obj2;136  write_into_two_out_params(&obj1, &obj2); // expected-note-re{{Call to function 'write_into_two_out_params' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'a' (assuming the call returns non-zero){{$}}}}137                                           // expected-note-re@-1{{Call to function 'write_into_two_out_params' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'b' (assuming the call returns non-zero){{$}}}}138} // expected-warning{{Potential leak of an object stored into 'obj1'}}139  // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}140  // expected-note@-2{{Object leaked: object allocated and stored into 'obj1' is not referenced later in this execution path and has a retain count of +1}}141  // expected-note@-3{{Object leaked: object allocated and stored into 'obj2' is not referenced later in this execution path and has a retain count of +1}}142 143void always_write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,144                                      OS_RETURNS_RETAINED OSObject **b);145 146void use_always_write_into_two_out_params() {147  OSObject *obj1;148  OSObject *obj2;149  always_write_into_two_out_params(&obj1, &obj2);150  obj1->release();151  obj2->release();152}153 154void use_always_write_into_two_out_params_leak() {155  OSObject *obj1;156  OSObject *obj2;157  always_write_into_two_out_params(&obj1, &obj2); // expected-note-re{{Call to function 'always_write_into_two_out_params' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'a'{{$}}}}158                                                  // expected-note-re@-1{{Call to function 'always_write_into_two_out_params' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'b'{{$}}}}159} // expected-warning{{Potential leak of an object stored into 'obj1'}}160  // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}161  // expected-note@-2{{Object leaked: object allocated and stored into 'obj1' is not referenced later in this execution path and has a retain count of +1}}162  // expected-note@-3{{Object leaked: object allocated and stored into 'obj2' is not referenced later in this execution path and has a retain count of +1}}163 164char *write_into_out_param_on_nonnull(OS_RETURNS_RETAINED OSObject **obj);165 166void use_out_param_osreturn_on_nonnull() {167  OSObject *obj;168  if (write_into_out_param_on_nonnull(&obj)) {169    obj->release();170  }171}172 173void use_out_param_leak_osreturn_on_nonnull() {174  OSObject *obj;175  write_into_out_param_on_nonnull(&obj); // expected-note-re{{Call to function 'write_into_out_param_on_nonnull' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj' (assuming the call returns non-zero){{$}}}}176} // expected-warning{{Potential leak of an object stored into 'obj'}}177  // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}178 179bool write_optional_out_param(OS_RETURNS_RETAINED OSObject **obj=nullptr);180 181void use_optional_out_param() {182  if (write_optional_out_param()) {};183}184 185OSReturn write_into_out_param_on_os_success(OS_RETURNS_RETAINED OSObject **obj);186 187void write_into_non_retained_out_param(OS_RETURNS_NOT_RETAINED OSObject **obj);188 189void use_write_into_non_retained_out_param() {190  OSObject *obj;191  write_into_non_retained_out_param(&obj);192}193 194void use_write_into_non_retained_out_param_uaf() {195  OSObject *obj;196  write_into_non_retained_out_param(&obj); // expected-note-re{{Call to function 'write_into_non_retained_out_param' writes an OSObject of type 'OSObject' with a +0 retain count into an out parameter 'obj'{{$}}}}197  obj->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}198                  // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}199}200 201void always_write_into_out_param(OS_RETURNS_RETAINED OSObject **obj);202 203void pass_through_out_param(OSObject **obj) {204  always_write_into_out_param(obj);205}206 207void always_write_into_out_param_has_source(OS_RETURNS_RETAINED OSObject **obj) {208  *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}209}210 211void use_always_write_into_out_param_has_source_leak() {212  OSObject *obj;213  always_write_into_out_param_has_source(&obj); // expected-note{{Calling 'always_write_into_out_param_has_source'}}214                                                // expected-note@-1{{Returning from 'always_write_into_out_param_has_source'}}215} // expected-warning{{Potential leak of an object stored into 'obj'}}216  // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}217 218void use_void_out_param_osreturn() {219  OSObject *obj;220  always_write_into_out_param(&obj);221  obj->release();222}223 224void use_void_out_param_osreturn_leak() {225  OSObject *obj;226  always_write_into_out_param(&obj); // expected-note-re{{Call to function 'always_write_into_out_param' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj'{{$}}}}227} // expected-warning{{Potential leak of an object stored into 'obj'}}228  // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}229 230void use_out_param_osreturn() {231  OSObject *obj;232  if (write_into_out_param_on_os_success(&obj) == kOSReturnSuccess) {233    obj->release();234  }235}236 237void use_out_param_leak_osreturn() {238  OSObject *obj;239  write_into_out_param_on_os_success(&obj); // expected-note-re{{Call to function 'write_into_out_param_on_os_success' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj' (assuming the call returns zero){{$}}}}240} // expected-warning{{Potential leak of an object stored into 'obj'}}241  // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}242 243void cleanup(OSObject **obj);244 245void test_cleanup_escaping() {246  __attribute__((cleanup(cleanup))) OSObject *obj;247  always_write_into_out_param(&obj); // no-warning, the value has escaped.248}249 250struct StructWithField {251  OSObject *obj;252 253  void initViaOutParamCall() { // no warning on writing into fields254    always_write_into_out_param(&obj);255  }256 257};258 259bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {260  if (coin()) { // expected-note{{Assuming the condition is false}}261                // expected-note@-1{{Taking false branch}}262    escape(obj);263    return true;264  }265  return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}266}267 268bool os_consume_violation(OS_CONSUME OSObject *obj) {269  if (coin()) { // expected-note{{Assuming the condition is false}}270                // expected-note@-1{{Taking false branch}}271    escape(obj);272    return true;273  }274  return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}275}276 277void os_consume_ok(OS_CONSUME OSObject *obj) {278  escape(obj);279}280 281void use_os_consume_violation() {282  OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}283  os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}}284                             // expected-note@-1{{Returning from 'os_consume_violation'}}285} // expected-note{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}286  // expected-warning@-1{{Potential leak of an object stored into 'obj'}}287 288void use_os_consume_violation_two_args() {289  OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}290  os_consume_violation_two_args(obj, coin()); // expected-note{{Calling 'os_consume_violation_two_args'}}291                             // expected-note@-1{{Returning from 'os_consume_violation_two_args'}}292} // expected-note{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}293  // expected-warning@-1{{Potential leak of an object stored into 'obj'}}294 295void use_os_consume_ok() {296  OSObject *obj = new OSObject;297  os_consume_ok(obj);298}299 300void test_escaping_into_voidstar() {301  OSObject *obj = new OSObject;302  escape(obj);303}304 305void test_escape_has_source() {306  OSObject *obj = new OSObject;307  if (obj)308    escape_with_source(obj);309  return;310}311 312void test_no_infinite_check_recursion(MyArray *arr) {313  OSObject *input = new OSObject;314  OSObject *o = arr->generateObject(input);315  o->release();316  input->release();317}318 319 320void check_param_attribute_propagation(MyArray *parent) {321  OSArray *arr = new OSArray;322  parent->consumeReference(arr);323}324 325unsigned int check_attribute_propagation(OSArray *arr) {326  OSObject *other = arr->identity();327  OSArray *casted = OSDynamicCast(OSArray, other);328  if (casted)329    return casted->getCount();330  return 0;331}332 333unsigned int check_attribute_indirect_propagation(MyArray *arr) {334  OSObject *other = arr->identity();335  OSArray *casted = OSDynamicCast(OSArray, other);336  if (casted)337    return casted->getCount();338  return 0;339}340 341void check_consumes_this(OSArray *owner) {342  OSArray *arr = new OSArray;343  arr->putIntoArray(owner);344}345 346void check_consumes_this_with_template(OSArray *owner) {347  OSArray *arr = new OSArray;348  arr->putIntoT(owner);349}350 351void check_free_no_error() {352  OSArray *arr = OSArray::withCapacity(10);353  arr->retain();354  arr->retain();355  arr->retain();356  arr->free();357}358 359void check_free_use_after_free() {360  OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}361  arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}362  arr->free(); // expected-note{{Object released}}363  arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}364                 // expected-note@-1{{Reference-counted object is used after it is released}}365}366 367unsigned int check_leak_explicit_new() {368  OSArray *arr = new OSArray; // expected-note{{Operator 'new' returns an OSObject of type 'OSArray' with a +1 retain count}}369  return arr->getCount(); // expected-note{{Object leaked: object allocated and stored into 'arr' is not referenced later in this execution path and has a retain count of +1}}370                          // expected-warning@-1{{Potential leak of an object stored into 'arr'}}371}372 373unsigned int check_leak_factory() {374  OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}375  return arr->getCount(); // expected-note{{Object leaked: object allocated and stored into 'arr' is not referenced later in this execution path and has a retain count of +1}}376                          // expected-warning@-1{{Potential leak of an object stored into 'arr'}}377}378 379void check_get_object() {380  OSObject::getObject();381}382 383void check_Get_object() {384  OSObject::GetObject();385}386 387void check_custom_iterator_rule(OSArray *arr) {388  OSIterator *it = arr->getIterator();389  it->release();390}391 392void check_iterator_leak(OSArray *arr) {393  arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type 'OSIterator' with a +1 retain count}}394} // expected-note{{Object leaked: allocated object of type 'OSIterator' is not referenced later}}395  // expected-warning@-1{{Potential leak of an object of type 'OSIterator}}'396 397void check_no_invalidation() {398  OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}399  OtherStruct::doNothingToArray(arr);400} // expected-warning{{Potential leak of an object stored into 'arr'}}401  // expected-note@-1{{Object leaked}}402 403void check_no_invalidation_other_struct() {404  OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}405  OtherStruct other(arr); // expected-warning{{Potential leak}}406                          // expected-note@-1{{Object leaked}}407}408 409struct ArrayOwner : public OSObject {410  OSArray *arr;411  ArrayOwner(OSArray *arr) : arr(arr) {}412 413  static ArrayOwner* create(OSArray *arr) {414    return new ArrayOwner(arr);415  }416 417  OSArray *getArray() {418    return arr;419  }420 421  OSArray *createArray() {422    return OSArray::withCapacity(10);423  }424 425  OSArray *createArraySourceUnknown();426 427  OSArray *getArraySourceUnknown();428};429 430OSArray *generateArray() {431  return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}432                                    // expected-note@-1{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}433}434 435unsigned int check_leak_good_error_message() {436  unsigned int out;437  {438    OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}439                                       // expected-note@-1{{Returning from 'generateArray'}}440    out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}441                              // expected-note@-1{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}442  }443  return out;444}445 446unsigned int check_leak_msg_temporary() {447  return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}448                                      // expected-note@-1{{Calling 'generateArray'}}449                                      // expected-note@-2{{Returning from 'generateArray'}}450                                      // expected-note@-3{{Object leaked: allocated object of type 'OSArray' is not referenced later in this execution path and has a retain count of +1}}451}452 453void check_confusing_getters() {454  OSArray *arr = OSArray::withCapacity(10);455 456  ArrayOwner *AO = ArrayOwner::create(arr);457  AO->getArray();458 459  AO->release();460  arr->release();461}462 463void check_rc_consumed() {464  OSArray *arr = OSArray::withCapacity(10);465  OSArray::consumeArray(arr);466}467 468void check_rc_consume_temporary() {469  OSArray::consumeArray(OSArray::withCapacity(10));470}471 472void check_rc_getter() {473  OSArray *arr = OSArray::MaskedGetter();474  (void)arr;475}476 477void check_rc_create() {478  OSArray *arr = OSArray::getOoopsActuallyCreate();479  arr->release();480}481 482 483void check_dynamic_cast() {484  OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));485  arr->release();486}487 488void check_required_cast() {489  OSArray *arr = OSRequiredCast(OSArray, OSObject::generateObject(1));490  arr->release(); // no-warning491}492 493void check_cast_behavior(OSObject *obj) {494  OSArray *arr1 = OSDynamicCast(OSArray, obj);495  clang_analyzer_eval(arr1 == obj); // expected-warning{{TRUE}}496                                    // expected-note@-1{{TRUE}}497                                    // expected-note@-2{{Assuming 'arr1' is not equal to 'obj'}}498                                    // expected-warning@-3{{FALSE}}499                                    // expected-note@-4   {{FALSE}}500  OSArray *arr2 = OSRequiredCast(OSArray, obj);501  clang_analyzer_eval(arr2 == obj); // expected-warning{{TRUE}}502                                    // expected-note@-1{{TRUE}}503}504 505unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {506  OSArray *arr = OSDynamicCast(OSArray, obj);507  if (arr) {508    return arr->getCount();509  } else {510 511    // The fact that dynamic cast has failed should not imply that512    // the input object was null.513    return obj->foo(); // no-warning514  }515}516 517void check_dynamic_cast_null_branch(OSObject *obj) {518  OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}519  OSArray *arr = OSDynamicCast(OSArray, obj); // expected-note{{Assuming dynamic cast returns null due to type mismatch}}520  if (!arr) // expected-note{{'arr' is null}}521            // expected-note@-1{{Taking true branch}}522    return; // expected-warning{{Potential leak of an object stored into 'arr1'}}523            // expected-note@-1{{Object leaked}}524  arr1->release();525}526 527void check_dynamic_cast_null_check() {528  OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}529                                                                      // expected-warning@-1{{Potential leak of an object}}530                                                                      // expected-note@-2{{Object leaked}}531                                                                      // expected-note@-3{{Assuming dynamic cast returns null due to type mismatch}}532  if (!arr)533    return;534  arr->release();535}536 537void check_dynamic_cast_alias() {538  OSObject *originalPtr = OSObject::generateObject(1);   // expected-note {{Call to method 'OSObject::generateObject' returns an OSObject}}539  OSArray *newPtr = OSDynamicCast(OSArray, originalPtr); // expected-note {{'newPtr' initialized to the value of 'originalPtr'}}540  if (newPtr) {                                          // expected-note {{'newPtr' is non-null}}541                                                         // expected-note@-1 {{Taking true branch}}542    originalPtr = OSObject::generateObject(42);543    (void)newPtr;544  }545  originalPtr->release(); // expected-warning {{Potential leak of an object stored into 'newPtr'}}546                          // expected-note@-1 {{Object leaked: object allocated and stored into 'newPtr' is not referenced later in this execution path and has a retain count of +1}}547}548 549void check_dynamic_cast_alias_cond() {550  OSObject *originalPtr = OSObject::generateObject(1); // expected-note {{Call to method 'OSObject::generateObject' returns an OSObject}}551  OSArray *newPtr = 0;552  if ((newPtr = OSDynamicCast(OSArray, originalPtr))) { // expected-note {{The value of 'originalPtr' is assigned to 'newPtr'}}553                                                        // expected-note@-1 {{'newPtr' is non-null}}554                                                        // expected-note@-2 {{Taking true branch}}555    originalPtr = OSObject::generateObject(42);556    (void)newPtr;557  }558  originalPtr->release(); // expected-warning {{Potential leak of an object stored into 'newPtr'}}559                          // expected-note@-1 {{Object leaked: object allocated and stored into 'newPtr' is not referenced later in this execution path and has a retain count of +1}}560}561 562void check_dynamic_cast_alias_intermediate() {563  OSObject *originalPtr = OSObject::generateObject(1); // expected-note {{Call to method 'OSObject::generateObject' returns an OSObject of type 'OSObject' with a +1 retain count}}564  OSObject *intermediate = originalPtr;                // TODO: add note here as well565  OSArray *newPtr = 0;566  if ((newPtr = OSDynamicCast(OSArray, intermediate))) { // expected-note {{The value of 'intermediate' is assigned to 'newPtr'}}567                                                         // expected-note@-1 {{'newPtr' is non-null}}568                                                         // expected-note@-2 {{Taking true branch}}569    intermediate = OSObject::generateObject(42);570    (void)newPtr;571  }572  intermediate->release(); // expected-warning {{Potential leak of an object stored into 'newPtr'}}573                           // expected-note@-1 {{Object leaked: object allocated and stored into 'newPtr' is not referenced later in this execution path and has a retain count of +1}}574}575 576void check_dynamic_cast_alias_intermediate_2() {577  OSObject *originalPtr = OSObject::generateObject(1); // expected-note {{Call to method 'OSObject::generateObject' returns an OSObject of type 'OSObject' with a +1 retain count}}578  OSObject *intermediate = originalPtr;                // TODO: add note here as well579  OSArray *newPtr = 0;580  if ((newPtr = OSDynamicCast(OSArray, intermediate))) { // expected-note {{Value assigned to 'newPtr'}}581                                                         // expected-note@-1 {{'newPtr' is non-null}}582                                                         // expected-note@-2 {{Taking true branch}}583    intermediate = OSObject::generateObject(42);584    (void)originalPtr;585  }586  (void)newPtr;587  intermediate->release(); // expected-warning {{Potential leak of an object stored into 'newPtr'}}588                           // expected-note@-1 {{Object leaked: object allocated and stored into 'newPtr' is not referenced later in this execution path and has a retain count of +1}}589}590 591void use_after_release() {592  OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}593  arr->release();                           // expected-note{{Object released}}594  arr->getCount();                          // expected-warning{{Reference-counted object is used after it is released}}595                                            // expected-note@-1{{Reference-counted object is used after it is released}}596}597 598void potential_leak() {599  OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}600  arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}601  arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}602  arr->getCount();603} // expected-warning{{Potential leak of an object stored into 'arr'}}604  // expected-note@-1{{Object leaked: object allocated and stored into 'arr' is not referenced later in this execution path and has a retain count of +1}}605 606void proper_cleanup() {607  OSArray *arr = OSArray::withCapacity(10); // +1608  arr->retain(); // +2609  arr->release(); // +1610  arr->getCount();611  arr->release(); // 0612}613 614unsigned int no_warning_on_getter(ArrayOwner *owner) {615  OSArray *arr = owner->getArray();616  return arr->getCount();617}618 619unsigned int warn_on_overrelease(ArrayOwner *owner) {620  // FIXME: summaries are not applied in case the source of the getter/setter621  // is known.622  OSArray *arr = owner->getArray();623  arr->release();624  return arr->getCount();625}626 627unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {628  OSArray *arr = owner->createArray();629  unsigned int out = arr->getCount();630  arr->release();631  return out;632}633 634unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {635  OSArray *arr = owner->createArraySourceUnknown();636  unsigned int out = arr->getCount();637  arr->release();638  return out;639}640 641unsigned int no_warn_ok_release(ArrayOwner *owner) {642  OSArray *arr = owner->getArray(); // +0643  arr->retain(); // +1644  arr->release(); // +0645  return arr->getCount(); // no-warning646}647 648unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {649  OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type 'OSArray' with a +0 retain count}}650  arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}651                  // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}652  return arr->getCount();653}654 655unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {656  OSArray *arr = owner->getArraySourceUnknown(); // +0657  arr->retain(); // +1658  arr->release(); // +0659  return arr->getCount();660}661 662OSObject *getObject();663typedef bool (^Blk)(OSObject *);664 665void test_escape_to_unknown_block(Blk blk) {666  blk(getObject()); // no-crash667}668 669using OSObjectPtr = os::smart_ptr<OSObject>;670 671void test_smart_ptr_uaf() {672  OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}673  {674    OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}675   // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}676    // expected-note@os_smart_ptr.h:13{{Field 'pointer' is non-null}}677    // expected-note@os_smart_ptr.h:13{{Taking true branch}}678    // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}679    // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}}680    // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}681  } // expected-note{{Calling '~smart_ptr'}}682  // expected-note@os_smart_ptr.h:35{{Field 'pointer' is non-null}}683  // expected-note@os_smart_ptr.h:35{{Taking true branch}}684  // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}685  // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}686  // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}687 // expected-note@-6{{Returning from '~smart_ptr'}}688  obj->release(); // expected-note{{Object released}}689  obj->release(); // expected-warning{{Reference-counted object is used after it is released}}690// expected-note@-1{{Reference-counted object is used after it is released}}691}692 693void test_smart_ptr_leak() {694  OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}695  {696    OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}697                        // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}698                        // expected-note@-2 {{'p' initialized here}}699    // expected-note@os_smart_ptr.h:13{{Field 'pointer' is non-null}}700    // expected-note@os_smart_ptr.h:13{{Taking true branch}}701    // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}702    // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}}703    // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}704  } // expected-note{{Calling '~smart_ptr'}}705  // expected-note@os_smart_ptr.h:35{{Field 'pointer' is non-null}}706  // expected-note@os_smart_ptr.h:35{{Taking true branch}}707  // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}708  // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}709  // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}710  // expected-note@-6{{Returning from '~smart_ptr'}}711} // expected-warning{{Potential leak of an object stored into 'p'}}712// expected-note@-1{{Object leaked: object allocated and stored into 'p' is not referenced later in this execution path and has a retain count of +1}}713 714void test_smart_ptr_no_leak() {715  OSObject *obj = new OSObject;716  {717    OSObjectPtr p(obj);718  }719  obj->release();720}721 722void test_osmetaclass_release() {723  const char *name = "no_name";724  const OSMetaClass *meta = OSMetaClass::copyMetaClassWithName(name);725  if (!meta) {726    return;727  } else {728    meta->releaseMetaClass();729  }730}731 732OSObject *getRuleViolation() {733  return new OSObject; // expected-warning{{Potential leak of an object of type 'OSObject'}}734// expected-note@-1{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}735// expected-note@-2{{Object leaked: allocated object of type 'OSObject' is returned from a function whose name ('getRuleViolation') starts with 'get'}}736}737 738OSObject *createRuleViolation(OSObject *param) { // expected-note{{Parameter 'param' starts at +0}}739  return param; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}740  // expected-note@-1{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}741}742 743void test_ostypealloc_correct_diagnostic_name() {744  OSArray *arr = OSTypeAlloc(OSArray); // expected-note{{Call to method 'OSMetaClass::alloc' returns an OSObject of type 'OSArray' with a +1 retain count}}745  arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}746  arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}747} // expected-note{{Object leaked: object allocated and stored into 'arr' is not referenced later in this execution path and has a retain count of +1}}748  // expected-warning@-1{{Potential leak of an object stored into 'arr'}}749 750void escape_elsewhere(OSObject *obj);751 752void test_free_on_escaped_object_diagnostics() {753  OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}754  escape_elsewhere(obj); // expected-note{{Object is now not exclusively owned}}755  obj->free(); // expected-note{{'free' called on an object that may be referenced elsewhere}}756  // expected-warning@-1{{'free' called on an object that may be referenced elsewhere}}757}758 759void test_tagged_retain_no_leak() {760  OSObject *obj = new OSObject;761  obj->taggedRelease();762}763 764void test_tagged_retain_no_uaf() {765  OSObject *obj = new OSObject;766  obj->taggedRetain();767  obj->release();768  obj->release();769}770 771class IOService {772public:773  OSObject *somethingMatching(OSObject *table = 0);774};775 776OSObject *testSuppressionForMethodsEndingWithMatching(IOService *svc,777                                                      OSObject *table = 0) {778  // This probably just passes table through. We should probably not make779  // ptr1 definitely equal to table, but we should not warn about leaks.780  OSObject *ptr1 = svc->somethingMatching(table); // no-warning781 782  // FIXME: This, however, should follow the Create Rule regardless.783  // We should warn about the leak here.784  OSObject *ptr2 = svc->somethingMatching(); // no-warning785 786  if (!table)787    table = OSTypeAlloc(OSArray);788 789  // This function itself ends with "Matching"! Do not warn when we're790  // returning from it at +0.791  return table; // no-warning792}793 794namespace weird_result {795struct WeirdResult {796  int x, y, z;797};798 799WeirdResult outParamWithWeirdResult(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);800 801WeirdResult testOutParamWithWeirdResult() {802  OSObject *obj;803  return outParamWithWeirdResult(&obj); // no-warning804}805} // namespace weird_result806 807namespace inherited_constructor_crash {808struct a {809  a(int);810};811struct b : a {812  // This is an "inherited constructor".813  using a::a;814};815void test() {816  // RetainCountChecker used to crash when looking for a summary817  // for the inherited constructor invocation.818  b(0);819}820} // namespace inherited_constructor_crash821