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.
glessard
(Guillaume Lessard)
2
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.
3 Likes
tera
3
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.
2 Likes
eskimo
(Quinn “The Eskimo!”)
4
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
3 Likes
tera
5
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".
1 Like
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?