brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.1 KiB · 2fbc515 Raw
94 lines · c
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.RetainCount -verify %s2// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.RetainCount -analyzer-inline-max-stack-depth=0 -verify %s3 4#pragma clang arc_cf_code_audited begin5typedef const void * CFTypeRef;6extern CFTypeRef CFRetain(CFTypeRef cf);7extern void CFRelease(CFTypeRef cf);8#pragma clang arc_cf_code_audited end9 10#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))11#define CF_CONSUMED __attribute__((cf_consumed))12 13extern CFTypeRef CFCreate(void) CF_RETURNS_RETAINED;14 15// A "safe" variant of CFRetain that doesn't crash when a null pointer is16// retained. This is often defined by users in a similar manner. The17// CF_RETURNS_RETAINED annotation is misleading here, because the function18// is not supposed to return an object with a +1 retain count. Instead, it19// is supposed to return an object with +(N+1) retain count, where N is20// the original retain count of 'cf'. However, there is no good annotation21// to use in this case, and it is pointless to provide such annotation22// because the only use cases would be CFRetain and SafeCFRetain.23// So instead we teach the analyzer to be able to accept such code24// and ignore the misplaced annotation.25CFTypeRef SafeCFRetain(CFTypeRef cf) CF_RETURNS_RETAINED {26  if (cf) {27    return CFRetain(cf);28  }29  return cf;30}31 32// A "safe" variant of CFRelease that doesn't crash when a null pointer is33// released. The CF_CONSUMED annotation seems reasonable here.34void SafeCFRelease(CFTypeRef CF_CONSUMED cf) {35  if (cf)36    CFRelease(cf); // no-warning (when inlined)37}38 39// The same thing, just with a different naming style.40CFTypeRef retainCFType(CFTypeRef cf) CF_RETURNS_RETAINED {41  if (cf) {42    return CFRetain(cf);43  }44  return cf;45}46 47void releaseCFType(CFTypeRef CF_CONSUMED cf) {48  if (cf)49    CFRelease(cf); // no-warning (when inlined)50}51 52void escape(CFTypeRef cf);53 54void makeSureTestsWork(void) {55  CFTypeRef cf = CFCreate();56  CFRelease(cf);57  CFRelease(cf); // expected-warning{{Reference-counted object is used after it is released}}58}59 60// Make sure we understand that the second SafeCFRetain doesn't return an61// object with +1 retain count, which we won't be able to release twice.62void falseOverrelease(CFTypeRef cf) {63  SafeCFRetain(cf);64  SafeCFRetain(cf);65  SafeCFRelease(cf);66  SafeCFRelease(cf); // no-warning after inlining this.67}68 69// Regular CFRelease() should behave similarly.70void sameWithNormalRelease(CFTypeRef cf) {71  SafeCFRetain(cf);72  SafeCFRetain(cf);73  CFRelease(cf);74  CFRelease(cf); // no-warning75}76 77// Make sure we understand that the second SafeCFRetain doesn't return an78// object with +1 retain count, which would no longer be owned by us after79// it escapes to escape() and released once.80void falseReleaseNotOwned(CFTypeRef cf) {81  SafeCFRetain(cf);82  SafeCFRetain(cf);83  escape(cf);84  SafeCFRelease(cf);85  SafeCFRelease(cf); // no-warning after inlining this.86}87 88void testTheOtherNamingConvention(CFTypeRef cf) {89  retainCFType(cf);90  retainCFType(cf);91  releaseCFType(cf);92  releaseCFType(cf); // no-warning93}94