Find out how many arguments a block needs - objective-c

Let's say I have an array containing Blocks, and I need to assert that all of them expect a given number of arguments.
Is there a way to find this out programmatically?

This is indeed possible, for any recent version of Clang.
The Apple ABI for Blocks is private but also published. Since that document tells us the layout the compiler will use for a Block object, we can duplicate that information in a header file and use it to access the components of a Block.
Mike Ash's MABlockForwarding project does just that (see also the article) -- much of the stuff at the top of this file is a copy-paste from the ABI doc. The thing that he created which we are interested in is the BlockSig() function:
static const char *BlockSig(id blockObj)
{
struct Block *block = (__bridge void *)blockObj;
struct BlockDescriptor *descriptor = block->descriptor;
assert(block->flags & BLOCK_HAS_SIGNATURE);
int index = 0;
if(block->flags & BLOCK_HAS_COPY_DISPOSE)
index += 2;
return descriptor->rest[index];
}
which will return (for Blocks that have it (which they all do with recent Clang)), a type encoding string describing the Block's return and argument types. From there, you can create an NSMethodSignature object, and ask it for its numberOfArguments:
NSString * (^block)(int, NSArray *) = ^NSString * (int i, NSArray * a){
return #"Oh, yeah!";
};
const char * types = BlockSig(block);
NSMethodSignature * sig = [NSMethodSignature signatureWithObjCTypes:types];
[sig numberOfArguments];
The result there is 3, because it includes a hidden argument for the Block itself (and Blocks don't use the hidden _cmd argument or it would be 4).

The answer is you cannot. See the comment on Mike Ash's page regarding this:
Search for Intropection which sends you here
So, what is your real problem? If you structure the arguments properly, you can insure that your system functions properly. For instance, you can do what C++ does with default values for arguments, and cast each block to a type that takes the max number of args, and always push that many items on the stack. Or you could always have the first argument be the number of arguments you are pushing on the stack. If you push objects and not numbers/pointers, then you r blocks can look at the class of each argument and dynamically adapt.

Related

Core Foundation: why LLVM analyzer report that caller doesn't own object created with *Create* function?

According to The Create Rule I have created my own "constructor" - CFStringCreateFromGoString. It contains "Create" in its name. I expect that if I call CFStringCreateFromGoString then I own returned object.
But according to LLVM static analyzer this is not entirely true and in some cases I receive warning Incorrect decrement of the reference count of an object that is not owned at this point by the caller - see 1.h. And in other cases where is no warning - see 2.h.
From common.h:
CFStringRef CFStringCreateFromGoString(_GoString_ str) {
return CFStringCreateWithBytes(NULL, (UInt8*)_GoStringPtr(str), (CFIndex)_GoStringLen(str), kCFStringEncodingUTF8, false);
}
From 1.h:
CGRect _GetTextLineGeometry(CGContextRef context, _GoString_ str, CTFontRef font) {
CFStringRef _str = CFStringCreateFromGoString(str);
CGRect r = GetTextLineGeometry(context, _str, font); // no warning if I remove this line
CFRelease(_str); // warning here
return r;
}
From 2.h:
CTFontRef _CreateFontFromFile(_GoString_ path, struct FontSpec spec) {
CFStringRef _path = CFStringCreateFromGoString(path);
CTFontRef r = CreateFontFromFile(_path, spec);
CFRelease(_path); // no warning
return r;
}
Can somebody explain the difference between 1.h and 2.h?
Update 0
Thx matt for comment.
The problem was at GetTextLineGeometry - this function by mistake performed CFRelease(_str). Now I have no warnings.
But I don't understand why warning was in _GetTextLineGeometry instead of GetTextLineGeometry?
The name component "Create" does not perform any magic; it is just a matter of convention. So, for that matter, is the concept of "ownership".
So forget about all that and just think about the retain count.
The static analyzer, unlike mere human beings like you and me, can see all your code, and can count. It is counting the retains and releases on this object. When we get to CFRelease(_str) in your first example, you have previously released this same object, causing its retain count to drop to zero; so at this point you are performing an overrelease. Thus the static analyzer flags you at this point.
Now let's go back and think about it again from the point of view of "ownership". Only the "owner" of something can release it; that is what "ownership" means. But the static analyzer is perfectly willing to let you transfer ownership, if you know what you're doing. So if you want to "take ownership" by releasing in GetTextLineGeometry, that's fine with the static analyzer. But when when we get to CFRelease(_str), that is a second "owner" — and that isn't cricket. Thus, again, the static analyzer flags you here.

Reading dynamically growing file using NSInputStream

I should use Objective-C to read some slowly growing file (under Mac OS X).
"Slowly" means that I read to EOF before it grows bigger.
In means of POSIX code in plain syncronous C I can do it as following:
while(1)
{
res = select(fd+1,&fdset,NULL,&fdset,some_timeout);
if(res > 0)
{
len = read(fd,buf,sizeof(buf));
if (len>0)
{
printf("Could read %u bytes. Continue.\n", len);
}
else
{
sleep(some_timeout_in_sec);
}
}
}
Now I want to re-write this in some asynchronous manner, using NSInputSource or some other async Objective-C technique.
The problem with NSInputSource: If I use scheduleInRunLoop: method then once I get NSStreamEventEndEncountered event, I stop receiving any events.
Can I still use NSInputSource or should I pass to using NSFileHandle somehow or what would you recommend ?
I see a few problems.
1) some_Timeout, for select() needs to be a struct timeval *.
2) for sleep() some_timeout needs to be an integer number of seconds.
3) the value in some_timeout is decremented via select() (which is why the last parameter is a pointer to the struct timeval*. And that struct needs to be re-initialized before each call to select().
4) the parameters to select() are highest fd of interest+1, then three separate struct fd_set * objects. The first is for input files, the second is for output files, the third is for exceptions, however, the posted code is using the same struct fd_set for both the inputs and the exceptions, This probably will not be what is needed.
When the above problems are corrected, the code should work.

