X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_utilities/lib/cfclass.cpp diff --git a/libsecurity_utilities/lib/cfclass.cpp b/libsecurity_utilities/lib/cfclass.cpp new file mode 100644 index 00000000..cfd80514 --- /dev/null +++ b/libsecurity_utilities/lib/cfclass.cpp @@ -0,0 +1,250 @@ + /* + * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include + +// +// CFClass +// +CFClass::CFClass(const char *name) +{ + // initialize the CFRuntimeClass structure + version = 0; + className = name; + init = NULL; + copy = NULL; + finalize = finalizeType; + equal = equalType; + hash = hashType; + copyFormattingDesc = copyFormattingDescType; + copyDebugDesc = copyDebugDescType; + + // update because we are now doing our own reference counting + version |= _kCFRuntimeCustomRefCount; // see ma, no hands! + refcount = refCountForType; + + // register + typeID = _CFRuntimeRegisterClass(this); + assert(typeID != _kCFRuntimeNotATypeID); +} + +uint32_t +CFClass::cleanupObject(intptr_t op, CFTypeRef cf, bool &zap) +{ + // the default is to not throw away the object + zap = false; + + bool isGC = CF_IS_COLLECTABLE(cf); + + uint32_t currentCount; + SecCFObject *obj = SecCFObject::optional(cf); + + uint32_t oldCount; + currentCount = obj->updateRetainCount(op, &oldCount); + + if (isGC) + { + auto_zone_t* zone = objc_collectableZone(); + + if (op == -1 && oldCount == 0) + { + auto_zone_release(zone, (void*) cf); + } + else if (op == 1 && oldCount == 0 && currentCount == 1) + { + auto_zone_retain(zone, (void*) cf); + } + else if (op == -1 && oldCount == 1 && currentCount == 0) + { + /* + To prevent accidental resurrection, just pull it out of the + cache. + */ + obj->aboutToDestruct(); + auto_zone_release(zone, (void*) cf); + } + else if (op == 0) + { + return currentCount; + } + + return 0; + } + + if (op == 0) + { + return currentCount; + } + else if (currentCount == 0) + { + finalizeType(cf); + zap = true; // the the caller to release the mutex and zap the object + return 0; + } + else + { + return 0; + } +} + +uint32_t +CFClass::refCountForType(intptr_t op, CFTypeRef cf) throw() +{ + uint32_t result = 0; + bool zap = false; + + try + { + SecCFObject *obj = SecCFObject::optional(cf); + Mutex* mutex = obj->getMutexForObject(); + if (mutex == NULL) + { + // if the object didn't have a mutex, it wasn't cached. + // Just clean it up and get out. + result = cleanupObject(op, cf, zap); + } + else + { + // we have a mutex, so we need to do our cleanup operation under its control + StLock _(*mutex); + result = cleanupObject(op, cf, zap); + } + + if (zap) // did we release the object? + { + delete obj; // should call the overloaded delete for the object + } + } + catch (...) + { + } + + // keep the compiler happy + return result; +} + + + +void +CFClass::finalizeType(CFTypeRef cf) throw() +{ + /* + Why are we asserting the mutex here as well as in refCountForType? + Because the way we control the objects and the queues are different + under GC than they are under non-GC operations. + + In non-GC, we need to control the lifetime of the object. This means + that the cache lock has to be asserted while we are determining if the + object should live or die. The mutex is recursive, which means that + we won't end up with mutex inversion. + + In GC, GC figures out the lifetime of the object. We probably don't need + to assert the mutex here, but it doesn't hurt. + */ + + SecCFObject *obj = SecCFObject::optional(cf); + + bool isCollectable = CF_IS_COLLECTABLE(cf); + + try + { + Mutex* mutex = obj->getMutexForObject(); + if (mutex == NULL) + { + // if the object didn't have a mutex, it wasn't cached. + // Just clean it up and get out. + obj->aboutToDestruct(); // removes the object from its associated cache. + } + else + { + StLock _(*mutex); + + if (obj->isNew()) + { + // New objects aren't in the cache. + // Just clean it up and get out. + obj->aboutToDestruct(); // removes the object from its associated cache. + return; + } + + obj->aboutToDestruct(); // removes the object from its associated cache. + } + } + catch(...) + { + } + + if (isCollectable) + { + delete obj; + } +} + +Boolean +CFClass::equalType(CFTypeRef cf1, CFTypeRef cf2) throw() +{ + // CF checks for pointer equality and ensures type equality already + try { + return SecCFObject::optional(cf1)->equal(*SecCFObject::optional(cf2)); + } catch (...) { + return false; + } +} + +CFHashCode +CFClass::hashType(CFTypeRef cf) throw() +{ + try { + return SecCFObject::optional(cf)->hash(); + } catch (...) { + return 666; /* Beasty return for error */ + } +} + +CFStringRef +CFClass::copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) throw() +{ + try { + return SecCFObject::optional(cf)->copyFormattingDesc(dict); + } catch (...) { + return CFSTR("Exception thrown trying to format object"); + } +} + +CFStringRef +CFClass::copyDebugDescType(CFTypeRef cf) throw() +{ + try { + return SecCFObject::optional(cf)->copyDebugDesc(); + } catch (...) { + return CFSTR("Exception thrown trying to format object"); + } +} + +