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, ...)
转发,好像有人打电话:
[objc_object lua_myMethodName:L];
// declared as
- (int)lua_myMethodName:(lua_State *)L { ... }
实际上,Lua导出对象上的任何“get”操作码都会返回一个缓存的Lua闭包,在调用时,它将通过由sprintf(s, "lua_%s:", key))
&&组成的选择器调用相应的Objective-C方法。 sel_getUid(s)
(包括所有检查)。如果生成的选择器未按-[respondsToSelector:]
实施,则exported_objc_object.myMethodName
只会返回nil
。
显然,代理库必须通过sel_getUid()
或sel_registerName()
进行动态查询(我相信@selector
和NSSelectorFromString()
也会在那里结束)。该手册指出sel_getUid()
旨在查找选择器名称(而不是立即将它们注册到SEL注册表中),但它的现代实现现在与sel_registerName()
相同,因为当时某人的代码中存在错误
我可以坚持使用sel_registerName()
行为,但这留下了内存食用攻击向量,因为某些恶意脚本可能会在循环中通过sml object[makeRandomKey()]
开始查找长的随机/无效选择器,从而溢出SEL注册表永远。如果sel_getUid()
按计划工作,则代理lib将能够测试选择器的存在,然后实际检查对象是否响应它,而无需过多注册。但事实并非如此。
答案 0 :(得分:4)
这是一个可行的hack,它使用依赖于实现的事实,即选择器是C字符串。
sel_isMapped((SEL)(void *)"lua_myMethodName:")