I am writing a Python script that calls functions from Security.framework on OS X through ctypes.
I was able to make a CFDictionaryRef and CFStringRef in Python, and store the string in the dictionary, but now that I'm adding Security.framework query objects (kSecClass
, kSecMatchLimit
, kSecReturnAttributes
, …) I get the following crash:
objc[28201]: Method cache corrupted. This may be a message to an invalid object, or a memory error somewhere else.
objc[28201]: receiver 0x7fff724fcdf8, SEL 0x7fff8d814fe5, isa 0x7fff724f5f90, cache 0x7fff724f5fa0, buckets 0x7fff8842ffe3, mask 0x5, occupied 0x0, wrap bucket 0x7fff8842ffe3
objc[28201]: receiver 0 bytes, buckets 0 bytes
objc[28201]: selector 'hash'
objc[28201]: isa '(null)'
objc[28201]: Method cache corrupted.
zsh: illegal hardware instruction python kc.py
I've tried calling CFDictionaryCreate()
with ctypes arrays containing the objects, and also calling CFMutableDictionaryCreate()
then CFDictionarySetValue
. See below.
import ctypes
import ctypes.util
from ctypes import CFUNCTYPE
security = ctypes.CDLL(ctypes.util.find_library('Security'))
foundation = ctypes.CDLL(ctypes.util.find_library('Foundation'))
CFDictionaryRef = ctypes.c_void_p
CFMutableDictionaryRef = ctypes.c_void_p
CFTypeRef = ctypes.c_void_p
CFIndex = ctypes.c_long
CFDictionaryCreate = CFUNCTYPE(CFDictionaryRef, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, CFIndex, ctypes.c_void_p, ctypes.c_void_p)(('CFDictionaryCreate', foundation))
CFDictionaryCreateMutable = CFUNCTYPE(CFMutableDictionaryRef, CFIndex, ctypes.c_void_p, ctypes.c_void_p)(('CFDictionaryCreateMutable', foundation))
CFDictionarySetValue = CFUNCTYPE(CFMutableDictionaryRef, ctypes.c_void_p, ctypes.c_void_p)(('CFDictionarySetValue', foundation))
def createCFDictionary(items):
"""
Create a CFDictionaryRef from items = [(CFTypeRef, CFTypeRef), ...]
"""
# Create C arrays for the keys and values (which are cast as CFTypeRefs).
keys_array = (CFTypeRef * len(items))(*[ctypes.cast(k, CFTypeRef) for k, v in items])
values_array = (CFTypeRef * len(items))(*[ctypes.cast(v, CFTypeRef) for k, v in items])
return CFDictionaryCreate(None,
keys_array, values_array, len(items),
foundation.kCFTypeDictionaryKeyCallBacks, foundation.kCFTypeDictionaryValueCallBacks)
# 1. Create a CFDictionary with the items in it (crashes).
query = createCFDictionary([(security.kSecClass, security.kSecClassCertificate)])
# 2a. Create a CFMutableDictionary.
query = CFDictionaryCreateMutable(0, foundation.kCFTypeDictionaryKeyCallBacks, foundation.kCFTypeDictionaryValueCallBacks)
# 2b. Add items to it (crashes).
CFDictionarySetValue(query, security.kSecClass, security.kSecClassCertificate)
I am happy to use PyObjC instead of ctypes if that's an easier solution; I am less familiar with it, however, and haven't been able to import Security.framework.
OS X 10.9.2, Python 2.7.5 (included with OS X).