Objective-C ARC和longjmp [英] Objective-C ARC and longjmp

查看:114
本文介绍了Objective-C ARC和longjmp的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将Objective-C ARC与longjmp混合的最佳实践是什么?

我使用Lua作为脚本语言,并且我的平台导出脚本的自定义库.入口点确实使用luaL_checkinteger(L, 2)(以及其他)来检查参数,而这些参数又可以调用luaL_typerror(L, 2, ...),这是在Lua中使用setjmp/longjmp实现的.据我所知,ARC只是自动生成retain/release代码,但是如果longjmp超出范围会发生什么呢?这段代码会在类型错误的参数上泄漏吗?

static int
set_tag(lua_State *L)
{
    NSControl *control = (__bridge NSControl *)lua_topointer(L, 1);
    [control setTag:(NSInteger)luaL_checkinteger(L, 2)]; // may longjmp!
    return 0;
}

在上面的代码段中,control将由ARC临时保留,但是由于longjmp具有不可捕获的性质,因此可能永远不会发生相应的释放调用.另一方面,所有参数可以在 分配给control变量之前进行检查.

static int
set_tag(lua_State *L)
{
    NSInteger tag = luaL_checkinteger(L, 2); // may longjmp!
    NSControl *control = (__bridge NSControl *)lua_topointer(L, 1);
    [control setTag:tag];
    return 0;
}

它可以解决上面的[潜在]泄漏吗?有更好的方法可以做到这一点吗?

更新:longjmp仅展开到Lua内部,并且从不交叉任何系统代码,除了Lua源代码(知道)和我的入口点(我希望知道)之外.

我很确定第二个片段的确正确,但是我需要某种形式上的证明.


最新更新:

LuaJIT实现了dwarf2兼容的错误,因此它们就像C ++异常一样.使用Lua代码将-fobjc-arc-exceptions编译器标志传递给启用了arc的源,任何保留的对象都将在任何lua_error上释放.现在不用担心!不过,仍然不允许您在Cocoa运行时中引发错误.

我记得原来的Lua可能也有例外,但我不确定.

解决方案

是否使用ARC并不重要;跳过系统框架中任何代码框架的任何setjmp/longjmp都将产生未定义的行为(出于同样的原因,不能将异常用于可恢复的错误处理).

所以,是的,该代码可能泄漏了. 可能,因为这取决于编译器在该块中以及在何处发出retain/release. 可能也是因为编译器是否发出retain/release会受到优化级别以及编译器版本的影响.

longjmp仅展开至Lua内部,从不跨越任何系统 代码,除了Lua源(知道)和我的入口点 (我希望知道).

那很有帮助.只要您对入口点进行结构化,以使它们从不与Lua可跳转范围相互混合,那么您应该就可以了.我建议关闭必须在其中进行管理的源文件中的ARC(当然,还要将ObjC-> Lua接口放入经过很好封装的实现中,以便其余代码可以进行ARC清理).

不过,请考虑存在非显而易见的风险:

for(id x in anArray) {
    ... lua call that causes longjmp ...
}

以上内容将导致lua跳过"系统代码. enumerateWithBlock:,KVO,通知处理程序等也是如此...

您将不得不非常仔细地思考由Lua调用您的代码而引起的每个潜在堆栈触发事件.如果该调用触发了系统部分上任何可以触发Lua API并可能触发longjmp的自动化行为,则所有选择都将关闭.

What is the best practice for mixing Objective-C ARC with longjmp?

I am using Lua as scripting language, and my platform exports custom library for scripts. Entry points do check arguments with luaL_checkinteger(L, 2) (among others), which, in turn, may call luaL_typerror(L, 2, ...), that is implemented in Lua with setjmp/longjmp. As far as I know, ARC simply auto-generates retain/release code, but what happens if it longjmps out of scope? Will this code leak on mistyped arguments?

static int
set_tag(lua_State *L)
{
    NSControl *control = (__bridge NSControl *)lua_topointer(L, 1);
    [control setTag:(NSInteger)luaL_checkinteger(L, 2)]; // may longjmp!
    return 0;
}

In the snippet above, control will be temporarily retained by ARC, but with longjmps uncatchable nature, corresponding release call may never happen. On the other hand, all arguments may be checked before assigning to control variable.

static int
set_tag(lua_State *L)
{
    NSInteger tag = luaL_checkinteger(L, 2); // may longjmp!
    NSControl *control = (__bridge NSControl *)lua_topointer(L, 1);
    [control setTag:tag];
    return 0;
}

Does it resolve [potential] leak above? Are there better ways to do this?

UPDATE: longjmp only unwinds to Lua internals, and never crosses any system code, except for Lua source (which is aware), and my entry points (which I hope are aware).

I'm pretty sure that second snippet does right, but I need kind of formal proof.


LATE UPDATE:

LuaJIT implements dwarf2-compatible errors, so they are just like C++ exceptions. Pass -fobjc-arc-exceptions compiler flag to arc-enabled sources with Lua code and any retained object will be released on any lua_error. Nothing to worry about now! You are still not allowed to throw errors across Cocoa runtime, though.

I recall that original Lua may be compiled with exceptions too, but I'm not sure.

解决方案

Doesn't really matter if ARC is in use or not; any setjmp/longjmp that jumps over any frame of code from the system frameworks will yield undefined behavior (for the same reason that exceptions cannot be used for recoverable error handling).

So, yes, that code might leak. Might because it depends on whether the compiler emits a retain/release in that block and where. Might also because whether the compiler emits retain/release will be impacted by the optimization level and, over time, the version of the compiler.

longjmp only unwinds to Lua internals, and never crosses any system code, except for Lua source (which is aware), and my entry points (which I hope are aware).

That is helpful. As long as you structure your entry points such that they never intermingle system scope with Lua jumpable scopes, you should be OK. I would recommend turning off ARC in the source files where you have to manage this (and, of course, put the ObjC->Lua interface into a nicely encapsulated bit of implementation so the rest of your code can be ARC clean).

Consider, though, that there is non-obvious risk:

for(id x in anArray) {
    ... lua call that causes longjmp ...
}

The above would cause lua to "jump over" system code. Same goes for enumerateWithBlock:, KVO, Notification handlers, etc...

You're going to have to think very very carefully about every potential stack trigger by a call from Lua into your code. If that call triggers any kind of automated behavior on the part of the system that could then call Lua API that could trigger a longjmp, all bets are off.

这篇关于Objective-C ARC和longjmp的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