CFStringGetCStringPtr returns NULL on iOS7

I have the following code in my Application:
static void foo(CFStringRef str)
{
CFStringEncoding encoding = CFStringGetSystemEncoding();
const char * cString = CFStringGetCStringPtr(str, encoding);
//.....
}
It's been around since iOS 5, and always worked.
Since iOS 7 release, CFStringGetCStringPtr returns NULL.
Adding the following code, have solved it:
if (cString==NULL)
{
cString = [
((NSString *)str) cStringUsingEncoding:[NSString defaultCStringEncoding]
];
}
Still, I would like to know if anyone knows what causes the problem?
CFStringGetCStringPtr() isn't guaranteed to return non-NULL. From the docs (emphasis added):
Whether or not this function returns a valid pointer or NULL depends on many factors, all of which depend on how the string was created and its properties. In addition, the function result might change between different releases and on different platforms. So do not count on receiving a non-NULL result from this function under any circumstances.
Always have a fallback to CFStringGetCString(), but even better, use Objective-C and NSString's helper methods (e.g. UTF8String).

Get generic type using Mono embedded

How to I create a generic List<String> object using mono embedded calls? I can get List's MonoClass:
MonoClass* list = mono_class_from_name(mscorlibimage,
"System.Collections.Generic", "List`1");
and I see in docs that there's
mono_class_from_generic_parameter(MonoGenericParam*...)
but I have no idea where and how to get the MonoGenericParam. Or perhaps I need to construct a valid name for mono_class_from_name? I think this can be a bit slower but I'd accept that for now. I tried
MonoClass* list = mono_class_from_name(mscorlib::get().image, "System.Collections.Generic", "List`1[System.String]");
but no luck.
UPDATE:
OK I found a way. Still I'd like to see if there's an official way of doing thing, as this hack looks too dirty to me.
Basically I searched mono sources for generic methods and found mono_class_bind_generic_parameters (see https://raw.github.com/mono/mono/master/mono/metadata/reflection.c). I had to link to libmono-2.0.a in addition to .so to use it. But it worked:
extern "C" MonoClass*
mono_class_bind_generic_parameters(MonoClass *klass,
int type_argc, MonoType **types, bool is_dynamic);
MonoClass* list = mono_class_from_name(mscorlib::get().image,
"System.Collections.Generic", "List`1");
MonoClass* strcls = mono_class_from_name(mscorlib::get().image, "System", "String");
printf("str class: %p\n", strcls);
MonoType* strtype = mono_class_get_type(strcls);
printf("str type: %p\n", strtype);
MonoType* types[1];
types[0] = strtype;
list = mono_class_bind_generic_parameters(list, 1, types, false);
printf("list[string] class: %p\n", list);
MonoObject* obj = mono_object_new(domain, list);
printf("list[string] created: %p\n", obj);
I suppose I can take sources (UPDATE: hardly so) of these methods and reimplement them (they parse metadata, etc) - if I don't want to link to .a - but I wonder if there's a simpler way. Mono docs just don't answer anything, as they use to.
UPDATE: found this thread: http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html which seems to say that no embedded API exists for what I want (i.e. they do not bother to expose mono_class_bind_generic_parameters). Can someone prove that it's correct? With that method, by the way, I get MonoReflectionType* and no way to get back MonoType* from it - while it is as easy to as getting ->type from the structure - which is internal and access via functions to it is internal. Mono Embedded should be called "Mono Internal" instead.
UPDATE: another method is to hack mono_class_inflate_generic_type using copy of internal structures:
struct _MonoGenericInst {
uint32_t id; /* unique ID for debugging */
uint32_t type_argc : 22; /* number of type arguments */
uint32_t is_open : 1; /* if this is an open type */
MonoType *type_argv [1];
};
struct _MonoGenericContext {
/* The instantiation corresponding to the class generic parameters */
MonoGenericInst *class_inst;
/* The instantiation corresponding to the method generic parameters */
void *method_inst;
};
_MonoGenericInst clsctx;
clsctx.type_argc = 1;
clsctx.is_open = 0;
clsctx.type_argv[0] = mono_class_get_type(System::String::_SClass());
MonoGenericContext ctx;
ctx.method_inst = 0;
ctx.class_inst = &clsctx;
MonoType* lt = mono_class_inflate_generic_type(
mono_class_get_type(System::Collections::Generic::List<System::String>::_SClass()),
&ctx);
This doesn't require static link to .a but is even a worse hack. And mono_class_inflate_generic_type is marked as DEPRECATED - so, if this is deprecated, then which is the modern one?
In many cases a mono embedding conundrum can be resolved by using a managed helper method. This is the approach used here.
So we have:
A managed helper method that accepts a generic type definition and an array of generic parameter types.
A client method that accepts a generic type definition name (e.g.: System.Collections.Generic.List`1), an assembly image that contains the type (or use an Assembly Qualified name) and an object of the required generic parameter type. We retrieve the underlying monoType for the object.
Note that when passing type info into the managed layer it has to be an instance of MonoReflectionType as obtained from mono_type_get_object().
The managed helper method is trivial and does the actual instantiation:
public static object CreateInstanceOfGenericType(Type genericTypeDefinition, Type[] parms)
{
// construct type from definition
Type constructedType = genericTypeDefinition.MakeGenericType(parms);
// create instance of constructed type
object obj = Activator.CreateInstance(constructedType);
return obj;
}
The helper code is called, in this case, from Objective-C:
+ (id)createInstanceOfGenericTypeDefinition:(char *)genericTypeDefinitionName monoImage:(MonoImage *)monoImage itemObject:(id)itemObject
{
// get the contained item monoType
MonoType *monoType = [DBType monoTypeForMonoObject:[itemObject monoObject]];
MonoReflectionType *monoReflectionType = mono_type_get_object([DBManagedEnvironment currentDomain], monoType);
// build a System.Array of item types
DBManagedObject *argType = [[DBManagedObject alloc] initWithMonoObject:(MonoObject *)monoReflectionType];
NSArray *argTypes = #[argType];
DBSystem_Array *dbsAargTypes = [argTypes dbsArrayWithTypeName:#"System.Type"];
// get the generic type definition
//
// Retrieves a MonoType from given name. If the name is not fully qualified,
// it defaults to get the type from the image or, if image is NULL or loading
// from it fails, uses corlib.
// This is the embedded equivalent of System.Type.GetType();
MonoType *monoGenericTypeDefinition = mono_reflection_type_from_name(genericTypeDefinitionName, monoImage);
// create instance using helper method
MonoMethod *helperMethod = [DBManagedEnvironment dubrovnikMonoMethodWithName:"CreateInstanceOfGenericType" className:"Dubrovnik.FrameworkHelper.GenericHelper" argCount:2];
void *hargs [2];
hargs[0] = mono_type_get_object([DBManagedEnvironment currentDomain], monoGenericTypeDefinition);
hargs[1] = [dbsAargTypes monoArray]; // a monoArray *
MonoObject *monoException = NULL;
MonoObject *monoObject = mono_runtime_invoke(helperMethod, NULL, hargs, &monoException);
if (monoException) NSRaiseExceptionFromMonoException(monoException);
id object = [System_Object subclassObjectWithMonoObject:monoObject];
return object;
}
For the complete code see Dubrovnik on Github

Corefoundation CFArray ownership

I found a strange problem while using Core Foundation Array! Here is the code snippet
fname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s"), path, ep->d_name);
CFArrayAppendValue(fileNames, fname);
CFRelease(fname); <---- problem here
cnt = CFArrayGetCount(fileNames);
for (i = 0; i < cnt; i++) {
fname = CFArrayGetValueAtIndex(fileNames, i);
if (fname) {
ptr = (char *)CFStringGetCStringPtr(fname, CFStringGetFastestEncoding(fname));
The code crashes at the last line. Please correct me if I got this wrong. After I created the CFStringRef, I add it to CFArray. As per my understanding the object is now owned by CFArray. Hence I can safely remove the CFStringRef I originally allocated. But when I do CFRelease(fname); the code crashes when I access the array elements in the second part of the code. Can someone explain what is correct way of doing it? If I remove the CFRelease() then everything works fine.
As CFMutableArray Reference says:
The value parameter is retained by theArray using the retain callback
provided when theArray was created. If value is not of the type
expected by the retain callback, the behavior is undefined.
So looks like this is the issue of the fileNames array creation. Probably the third parameter of the CFArrayCreateMutable function. Since CFString is a CFType try to pass kCFTypeArrayCallBacks there.