Merge pull request #4574 from dumganhar/hash_code-fix

closed #3463: Potential hash collision by using typeid(T).hash_code() in JSB and LuaBinding.
This commit is contained in:
James Chen 2013-12-20 01:27:50 -08:00
commit 5751995e2e
9 changed files with 150 additions and 164 deletions

View File

@ -67,7 +67,7 @@ static void serverEntryPoint(void);
js_proxy_t *_native_js_global_ht = NULL;
js_proxy_t *_js_native_global_ht = NULL;
std::unordered_map<long, js_type_class_t*> _js_global_type_map;
std::unordered_map<std::string, js_type_class_t*> _js_global_type_map;
static char *_js_log_buf = NULL;

View File

@ -42,8 +42,8 @@ static JSBool dummy_constructor(JSContext *cx, uint32_t argc, jsval *vp) {
T* cobj = new T();
cobj->autorelease();
js_type_class_t *p;
long typeId = t.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
p = typeMapIter->second;
@ -184,8 +184,8 @@ JSBool JSB_CCPhysicsDebugNode_debugNodeForCPSpace__static(JSContext *cx, uint32_
if (ret) {
TypeTest<PhysicsDebugNode> t;
js_type_class_t *typeClass = nullptr;
long typeId = t.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
@ -274,8 +274,8 @@ void JSB_CCPhysicsDebugNode_createClass(JSContext *cx, JSObject* globalObj, cons
TypeTest<cocos2d::DrawNode> t1;
js_type_class_t *typeClass = nullptr;
long typeId = t1.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
std::string typeName = t1.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
@ -285,15 +285,15 @@ void JSB_CCPhysicsDebugNode_createClass(JSContext *cx, JSObject* globalObj, cons
TypeTest<PhysicsDebugNode> t;
js_type_class_t *p;
typeId = t.s_id();
typeName = t.s_name();
if (_js_global_type_map.find(typeId) == _js_global_type_map.end())
if (_js_global_type_map.find(typeName) == _js_global_type_map.end())
{
p = (js_type_class_t *)malloc(sizeof(js_type_class_t));
p->jsclass = JSB_CCPhysicsDebugNode_class;
p->proto = JSB_CCPhysicsDebugNode_object;
p->parentProto = typeClass->proto;
_js_global_type_map.insert(std::make_pair(typeId, p));
_js_global_type_map.insert(std::make_pair(typeName, p));
}
}
@ -317,8 +317,8 @@ JSBool JSPROXY_CCPhysicsSprite_spriteWithFile_rect__static(JSContext *cx, uint32
if (ret) {
TypeTest<PhysicsSprite> t;
js_type_class_t *typeClass = nullptr;
long typeId = t.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
@ -346,8 +346,8 @@ JSBool JSPROXY_CCPhysicsSprite_spriteWithFile_rect__static(JSContext *cx, uint32
if (ret) {
TypeTest<PhysicsSprite> t;
js_type_class_t *typeClass = nullptr;
long typeId = t.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
@ -387,8 +387,8 @@ JSBool JSPROXY_CCPhysicsSprite_spriteWithSpriteFrame__static(JSContext *cx, uint
if (ret) {
TypeTest<PhysicsSprite> t;
js_type_class_t *typeClass = nullptr;
long typeId = t.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
@ -421,8 +421,8 @@ JSBool JSPROXY_CCPhysicsSprite_spriteWithSpriteFrameName__static(JSContext *cx,
if (ret) {
TypeTest<PhysicsSprite> t;
js_type_class_t *typeClass = nullptr;
long typeId = t.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
@ -475,8 +475,8 @@ void JSPROXY_CCPhysicsSprite_createClass(JSContext *cx, JSObject* globalObj)
TypeTest<cocos2d::Sprite> t1;
js_type_class_t *typeClass = nullptr;
long typeId = t1.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
std::string typeName = t1.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
@ -485,14 +485,14 @@ void JSPROXY_CCPhysicsSprite_createClass(JSContext *cx, JSObject* globalObj)
TypeTest<PhysicsSprite> t;
js_type_class_t *p;
typeId = t.s_id();
if (_js_global_type_map.find(typeId) == _js_global_type_map.end())
typeName = t.s_name();
if (_js_global_type_map.find(typeName) == _js_global_type_map.end())
{
p = (js_type_class_t *)malloc(sizeof(js_type_class_t));
p->jsclass = JSPROXY_CCPhysicsSprite_class;
p->proto = JSPROXY_CCPhysicsSprite_object;
p->parentProto = typeClass->proto;
_js_global_type_map.insert(std::make_pair(typeId, p));
_js_global_type_map.insert(std::make_pair(typeName, p));
}
}

View File

@ -40,12 +40,12 @@ extern callfuncTarget_proxy_t *_callfuncTarget_native_ht;
template <class T>
inline js_type_class_t *js_get_type_from_native(T* native_obj) {
bool found = false;
long typeId = typeid(*native_obj).hash_code();
auto typeProxyIter = _js_global_type_map.find(typeId);
std::string typeName = typeid(*native_obj).name();
auto typeProxyIter = _js_global_type_map.find(typeName);
if (typeProxyIter == _js_global_type_map.end())
{
typeId = typeid(T).hash_code();
typeProxyIter = _js_global_type_map.find(typeId);
typeName = typeid(T).name();
typeProxyIter = _js_global_type_map.find(typeName);
if (typeProxyIter != _js_global_type_map.end())
{
found = true;

View File

@ -1,26 +1,26 @@
#include "js_bindings_opengl.h"
void GLNode::draw() {
js_proxy_t* proxy = NULL;
JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
proxy = js_get_or_create_proxy<cocos2d::Node>(cx, this);
if( proxy ) {
JSObject *jsObj = proxy->obj;
if (jsObj) {
JSBool found;
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
JS_HasProperty(cx, jsObj, "draw", &found);
if (found == JS_TRUE) {
JS::RootedValue rval(cx);
JS::RootedValue fval(cx);
jsval *argv = NULL; unsigned argc=0;
JS_GetProperty(cx, jsObj, "draw", &fval);
JS_CallFunctionValue(cx, jsObj, fval, argc, argv, rval.address());
}
js_proxy_t* proxy = NULL;
JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
proxy = js_get_or_create_proxy<cocos2d::Node>(cx, this);
if( proxy ) {
JSObject *jsObj = proxy->obj;
if (jsObj) {
JSBool found;
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
JS_HasProperty(cx, jsObj, "draw", &found);
if (found == JS_TRUE) {
JS::RootedValue rval(cx);
JS::RootedValue fval(cx);
jsval *argv = NULL; unsigned argc=0;
JS_GetProperty(cx, jsObj, "draw", &fval);
JS_CallFunctionValue(cx, jsObj, fval, argc, argv, rval.address());
}
}
}
}
}
@ -29,34 +29,34 @@ JSObject *js_cocos2dx_GLNode_prototype;
JSBool js_cocos2dx_GLNode_constructor(JSContext *cx, uint32_t argc, jsval *vp)
{
if (argc == 0) {
GLNode* cobj = new GLNode();
cocos2d::Object *_ccobj = dynamic_cast<cocos2d::Object *>(cobj);
if (_ccobj) {
_ccobj->autorelease();
if (argc == 0) {
GLNode* cobj = new GLNode();
cocos2d::Object *_ccobj = dynamic_cast<cocos2d::Object *>(cobj);
if (_ccobj) {
_ccobj->autorelease();
}
TypeTest<GLNode> t;
js_type_class_t *typeClass = nullptr;
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
JSObject *obj = JS_NewObject(cx, typeClass->jsclass, typeClass->proto, typeClass->parentProto);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
// link the native object with the javascript object
js_proxy_t *p = jsb_new_proxy(cobj, obj);
JS_AddNamedObjectRoot(cx, &p->obj, "cocos2d::GLNode");
return JS_TRUE;
}
TypeTest<GLNode> t;
js_type_class_t *typeClass = nullptr;
long typeId = t.s_id();
auto typeMapIter = _js_global_type_map.find(typeId);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
JSObject *obj = JS_NewObject(cx, typeClass->jsclass, typeClass->proto, typeClass->parentProto);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
// link the native object with the javascript object
js_proxy_t *p = jsb_new_proxy(cobj, obj);
JS_AddNamedObjectRoot(cx, &p->obj, "cocos2d::GLNode");
return JS_TRUE;
}
JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0);
return JS_FALSE;
JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0);
return JS_FALSE;
}
void js_cocos2dx_GLNode_finalize(JSFreeOp *fop, JSObject *obj) {
@ -64,7 +64,7 @@ void js_cocos2dx_GLNode_finalize(JSFreeOp *fop, JSObject *obj) {
static JSBool js_cocos2dx_GLNode_ctor(JSContext *cx, uint32_t argc, jsval *vp)
{
JSObject *obj = JS_THIS_OBJECT(cx, vp);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
GLNode *nobj = new GLNode();
js_proxy_t* p = jsb_new_proxy(nobj, obj);
nobj->autorelease();
@ -75,72 +75,72 @@ static JSBool js_cocos2dx_GLNode_ctor(JSContext *cx, uint32_t argc, jsval *vp)
JSBool js_cocos2dx_GLNode_create(JSContext *cx, uint32_t argc, jsval *vp)
{
GLNode* ret = new GLNode();
jsval jsret;
do {
if (ret) {
js_proxy_t *proxy = js_get_or_create_proxy<GLNode>(cx, ret);
jsret = OBJECT_TO_JSVAL(proxy->obj);
} else {
jsret = JSVAL_NULL;
}
} while (0);
JS_SET_RVAL(cx, vp, jsret);
return JS_TRUE;
GLNode* ret = new GLNode();
jsval jsret;
do {
if (ret) {
js_proxy_t *proxy = js_get_or_create_proxy<GLNode>(cx, ret);
jsret = OBJECT_TO_JSVAL(proxy->obj);
} else {
jsret = JSVAL_NULL;
}
} while (0);
JS_SET_RVAL(cx, vp, jsret);
return JS_TRUE;
}
extern JSObject* jsb_Node_prototype;
void js_register_cocos2dx_GLNode(JSContext *cx, JSObject *global) {
js_cocos2dx_GLNode_class = (JSClass *)calloc(1, sizeof(JSClass));
js_cocos2dx_GLNode_class->name = "GLNode";
js_cocos2dx_GLNode_class->addProperty = JS_PropertyStub;
js_cocos2dx_GLNode_class->delProperty = JS_DeletePropertyStub;
js_cocos2dx_GLNode_class->getProperty = JS_PropertyStub;
js_cocos2dx_GLNode_class->setProperty = JS_StrictPropertyStub;
js_cocos2dx_GLNode_class->enumerate = JS_EnumerateStub;
js_cocos2dx_GLNode_class->resolve = JS_ResolveStub;
js_cocos2dx_GLNode_class->convert = JS_ConvertStub;
js_cocos2dx_GLNode_class->finalize = js_cocos2dx_GLNode_finalize;
js_cocos2dx_GLNode_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
static JSPropertySpec properties[] = {
{0, 0, 0, 0, 0}
};
static JSFunctionSpec funcs[] = {
JS_FN("ctor", js_cocos2dx_GLNode_ctor, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
static JSFunctionSpec st_funcs[] = {
JS_FN("create", js_cocos2dx_GLNode_create, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
js_cocos2dx_GLNode_prototype = JS_InitClass(
cx, global,
jsb_Node_prototype,
js_cocos2dx_GLNode_class,
js_cocos2dx_GLNode_constructor, 0, // constructor
properties,
funcs,
NULL, // no static properties
st_funcs);
// make the class enumerable in the registered namespace
JSBool found;
JS_SetPropertyAttributes(cx, global, "GLNode", JSPROP_ENUMERATE | JSPROP_READONLY, &found);
// add the proto and JSClass to the type->js info hash table
TypeTest<GLNode> t;
js_type_class_t *p;
long typeId = t.s_id();
if (_js_global_type_map.find(typeId) == _js_global_type_map.end())
{
p = (js_type_class_t *)malloc(sizeof(js_type_class_t));
p->jsclass = js_cocos2dx_GLNode_class;
p->proto = js_cocos2dx_GLNode_prototype;
p->parentProto = jsb_Node_prototype;
_js_global_type_map.insert(std::make_pair(typeId, p));
}
js_cocos2dx_GLNode_class = (JSClass *)calloc(1, sizeof(JSClass));
js_cocos2dx_GLNode_class->name = "GLNode";
js_cocos2dx_GLNode_class->addProperty = JS_PropertyStub;
js_cocos2dx_GLNode_class->delProperty = JS_DeletePropertyStub;
js_cocos2dx_GLNode_class->getProperty = JS_PropertyStub;
js_cocos2dx_GLNode_class->setProperty = JS_StrictPropertyStub;
js_cocos2dx_GLNode_class->enumerate = JS_EnumerateStub;
js_cocos2dx_GLNode_class->resolve = JS_ResolveStub;
js_cocos2dx_GLNode_class->convert = JS_ConvertStub;
js_cocos2dx_GLNode_class->finalize = js_cocos2dx_GLNode_finalize;
js_cocos2dx_GLNode_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
static JSPropertySpec properties[] = {
{0, 0, 0, 0, 0}
};
static JSFunctionSpec funcs[] = {
JS_FN("ctor", js_cocos2dx_GLNode_ctor, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
static JSFunctionSpec st_funcs[] = {
JS_FN("create", js_cocos2dx_GLNode_create, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
js_cocos2dx_GLNode_prototype = JS_InitClass(
cx, global,
jsb_Node_prototype,
js_cocos2dx_GLNode_class,
js_cocos2dx_GLNode_constructor, 0, // constructor
properties,
funcs,
NULL, // no static properties
st_funcs);
// make the class enumerable in the registered namespace
JSBool found;
JS_SetPropertyAttributes(cx, global, "GLNode", JSPROP_ENUMERATE | JSPROP_READONLY, &found);
// add the proto and JSClass to the type->js info hash table
TypeTest<GLNode> t;
js_type_class_t *p;
std::string typeName = t.s_name();
if (_js_global_type_map.find(typeName) == _js_global_type_map.end())
{
p = (js_type_class_t *)malloc(sizeof(js_type_class_t));
p->jsclass = js_cocos2dx_GLNode_class;
p->proto = js_cocos2dx_GLNode_prototype;
p->parentProto = jsb_Node_prototype;
_js_global_type_map.insert(std::make_pair(typeName, p));
}
}

View File

@ -20,26 +20,12 @@ typedef struct js_type_class {
JSObject *parentProto;
} js_type_class_t;
extern std::unordered_map<long, js_type_class_t*> _js_global_type_map;
extern std::unordered_map<std::string, js_type_class_t*> _js_global_type_map;
template< typename DERIVED >
class TypeTest
{
public:
static long s_id()
{
// return id unique for DERIVED
// NOT SURE IT WILL BE REALLY UNIQUE FOR EACH CLASS!!
/* Commented by James Chen
Using 'getHashCodeByString(typeid(*native_obj).name())' instead of 'reinterpret_cast<long>(typeid(*native_obj).name());'.
Since on win32 platform, 'reinterpret_cast<long>(typeid(*native_obj).name());' invoking in cocos2d.dll and outside cocos2d.dll(in TestJavascript.exe) will return different address.
But the return string from typeid(*native_obj).name() is the same string, so we must convert the string to hash id to make sure we can get unique id.
*/
// static const long id = reinterpret_cast<long>(typeid( DERIVED ).name());
static const long id = typeid( DERIVED ).hash_code();
return id;
}
public:
static const char* s_name()
{
// return id unique for DERIVED

View File

@ -32,7 +32,7 @@ extern "C" {
}
#endif
std::map<long, std::string> g_luaType;
std::unordered_map<std::string, std::string> g_luaType;
#if COCOS2D_DEBUG >=1
void luaval_to_native_err(lua_State* L,const char* msg,tolua_Error* err)
@ -1640,8 +1640,8 @@ void array_to_luaval(lua_State* L,Array* inValue)
if (nullptr == obj)
continue;
long typeId = typeid(*obj).hash_code();
auto iter = g_luaType.find(typeId);
std::string typeName = typeid(*obj).name();
auto iter = g_luaType.find(typeName);
if (g_luaType.end() != iter)
{
className = iter->second;
@ -1729,9 +1729,9 @@ void dictionary_to_luaval(lua_State* L, Dictionary* dict)
if (NULL == element)
continue;
long typeId = typeid(element->getObject()).hash_code();
std::string typeName = typeid(element->getObject()).name();
auto iter = g_luaType.find(typeId);
auto iter = g_luaType.find(typeName);
if (g_luaType.end() != iter)
{
className = iter->second;

View File

@ -11,7 +11,7 @@ extern "C" {
using namespace cocos2d;
extern std::map<long, std::string> g_luaType;
extern std::unordered_map<std::string, std::string> g_luaType;
#if COCOS2D_DEBUG >=1
void luaval_to_native_err(lua_State* L,const char* msg,tolua_Error* err);
@ -160,8 +160,8 @@ void ccvector_to_luaval(lua_State* L,const cocos2d::Vector<T>& inValue)
if (nullptr != dynamic_cast<cocos2d::Object *>(obj))
{
long typeId = typeid(*obj).hash_code();
auto iter = g_luaType.find(typeId);
std::string typeName = typeid(*obj).name();
auto iter = g_luaType.find(typeName);
if (g_luaType.end() != iter)
{
lua_pushnumber(L, (lua_Number)indexTable);

View File

@ -694,8 +694,8 @@ int register_cocos2dx_extension_CCBProxy(lua_State* tolua_S)
tolua_endmodule(tolua_S);
tolua_endmodule(tolua_S);
long typeId = typeid(CCBProxy).hash_code();
g_luaType[typeId] = "CCBProxy";
std::string typeName = typeid(CCBProxy).name();
g_luaType[typeName] = "CCBProxy";
return 1;
}

@ -1 +1 @@
Subproject commit f0b6cc8dd3d375f0999ec4e49dd90dbe1938c460
Subproject commit ad532012457e2eaff15d73d9ba28a638fa748d2d