diff --git a/init.c b/init.c index b559468..35e843b 100644 --- a/init.c +++ b/init.c @@ -756,38 +756,51 @@ __objc_compute_ivar_offsets (Class class) } else { - if (class->ivars != 0) + if (NULL == class->ivars) { - Class super = class_superclass_of_class(class); - int start = class->ivars->ivar_list[0].ivar_offset; - /* Quick and dirty test */ - if (Nil != super && start != super->instance_size) - { - while (NULL == super->ivars) - { - super = class_superclass_of_class(super); - } - struct objc_ivar *ivar = - &super->ivars->ivar_list[super->ivars->ivar_count-1]; - if (start != (ivar->ivar_offset + objc_sizeof_type(ivar->ivar_type))) - { - /* Panic if this class has an instance variable that overlaps the - * superclass. */ - fprintf(stderr, - "Error: Instance variables in %s overlap superclass %s", - class->name, super->name); - fprintf(stderr, - "Offset of first instance variable, %s, is %d", - class->ivars->ivar_list[0].ivar_name, start); - fprintf(stderr, - "Last instance variable in superclass, %s, ends at offset %d", - ivar->ivar_name, - ivar->ivar_offset + objc_sizeof_type(ivar->ivar_type)); - fprintf(stderr, "This probably means that you are subclassing a class from a library, which has changed in a binary-incompatible way.\n"); - abort(); - } - } + return; + } + Class super = class_superclass_of_class(class); + int start = class->ivars->ivar_list[0].ivar_offset; + /* Quick and dirty test. If the first ivar comes straight after the last + * class, then it's fine. */ + if (Nil == super || start == super->instance_size) + { + return; + } + /* Find the last superclass with at least one ivar. */ + while (NULL == super->ivars) + { + super = class_superclass_of_class(super); + } + struct objc_ivar *ivar = + &super->ivars->ivar_list[super->ivars->ivar_count-1]; + if (start == (ivar->ivar_offset + objc_sizeof_type(ivar->ivar_type))) + { + return; + } + /* The classes don't line up, but don't panic; check that the + * difference is not just padding for alignment */ + int align = objc_alignof_type(class->ivars->ivar_list[0].ivar_type); + if (start > ivar->ivar_offset && + start - ivar->ivar_offset < align) + { + return; } + /* Panic if this class has an instance variable that overlaps the + * superclass. */ + fprintf(stderr, + "Error: Instance variables in %s overlap superclass %s", + class->name, super->name); + fprintf(stderr, + "Offset of first instance variable, %s, is %d", + class->ivars->ivar_list[0].ivar_name, start); + fprintf(stderr, + "Last instance variable in superclass, %s, ends at offset %d", + ivar->ivar_name, + ivar->ivar_offset + objc_sizeof_type(ivar->ivar_type)); + fprintf(stderr, "This probably means that you are subclassing a class from a library, which has changed in a binary-incompatible way.\n"); + abort(); } }