Audit the runtime for direct access to variable-sized arrays.

Several of the structures now end with an array of structures that may
have other fields added to them that the runtime doesn't know about yet
by a compiler.  Rather than indexing into them directly, we must call an
accessor to find the correct address.

A few of the places where accesses were replaced were in functions where
it is safe because they only deal with versions of the structures that
are dynamically allocated (and will therefore have the correct size).
This was done to simplify future auditing: these fields should be
accessed directly only from the accessor functions in the header and
from the upgraders (currently in legacy.c).

Also fix a few bugs where the sizes weren't being filled in.
main
David Chisnall 8 years ago
parent 64ab2d51f5
commit c4ff744620

@ -49,7 +49,7 @@ PRIVATE void objc_send_load_message(Class class)
{
for (int i=0 ; i<l->count ; i++)
{
Method m = &l->methods[i];
Method m = method_at_index(l, i);
if (sel_isEqual(m->selector, loadSel))
{
if (load_messages_table_get(load_table, m->imp) == 0)
@ -345,8 +345,8 @@ static void reload_class(struct objc_class *class, struct objc_class *old)
// work with the view ivar now!
for (int i=0 ; equalLayouts && (i<old->ivars->count) ; i++)
{
struct objc_ivar *oldIvar = &old->ivars->ivar_list[i];
struct objc_ivar *newIvar = &class->ivars->ivar_list[i];
struct objc_ivar *oldIvar = ivar_at_index(old->ivars, i);
struct objc_ivar *newIvar = ivar_at_index(class->ivars, i);
equalLayouts &= strcmp(oldIvar->name, newIvar->name) == 0;
equalLayouts &= strcmp(oldIvar->type, newIvar->type) == 0;
equalLayouts &= (oldIvar->offset == newIvar->offset);

@ -153,7 +153,7 @@ PRIVATE void checkARCAccessorsSlow(Class cls)
{
for (int i=0 ; i<l->count ; i++)
{
SEL s = l->methods[i].selector;
SEL s = method_at_index(l, i)->selector;
if (selEqualUnTyped(s, retain) ||
selEqualUnTyped(s, release) ||
selEqualUnTyped(s, autorelease))
@ -184,8 +184,8 @@ static void collectMethodsForMethodListToSparseArray(
}
for (unsigned i=0 ; i<list->count ; i++)
{
SparseArrayInsert(sarray, list->methods[i].selector->index,
(void*)&list->methods[i]);
SparseArrayInsert(sarray, method_at_index(list, i)->selector->index,
(void*)method_at_index(list, i));
}
}
@ -458,9 +458,9 @@ static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
for (unsigned i=0 ; i<list->count ; i++)
{
struct objc_method *super_method = super_dtable
? SparseArrayLookup(super_dtable, list->methods[i].selector->index)
? SparseArrayLookup(super_dtable, method_at_index(list, i)->selector->index)
: NULL;
installMethodInDtable(class, dtable, &list->methods[i], super_method, YES);
installMethodInDtable(class, dtable, method_at_index(list, i), super_method, YES);
}
list = list->next;
}

@ -344,9 +344,9 @@ static void collectIvarForClass(Class cls, GC_word *bitmap)
{
for (unsigned i=0 ; (cls->ivars != 0) && (i<cls->ivars->count) ; i++)
{
struct objc_ivar *ivar = &cls->ivars->ivar_list[i];
struct objc_ivar *ivar = ivar_at_index(cls->ivars, i);
size_t start = ivar->offset;
size_t end = i+1 < cls->ivars->count ? cls->ivars->ivar_list[i+1].offset
size_t end = i+1 < cls->ivars->count ? ivar_at_index(cls->ivars, i+1)->offset
: cls->instance_size;
switch (ivar->type[0])
{

@ -65,14 +65,14 @@ PRIVATE void objc_compute_ivar_offsets(Class class)
long cumulative_fudge = 0;
for (i = 0 ; i < class->ivars->count ; i++)
{
struct objc_ivar *ivar = &class->ivars->ivar_list[i];
struct objc_ivar *ivar = ivar_at_index(class->ivars, i);
// We are going to be allocating an extra word for the reference count
// in front of the object. This doesn't matter for aligment most of
// the time, but if we have an instance variable that is a vector type
// then we will need to ensure that we are properly aligned again.
long ivar_size = (i+1 == class->ivars->count)
? (class_size - *ivar->offset)
: *class->ivars->ivar_list[i+1].offset - *ivar->offset ;
: *ivar_at_index(class->ivars, i+1)->offset - *ivar->offset ;
// FIXME: use alignment
*ivar->offset += cumulative_fudge;
// We only need to do the realignment for things that are
@ -96,7 +96,7 @@ PRIVATE void objc_compute_ivar_offsets(Class class)
{
for (i = 0 ; i < class->ivars->count ; i++)
{
legacy->ivars->ivar_list[i].offset = *class->ivars->ivar_list[i].offset;
legacy->ivars->ivar_list[i].offset = *ivar_at_index(class->ivars, i)->offset;
}
}
}

@ -1,3 +1,4 @@
#include <assert.h>
/**
* Metadata structure for an instance variable.
@ -120,6 +121,20 @@ struct objc_ivar_list
struct objc_ivar ivar_list[];
};
/**
* Returns a pointer to the ivar inside the `objc_ivar_list` structure. This
* structure is designed to allow the compiler to add other fields without
* breaking the ABI, so although the `ivar_list` field appears to be an array
* of `objc_ivar` structures, it may be an array of some future version of
* `objc_ivar` structs, which have fields appended that this version of the
* runtime does not know about.
*/
static struct objc_ivar *ivar_at_index(struct objc_ivar_list *l, int i)
{
assert(l->size >= sizeof(struct objc_ivar));
return (struct objc_ivar*)(((char*)l->ivar_list) + (i * l->size));
}
/**
* Legacy version of the ivar list
*/

@ -1,3 +1,5 @@
#include <assert.h>
/**
* Metadata structure describing a method.
*/
@ -63,6 +65,20 @@ struct objc_method_list
struct objc_method methods[];
};
/**
* Returns a pointer to the method inside the `objc_method` structure. This
* structure is designed to allow the compiler to add other fields without
* breaking the ABI, so although the `methods` field appears to be an array
* of `objc_method` structures, it may be an array of some future version of
* `objc_method` structs, which have fields appended that this version of the
* runtime does not know about.
*/
static struct objc_method *method_at_index(struct objc_method_list *l, int i)
{
assert(l->size >= sizeof(struct objc_method));
return (struct objc_method*)(((char*)l->methods) + (i * l->size));
}
/**
* Legacy version of the method list.
*/

@ -1,4 +1,5 @@
#include "visibility.h"
#include <assert.h>
enum PropertyAttributeKind
{
@ -204,6 +205,20 @@ struct objc_property_list
struct objc_property properties[];
};
/**
* Returns a pointer to the property inside the `objc_property` structure.
* This structure is designed to allow the compiler to add other fields without
* breaking the ABI, so although the `properties` field appears to be an array
* of `objc_property` structures, it may be an array of some future version of
* `objc_property` structs, which have fields appended that this version of the
* runtime does not know about.
*/
static struct objc_property *property_at_index(struct objc_property_list *l, int i)
{
assert(l->size >= sizeof(struct objc_property));
return (struct objc_property*)(((char*)l->properties) + (i * l->size));
}
/**
* Constructs a property description from a list of attributes, returning the
* instance variable name via the third parameter.

@ -249,7 +249,7 @@ objc_property_t class_getProperty(Class cls, const char *name)
{
for (int i=0 ; i<properties->count ; i++)
{
objc_property_t p = &properties->properties[i];
objc_property_t p = property_at_index(properties, i);
if (strcmp(property_getName(p), name) == 0)
{
return p;
@ -287,7 +287,7 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount)
{
for (int i=0 ; i<properties->count ; i++)
{
list[out++] = &l->properties[i];
list[out++] = property_at_index(l, i);
}
}
return list;

@ -363,8 +363,8 @@ struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
calloc(sizeof(struct objc_method_description), list->count);
for (int i=0 ; i < (list->count) ; i++)
{
out[i].name = list->methods[i].selector;
out[i].types = sel_getType_np(list->methods[i].selector);
out[i].name = protocol_method_at_index(list, i)->selector;
out[i].types = sel_getType_np(protocol_method_at_index(list, i)->selector);
}
return out;
}
@ -415,7 +415,7 @@ objc_property_t *protocol_copyPropertyList(Protocol *p,
{
for (int i=0 ; i<properties->count ; i++)
{
list[out++] = &properties->properties[i];
list[out++] = property_at_index(properties, i);
}
}
properties = p->optional_properties;
@ -423,7 +423,7 @@ objc_property_t *protocol_copyPropertyList(Protocol *p,
{
for (int i=0 ; i<properties->count ; i++)
{
list[out++] = &properties->properties[i];
list[out++] = property_at_index(properties, i);
}
}
*outCount = count;
@ -449,7 +449,7 @@ objc_property_t protocol_getProperty(Protocol *p,
{
for (int i=0 ; i<properties->count ; i++)
{
objc_property_t prop = &properties->properties[i];
objc_property_t prop = property_at_index(properties, i);
if (strcmp(property_getName(prop), name) == 0)
{
return prop;
@ -474,10 +474,10 @@ get_method_description(Protocol *p,
}
for (int i=0 ; i<list->count ; i++)
{
SEL s = list->methods[i].selector;
SEL s = protocol_method_at_index(list, i)->selector;
if (sel_isEqual(s, aSel))
{
return &list->methods[i];
return protocol_method_at_index(list, i);
}
}
return NULL;
@ -634,8 +634,8 @@ void protocol_addMethodDescription(Protocol *aProtocol,
}
struct objc_protocol_method_description_list *list = *listPtr;
int index = list->count-1;
list->methods[index].selector = sel_registerTypedName_np(sel_getName(name), types);
list->methods[index].types = types;
protocol_method_at_index(list, index)->selector = sel_registerTypedName_np(sel_getName(name), types);
protocol_method_at_index(list, index)->types = types;
}
void protocol_addProtocol(Protocol *aProtocol, Protocol *addition)
{
@ -677,6 +677,7 @@ void protocol_addProperty(Protocol *aProtocol,
if (NULL == *listPtr)
{
*listPtr = calloc(1, sizeof(struct objc_property_list) + sizeof(struct objc_property));
(*listPtr)->size = sizeof(struct objc_property);
(*listPtr)->count = 1;
}
else
@ -689,6 +690,7 @@ void protocol_addProperty(Protocol *aProtocol,
int index = list->count-1;
const char *iVarName = NULL;
struct objc_property p = propertyFromAttrs(attributes, attributeCount, name);
assert(list->size == sizeof(p));
memcpy(&(list->properties[index]), &p, sizeof(p));
}

@ -3,6 +3,7 @@
#include "selector.h"
#include <stdlib.h>
#include <assert.h>
struct objc_protocol_method_description_list_gcc
{
@ -49,6 +50,21 @@ struct objc_protocol_method_description_list
struct objc_protocol_method_description methods[];
};
/**
* Returns a pointer to the method inside the method description list
* structure. This structure is designed to allow the compiler to add other
* fields without breaking the ABI, so although the `methods` field appears to
* be an array of `objc_protocol_method_description` structures, it may be an
* array of some future version of these structs, which have fields appended
* that this version of the runtime does not know about.
*/
static struct objc_protocol_method_description *
protocol_method_at_index(struct objc_protocol_method_description_list *l, int i)
{
assert(l->size >= sizeof(struct objc_protocol_method_description));
return (struct objc_protocol_method_description*)(((char*)l->methods) + (i * l->size));
}
struct objc_protocol
{
/**

@ -78,7 +78,7 @@ static Method class_getInstanceMethodNonrecursive(Class aClass, SEL aSelector)
{
for (int i=0 ; i<methods->count ; i++)
{
Method method = &methods->methods[i];
Method method = method_at_index(methods, i);
if (sel_isEqual(method->selector, aSelector))
{
return method;
@ -121,7 +121,7 @@ BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment,
cls->ivars = realloc(ivarlist, sizeof(struct objc_ivar_list) +
(ivarlist->count) * sizeof(struct objc_ivar));
}
Ivar ivar = &cls->ivars->ivar_list[cls->ivars->count - 1];
Ivar ivar = ivar_at_index(cls->ivars, cls->ivars->count - 1);
ivar->name = strdup(name);
ivar->type = strdup(types);
ivar->align = alignment;
@ -156,7 +156,7 @@ BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
{
for (int i=0 ; i<methods->count ; i++)
{
Method method = &methods->methods[i];
Method method = method_at_index(methods, i);
if (strcmp(sel_getName(method->selector), methodName) == 0)
{
return NO;
@ -166,12 +166,14 @@ BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
methods = malloc(sizeof(struct objc_method_list) + sizeof(struct objc_method));
methods->next = cls->methods;
methods->size = sizeof(struct objc_method);
cls->methods = methods;
methods->count = 1;
methods->methods[0].selector = sel_registerTypedName_np(methodName, types);
methods->methods[0].types = strdup(types);
methods->methods[0].imp = imp;
struct objc_method *m0 = method_at_index(methods, 0);
m0->selector = sel_registerTypedName_np(methodName, types);
m0->types = strdup(types);
m0->imp = imp;
if (classHasDtable(cls))
{
@ -227,7 +229,7 @@ Ivar * class_copyIvarList(Class cls, unsigned int *outCount)
count = 0;
for (index = 0; index < ivarlist->count; index++)
{
list[count++] = &ivarlist->ivar_list[index];
list[count++] = ivar_at_index(ivarlist, index);
}
return list;
@ -264,7 +266,7 @@ Method * class_copyMethodList(Class cls, unsigned int *outCount)
unsigned int index;
for (index = 0; index < methods->count; index++)
{
list[count++] = &methods->methods[index];
list[count++] = method_at_index(methods, index);
}
}
@ -409,7 +411,7 @@ Ivar class_getInstanceVariable(Class cls, const char *name)
{
for (int i = 0; i < ivarlist->count; i++)
{
Ivar ivar = &ivarlist->ivar_list[i];
Ivar ivar = ivar_at_index(ivarlist, i);
if (strcmp(ivar->name, name) == 0)
{
return ivar;
@ -569,7 +571,7 @@ static void freeMethodLists(Class aClass)
{
for (int i=0 ; i<methods->count ; i++)
{
free((void*)methods->methods[i].types);
free((void*)method_at_index(methods, i)->types);
}
struct objc_method_list *current = methods;
methods = methods->next;
@ -586,12 +588,12 @@ static void freeIvarLists(Class aClass)
{
// For dynamically created classes, ivar offset variables are allocated
// as a contiguous range starting with the first one.
free(ivarlist->ivar_list[0].offset);
free(ivar_at_index(ivarlist, 0)->offset);
}
for (int i=0 ; i<ivarlist->count ; i++)
{
Ivar ivar = &ivarlist->ivar_list[i];
Ivar ivar = ivar_at_index(ivarlist, i);
free((void*)ivar->type);
free((void*)ivar->name);
}
@ -765,8 +767,8 @@ void objc_registerClassPair(Class cls)
int *ptrs = calloc(cls->ivars->count, sizeof(int));
for (int i=0 ; i<cls->ivars->count ; i++)
{
ptrs[i] = (int)(intptr_t)cls->ivars->ivar_list[i].offset;
cls->ivars->ivar_list[i].offset = &ptrs[i];
ptrs[i] = (int)(intptr_t)ivar_at_index(cls->ivars, i)->offset;
ivar_at_index(cls->ivars, i)->offset = &ptrs[i];
}
}
LOCK_RUNTIME_FOR_SCOPE();

@ -588,7 +588,7 @@ PRIVATE void objc_register_selectors_from_list(struct objc_method_list *l)
{
for (int i=0 ; i<l->count ; i++)
{
Method m = &l->methods[i];
Method m = method_at_index(l, i);
struct objc_selector sel = { {(const char*)m->selector}, m->types };
m->selector = objc_register_selector_copy(&sel, NO);
}

Loading…
Cancel
Save