diff --git a/src/js_realm_object.hpp b/src/js_realm_object.hpp index 78238277..4428ea3d 100644 --- a/src/js_realm_object.hpp +++ b/src/js_realm_object.hpp @@ -106,14 +106,12 @@ typename T::Object RealmObjectClass::create_instance(ContextType ctx, realm:: template void RealmObjectClass::get_property(ContextType ctx, ObjectType object, const String &property, ReturnValue &return_value) { - try { - auto realm_object = get_internal>(object); + auto realm_object = get_internal>(object); + std::string name = property; + if (realm_object->get_object_schema().property_for_name(name)) { NativeAccessor accessor(ctx, realm_object->realm(), realm_object->get_object_schema()); - std::string name = property; auto result = realm_object->template get_property_value(accessor, name); return_value.set(result); - } catch (InvalidPropertyException &ex) { - // getters for nonexistent properties in JS should always return undefined } } diff --git a/src/jsc/jsc_class.hpp b/src/jsc/jsc_class.hpp index 8accc341..abcec8f4 100644 --- a/src/jsc/jsc_class.hpp +++ b/src/jsc/jsc_class.hpp @@ -300,20 +300,43 @@ inline void ObjectWrap::get_property_names(JSContextRef ctx, JSObject } } +static inline bool try_get_int(JSStringRef property, int64_t& value) { + value = 0; + auto str = JSStringGetCharactersPtr(property); + auto end = str + JSStringGetLength(property); + while (str != end && iswspace(*str)) { + ++str; + } + bool negative = false; + if (str != end && *str == '-') { + negative = true; + ++str; + } + while (str != end && *str >= '0' && *str <= '9') { + if (int_multiply_with_overflow_detect(value, 10)) { + return false; + } + value += *str - '0'; + ++str; + } + if (negative) { + value *= -1; + } + return str == end; +} + template inline JSValueRef ObjectWrap::get_property(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { if (auto index_getter = s_class.index_accessor.getter) { - try { - uint32_t index = validated_positive_index(jsc::String(property)); + int64_t num; + if (try_get_int(property, num)) { + uint32_t index; + if (num < 0 || util::int_cast_with_overflow_detect(num, index)) { + // Out-of-bounds index getters should just return undefined in JS. + return Value::from_undefined(ctx); + } return index_getter(ctx, object, index, exception); } - catch (std::out_of_range &) { - // Out-of-bounds index getters should just return undefined in JS. - return Value::from_undefined(ctx); - } - catch (std::invalid_argument &) { - // Property is not a number. - } } if (auto string_getter = s_class.string_accessor.getter) { return string_getter(ctx, object, property, exception); @@ -326,24 +349,24 @@ inline bool ObjectWrap::set_property(JSContextRef ctx, JSObjectRef ob auto index_setter = s_class.index_accessor.setter; if (index_setter || s_class.index_accessor.getter) { - try { - uint32_t index = validated_positive_index(jsc::String(property)); - + int64_t num; + if (try_get_int(property, num)) { + if (num < 0) { + *exception = Exception::value(ctx, util::format("Index %1 cannot be less than zero.", num)); + return false; + } + int32_t index; + if (util::int_cast_with_overflow_detect(num, index)) { + *exception = Exception::value(ctx, util::format("Index %1 cannot be greater than %2.", + num, std::numeric_limits::max())); + return false; + } if (index_setter) { return index_setter(ctx, object, index, value, exception); } - else { - *exception = Exception::value(ctx, std::string("Cannot assign to read only index ") + util::to_string(index)); - return false; - } - } - catch (std::out_of_range &e) { - *exception = Exception::value(ctx, e); + *exception = Exception::value(ctx, util::format("Cannot assign to read only index %1", index)); return false; } - catch (std::invalid_argument &) { - // Property is not a number. - } } if (auto string_setter = s_class.string_accessor.setter) { return string_setter(ctx, object, property, value, exception);