Skip to content

Commit

Permalink
Retrieve class of instance in objc_alloc_init
Browse files Browse the repository at this point in the history
If +alloc was overwritten, it is not guaranteed that it returns an
instance of cls. Retrieve the class of the instance returned by
objc_alloc instead.
  • Loading branch information
hmelder committed Nov 18, 2024
1 parent 47d02a8 commit cca7623
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 3 deletions.
13 changes: 13 additions & 0 deletions Test/FastPathAlloc.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ @interface NoAlloc : Test @end
@interface NoInit : Test @end
@interface NoInit2 : NoInit @end

@interface ShouldInitSubclassed : NoInit @end

@implementation ShouldAlloc
+ (instancetype)alloc
{
Expand Down Expand Up @@ -91,6 +93,13 @@ + (instancetype)alloc
}
@end

@implementation ShouldInitSubclassed
+ (instancetype) alloc
{
return [ShouldInit alloc];
}
@end

Class getClassNamed(char *name)
{
return nil;
Expand All @@ -114,6 +123,10 @@ int main(void)
[[ShouldInit2 alloc] init];
assert(called);

called = NO;
[[ShouldInitSubclassed alloc] init];
assert(called);

called = NO;
[NoAlloc alloc];
assert(!called);
Expand Down
6 changes: 3 additions & 3 deletions fast_paths.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ - (id)init;
@end
#include <stdio.h>

/**
* Equivalent to [cls alloc]. If there's a fast path opt-in, then this skips the message send.
*/
OBJC_PUBLIC
id
objc_alloc(Class cls)
Expand Down Expand Up @@ -66,6 +63,9 @@ - (id)init;
return nil;
}
id instance = objc_alloc(cls);
// If +alloc was overwritten, it is not guaranteed that it returns
// an instance of cls.
cls = classForObject(instance);
if (objc_test_class_flag(cls, objc_class_flag_fast_alloc_init))
{
return instance;
Expand Down

0 comments on commit cca7623

Please sign in to comment.