From 6e4a8cb542c8f9cff599fb4ae2f628a613217d13 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Mon, 16 Sep 2024 15:24:01 -0300 Subject: [PATCH] fix: possible race condition extending native class --- NativeScript/runtime/ClassBuilder.cpp | 43 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/NativeScript/runtime/ClassBuilder.cpp b/NativeScript/runtime/ClassBuilder.cpp index a748e27f..e06f2c20 100644 --- a/NativeScript/runtime/ClassBuilder.cpp +++ b/NativeScript/runtime/ClassBuilder.cpp @@ -2,27 +2,34 @@ namespace tns { -// Moved this method in a separate .cpp file because ARC destroys the class created with objc_allocateClassPair -// when the control leaves this method scope +// Moved this method in a separate .cpp file because ARC destroys the class +// created with objc_allocateClassPair when the control leaves this method scope -Class ClassBuilder::GetExtendedClass(std::string baseClassName, std::string staticClassName) { - Class baseClass = objc_getClass(baseClassName.c_str()); - std::string name = !staticClassName.empty() ? staticClassName : baseClassName + "_" + std::to_string(++ClassBuilder::classNameCounter_); - Class clazz = objc_getClass(name.c_str()); +Class ClassBuilder::GetExtendedClass(std::string baseClassName, + std::string staticClassName) { + Class baseClass = objc_getClass(baseClassName.c_str()); + std::string name = + !staticClassName.empty() + ? staticClassName + : baseClassName + "_" + + std::to_string(++ClassBuilder::classNameCounter_); + // here we could either call objc_getClass with the name to see if the class + // already exists or we can just try allocating it, which will return nil if + // the class already exists so we try allocating it every time to avoid race + // conditions in case this method is being executed by multiple threads + Class clazz = objc_allocateClassPair(baseClass, name.c_str(), 0); - if (clazz != nil) { - int i = 1; - std::string initialName = name; - while (clazz != nil) { - name = initialName + std::to_string(i++); - clazz = objc_getClass(name.c_str()); - } + if (clazz != nil) { + int i = 1; + std::string initialName = name; + while (clazz != nil) { + name = initialName + std::to_string(i++); + clazz = objc_allocateClassPair(baseClass, name.c_str(), 0); } + } - clazz = objc_allocateClassPair(baseClass, name.c_str(), 0); - - objc_registerClassPair(clazz); - return clazz; + objc_registerClassPair(clazz); + return clazz; } -} +} // namespace tns