回到sel_getUid()的原始行为

use*_*367 5 objective-c objective-c-runtime selector

TL; DR:如何检查具有给定名称的选择器是否已注册,而不实际注册?

谢谢!


嗨,我有一个Objective-C应用程序和一堆NSObject,通过用objc编写的简单代理库导出到Lua状态.所有Lua方面的电话都是这样的:

exported_objc_object:myMethodName(...)

-- same as --
exported_objc_object.myMethodName(exported_objc_object, ...)

-- same as --
key = 'myMethodName'
exported_objc_object[key](exported_objc_object, ...)
Run Code Online (Sandbox Code Playgroud)

转发好像有人打电话:

[objc_object lua_myMethodName:L];

// declared as
- (int)lua_myMethodName:(lua_State *)L { ... }
Run Code Online (Sandbox Code Playgroud)

实际上,Lua导出对象上的任何"get"操作码都会返回一个缓存的Lua闭包,在调用时会通过使用sprintf(s, "lua_%s:", key))&& sel_getUid(s)(包括所有检查)构造的选择器调用相应的Objective-C方法.如果生成的选择器没有实现-[respondsToSelector:],那么exported_objc_object.myMethodName只需返回nil.

显然,代理库必须通过sel_getUid()sel_registerName()(我相信两者@selectorNSSelectorFromString()最终在那里)进行动态查找.手册说明了sel_getUid()用于查找选择器名称(而不是立即将它们注册到SEL注册表中),但它的现代实现现在与sel_registerName()由于当时某人的代码中的错误相同.

我可以坚持sel_registerName()行为,但这留下了内存吃攻击向量,因为一些恶意脚本可能会开始通过object[makeRandomKey()]循环中的sml查找长的随机/无效选择器,从而永远溢出SEL注册表.如果sel_getUid()按计划工作,代理lib将能够测试选择器的存在,然后实际检查对象是否响应它,而无需过多注册.但事实并非如此.

new*_*cct 4

这是一个可能有效的 hack,它使用了依赖于实现的事实,即选择器是一个 C 字符串。

sel_isMapped((SEL)(void *)"lua_myMethodName:")
Run Code Online (Sandbox Code Playgroud)