Hi,

I have a strange problem.

I am using C and the objc runtime on OSX 10.9.3 to get a value from a
NSDictionary.

The objectForKey method returns an invalid pointer on x64 (not NULL,
but the same address 0x937 for _any_ valid key), but works fine on
i386.

I attached a small test case to show the problem.

Here's how to build and run the test case:

echo "on 32bit works..."
gcc -arch i386 -O2 test5.c -o test5_32 -lobjc
./test5_32

echo "on 64bit crashes..."
gcc -arch x86_64 -O2 test5.c -o test5 -lobjc
./test5


Any help would be appreciated, even to tell me that you can or can't
reproduce the problem or that you find problems with the code, or to
redirect me to a different forum/mailing list.

Thanks,
Cosmin.
#include <assert.h>
#include <stdio.h>
#include <dlfcn.h>

typedef struct objc_class    *Class;
typedef struct objc_object   *id;
typedef struct objc_method   *Method;
typedef struct objc_selector *SEL;

struct objc_class  { Class isa; };
struct objc_object { Class isa; };

typedef id (*IMP) (id, SEL, ...);

Class objc_getClass(const char *name);
SEL sel_registerName(const char *str);
Method class_getInstanceMethod(Class aClass, SEL aSelector);
IMP method_getImplementation(Method method);

IMP cimp(const char* clsname, const char* selname) {
	Class  cls    = objc_getClass(clsname)                     ; assert(cls != 0);
	SEL    sel    = sel_registerName(selname)                  ; assert(sel != 0);
	Method method = class_getInstanceMethod(cls->isa, sel)     ; assert(method != 0);
	IMP    imp    = method_getImplementation(method)           ; assert(imp != 0);
	return imp;
}

IMP imp(id obj, const char* selname) {
	Class  cls    = obj->isa                                   ; assert(obj != 0); assert(cls != 0);
	SEL    sel    = sel_registerName(selname)                  ; assert(sel != 0);
	Method method = class_getInstanceMethod(cls, sel)          ; assert(method != 0);
	IMP    imp    = method_getImplementation(method)           ; assert(imp != 0);
	return imp;
}

#define callc(clsname, selname, ctype, ...) (((ctype)cimp(clsname, selname)) ((id)objc_getClass(clsname), sel_registerName(selname), __VA_ARGS__))
#define callc0(clsname, selname, ctype)     (((ctype)cimp(clsname, selname)) ((id)objc_getClass(clsname), sel_registerName(selname)))
#define call(obj, selname, ctype, ...)      (((ctype)imp (obj,     selname)) (obj, sel_registerName(selname), __VA_ARGS__))
#define call0(obj, selname, ctype)          (((ctype)imp (obj,     selname)) (obj, sel_registerName(selname)))

int main() {

	setvbuf(stdout, NULL, _IONBF, 0);

	dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_GLOBAL);

	{
	//making a NSNumber from scratch works...
	id n = callc("NSNumber", "numberWithDouble:", id (*) (id, SEL, double), 12345); //make a NSNumber with value 12345
	printf("%p\n", (void*)n); //note the high address

	double x = call0(n, "doubleValue", double (*) (id, SEL)); //get back the value
	printf("%f\n", x); //12345
	}

	//but getting a NSNumber from the dictionary below segfaults on 64bit (works on 32bit)...

	const char* path = "/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/Frameworks/HIServices.framework/Versions/Current/Resources/cursors/resizenorthwestsoutheast/info.plist";

	//create a dictionary from the contents of the info.plist file
	id spath = callc("NSString", "stringWithUTF8String:", id (*) (id, SEL, const char*), path); //make a NSString with the value of `path`
	id d = callc("NSDictionary", "dictionaryWithContentsOfFile:", id (*) (id, SEL, id), spath); //make a NSDictionary with contents of `path`

	//try to get the value of the key "hotx" from that dictionary
	id s = callc("NSString", "stringWithUTF8String:", id (*) (id, SEL, const char*), "hotx"); //make a NSString with value "hotx"
	id n = call(d, "objectForKey:", id (*) (id, SEL, id), s); //get the value of key "hotx"
	printf("%p\n", (void*)n); //note the low address

	s = callc("NSString", "stringWithUTF8String:", id (*) (id, SEL, const char*), "hoty"); //make a NSString with value "hoty"
	n = call(d, "objectForKey:", id (*) (id, SEL, id), s); //get the value of key "hoty"
	printf("%p\n", (void*)n); //note the same low address !!! what's going on here???

	double x = call0(n, "doubleValue", double (*) (id, SEL)); //crash, of course...
	printf("%f\n", x); //should be 9

	return 0;
}

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to