[llvm-dev] Debugging a metadata-emit problem, Bug #30413

Lobron, David via llvm-dev llvm-dev at lists.llvm.org
Tue Jan 17 07:31:37 PST 2017


Hello llvm-dev,

I opened bug report 30413 a while ago, and I'd like to request help from someone with better knowledge of clang.  The bug occurs on Linux, where clang does not emit type metadata when compiling Objective-C programs, as it does on the Mac, and as gcc does on Linux.  My program uses that metadata to do type introspection (see below for an example).

>From code inspection, it appears that the type metadata is written by code in clang's ASTContext class.  I wrote a test program, copied below, which reproduces this bug.  I ran clang under gdb, and set a breakpoint on all the methods in the clang::ASTContext:: namespace, but I found that none of these were called (at least, none of the 571 breakpoints was triggered).  I confirmed that other gdb breakpoints (e.g., on ::main) did get triggered, so I know that my breakpoints in general were working. 

I was left with two questions:

- Are the clang::ASTContext:: methods not called when compiling an ObjC program?

- Is there some other part of the code where the metadata is emitted, if not from clang::ASTContext::?  I looked for a quite a while, but I could not find a plausible candidate.

Any help would be appreciated!  Feel free to reply to me directly, or to the list, or to post suggestions in the bug report here:

https://llvm.org/bugs/show_bug.cgi?id=30413

Thanks!

--David

My test program code is below.  On a Mac, compiled with clang, the runtime can correctly introspect the type of an NSString* instance variable.  The output is:

2017-01-17 10:26:21.333 TestClassMetadata[13856:3607976] Ivar type _intIvar does not appear to be an object-valued class: type is i
2017-01-17 10:26:21.334 TestClassMetadata[13856:3607976] Ivar type _doubleVar does not appear to be an object-valued class: type is d
2017-01-17 10:26:21.334 TestClassMetadata[13856:3607976] Introspected class NSString for ivar name _stringIvar

On Linux, compiled with clang, the NSString introspection does not work, because the metadata is not present.  The output there is:

2017-01-17 15:27:15.641 TestClassMetadata[32308:32308] Ivar type _intIvar does not appear to be an object-valued class: type is i
2017-01-17 15:27:15.661 TestClassMetadata[32308:32308] Ivar type _doubleVar does not appear to be an object-valued class: type is d
2017-01-17 15:27:15.661 TestClassMetadata[32308:32308] Ivar type _stringIvar does not appear to be an object-valued class: type is @

(Note the difference in the last lines).

Program code:

#import <Foundation/Foundation.h>

#ifdef __APPLE__
#import <objc/objc-runtime.h>
#else
#import <objc/runtime.h>
#endif

@interface TestClass : NSObject {
    @public
    int         _intIvar;
    double      _doubleVar;
    NSString    *_stringIvar;
}
- (id)init;
- (void)sayHello:(NSString *)txt;
@end

@implementation TestClass

- (void)sayHello:(NSString *)txt 
{
  [_stringIvar release];
  _stringIvar = [txt retain];
  NSLog(@"%@", _stringIvar);
}

- (void)dealloc
{
  [_stringIvar release];
  [super dealloc];
}

- (id)init {
    if ((self = [super init]) != nil) {
        unsigned i;
        Class c = [self class];
        NSAssert(c != 0, @"Could not get class object");
	unsigned ivarCount;
	Ivar *ivarList = class_copyIvarList(c, &ivarCount);
	for (i = 0; i < ivarCount; i++) {
	    Ivar ivar = ivarList[i];
	    const char *ivarCname = ivar_getName(ivar);
	    if (ivarCname != 0) {
		NSString *ivarName = [NSString stringWithUTF8String:ivarCname];
		const char *ivarType = ivar_getTypeEncoding(ivar);
		if (ivarType[0] == '@' && ivarType[1] == '"') {
		    NSString *className = [[[NSString alloc] initWithBytes: &ivarType[2]
							     length: strlen(&ivarType[2])-1
							     encoding: NSUTF8StringEncoding] autorelease];
		    Class c = NSClassFromString(className);
		    if (c == nil) {
			NSLog(@"WARNING: unknown class name \"%@\" in declaration of %@", className, [self class]);
		    } else {
			NSLog(@"Introspected class %@ for ivar name %@",
			      className, ivarName);
		    }
		} else {
		    NSLog(@"Ivar type %s does not appear to be an object-valued class: type is %s", ivarCname, ivarType);
		}
	    }
	}
	if (ivarList)
	    free(ivarList);
    }
    
    return self;
}

@end

int main() {
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    TestClass *c = [[[TestClass alloc] init] autorelease];
    [pool release];
    
    return 0;
}


More information about the llvm-dev mailing list