Is it possible for the automatic String
to UnsafePointer<CChar>
conversion to clobber errno
when calling functions imported from C modules? Is it dependent on whether the String
is native UTF8 or bridged UTF16?
Thanks.
Is it possible for the automatic String
to UnsafePointer<CChar>
conversion to clobber errno
when calling functions imported from C modules? Is it dependent on whether the String
is native UTF8 or bridged UTF16?
Thanks.
I think it's possible that in some cases it could happen (e.g. materializing a utf8 c-string from a utf16 NSString.) If you need access to your errno
after the call to the C function, I would recommend using the String.withUTF8
closure-taking function, and check errno
within the closure.
I would not rule it out (e.g. it could be reset in malloc/free done internally), and if that's happening in your case you may fix the issue at the C side – make a wrapper that converts errno
to something better like the return value:
int foo(const char* param) { ... } // errno is set appropriately after the call
int fooWrapper(const char* param) {
foo(param);
return errno;
}
If obj-c is tolerable you may even make the call returning error in the standard obj-c way (it will look throwing when used from swift):
// typing in a web window so could contain typos
@implementation SomeClass
...
-(BOOL)fooWrapper:(NSString*)param error:(NSError**)error {
int result = foo(param.UTF8String);
if (result != 0) { // or whatever the check should be here
*error = [NSError errorWithDomain: @"yourDomain" code:errno userInfo: nil];
return false;
}
return true;
}
...
@end
Edit: corrected the obj-c code above: the obj-c NSError to swift throw conversion works only with obj-c methods, not with standalone functions.
On the Objective-C side, I write it this way:
int result = foo(…);
if ((result < 0) && (error != NULL)) { here
int err = errno;
*error = [NSError errorWithDomain: @"yourDomain" code:err userInfo: nil];
return false;
}
This involves three changes:
I default to a < 0
test because Unix APIs are weird! But, as you said, this will vary based on the specific API you’re calling.
You have to check for error
being NULL
because Objective-C clients might not care about the exact error.
Sample errno
before you start constructing the NSError
, because C-based languages can evaluate parameters in any order and it’s possible that evaluating one of the other parameters might clobber errno
.
Share and Enjoy
Quinn “The Eskimo!” @ DTS @ Apple
Yep. I'd modify your version a little bit further to return false/NO in case of error even if nil is passed in the error parameter.
You are right, that totally escaped me.
BTW, malloc only sets errno on error:
errno = 123
malloc(1) // ok
print(errno) // 123
print(errno) // still 123 (errno is not changed so far)
malloc(-1) // fail
print(errno) // 12
This is in accordance with the docs: "If there is an error, they return a NULL pointer and set errno to ENOMEM".
Thanks for your advice!
Also, what about inout T
to UnsafeMutablePointer<T>
conversion? Is it possible for this to clobber errno
, specifically when T
is a POD type?
No.