-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create blocks with BLOCK_HAS_SIGNATURE #442
Comments
Parts of the code for generating the encodings in a But we can definitely add a way to do it in an Do you have an example of a few APIs that fail, so that I can add them to the test suite when implementing the feature? |
The ones I know of are |
Thanks for the examples, I haven't worked with I probably won't have the time to implement a function for creating blocks with encodings at the moment (I'm out of the country, and my focus lies elsewhere), but I will happily review and accept a PR that does it (and I could mentor an implementer as well). |
I seem to have hit this limitation as well. The concerned framework is The process crashes on the uncaught exception Details
in which:
This is a case where it is needed to give a new block to the framework and Obj-C runtime instead of simply receiving one from it and calling it, for which there is no problem. Interestingly however, not all such cases end up triggering an error: both It would therefore be nice to have an easy way to make this work out of the box. In the meantime, I'll try the workaround mentioned in #434 (comment) or #615 (comment) or something like that. |
Actually, it really seems to be rather linked to the Thinking a bit out loud how to solve this: @madsmtm, do you think it would be possible to expose a possibly- Regarding what is mentioned in #70 (comment), I find the macro version to be an acceptable backup solution while waiting for the desired Rust features. At the very least and if I understand things correctly, it would make it an optional requirement of Another possibility would be to generate the C string at runtime and store it in the Yet another possibility would be to use some kind of proc-macro, for example a derive one that would automatically implement an additional trait for the type that only carries the wanted constant and that would be a subtrait of |
Yeah, me neither. A guess is that the
No, that shouldn't have an effect, those contents are fully transparent to Objective-C.
Indeed.
I'd be fine with that - sorry for not responding sooner, I guess I kinda wanted to respond with a PR doing exactly this, but just never got around to doing so. I will review and accept a PR if you want to attempt doing it, though? I think what I'd prefer would be something like the following, on both pub unsafe fn with_encoding<Closure>(encoding: &'static CStr, closure: Closure) -> Self
where
// ... Same as the existing `new` methods
{
#[cfg(debug_assertions)]
{
// Somehow help ensure that the encoding is correct. Not important, but nice to have.
A::ENCODINGS;
R::ENCODING_RETURN;
}
// ... implementation
}
// Usage
let block = RcBlock::with_encoding(c"i12@?0i8", |arg: i32| {
arg + 2
}); There's a bit more to this, especially given that the block encoding seems to include some numbers, perhaps similar to the encoding for methods? Should be documented in the method, so that users are empowered to write the correct encoding.
I'm pretty sure that we still wouldn't be able to do what I wanted in that PR (automatic If I remember correctly, the basic limitation in const fn compute_static_str_len(encoding: &Encoding) -> usize { todo!() }
fn new<R: EncodeReturn>() {
// Create a temporary array to store the static encoding in
let arr: [0u8; compute_static_str_len(&R::ENCODING_RETURN)] = [0u8; compute_static_str_len(&R::ENCODING_RETURN)];
// Use array
} Which doesn't work currently. But maybe there are ways around this that I don't know about?
Yeah, there might be ways to do this by storing the string and the descriptor in the block itself (though it'd probably have to store A bigger problem that I see with this would be regards to the correctness: It's been a while since I combed the spec, but I don't think the lifetime of the descriptor is explicitly noted anywhere in there? So it's a possibility that there is Objective-C code out there that relies on the descriptor or the encoding being
True, though overkill IMO. |
Hey, thanks for the answer!
I don't exactly need it anymore as it seems that the default settings fit my requirements just fine, but it did limit me in my ability to experiment and having this part of the API available to me would help me investigate and understand some more things in order to get more confidence about what I'm doing. I might therefore open such a PR this week, as it shouldn't be too complicated.
Yes, I can indeed reproduce separately: the trait EncodeReturn {
const ENCODING_RETURN: Encoding;
fn init_arr() -> &'static [u8];
}
impl Encoding {
// The aforementioned `compute_static_str_len`.
const fn str_len(&self) -> usize {
todo!()
}
}
struct X;
impl EncodeReturn for X {
const ENCODING_RETURN: Encoding = todo!();
// Always the same for everyone:
fn init_arr() -> &'static [u8] {
&[0; Self::ENCODING_RETURN.str_len()]
}
}
fn new<R: EncodeReturn>() {
let arr = R::init_arr();
// Use array
} in which |
I would really like to avoid having to change the I have posted an alternative in #636 (comment), let's discuss it there. |
I looked into how it's implemented for FileProvider (have not yet looked at NetworkExtension, the setup for testing it is kinda bothersome): It seems like it's implemented by passing the block's encoding to /* @class NSInvocation(FPExtensions) */
-(void)fp_zeroOutReplyBlockArgumentsWithError:(NSError*)error {
NSMethodSignature* signature = [self methodSignature];
NSUInteger numArgs = [signature numberOfArguments];
NSUInteger frameLen = [signature frameLength];
void* zerovalue = stack - (frameLen + 0xf & 0xfffffffffffffff0); // No idea what this is
bzero(zerovalue, frameLen);
if (numArgs >= 2) {
for (int i = 1; i < numArgs; i++) {
[self setArgument:zerovalue atIndex:i];
}
}
NSUInteger i = [signature fp_indexOfLastArgumentWithType:"@\"NSError\""];
if (i != 0x7fffffffffffffff) {
[self setArgument:error atIndex:i];
}
} Not entirely sure what's going on, but I think my suspicion is correct, that they do this for backwards compatibility. From this, I also see a few major points:
|
Nice work @PaulDance and @madsmtm! |
objc2/crates/block2/src/concrete_block.rs
Line 189 in dd6c804
Some newer Apple APIs appear to fail in unexpected ways when called with blocks that don't have signatures. It would be useful to at least have some way of manually specifying a signature, though unsafe. Generating it automatically would be even better of course, though it's an interesting question how to actually do so.
The text was updated successfully, but these errors were encountered: