Avoid throwing exceptions in non-error property reads
These make debugging annoying (and probably slow things down, but that's a secondary benefit).
This commit is contained in:
parent
18dea2bc6c
commit
2a28a29341
|
@ -106,14 +106,12 @@ typename T::Object RealmObjectClass<T>::create_instance(ContextType ctx, realm::
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void RealmObjectClass<T>::get_property(ContextType ctx, ObjectType object, const String &property, ReturnValue &return_value) {
|
void RealmObjectClass<T>::get_property(ContextType ctx, ObjectType object, const String &property, ReturnValue &return_value) {
|
||||||
try {
|
auto realm_object = get_internal<T, RealmObjectClass<T>>(object);
|
||||||
auto realm_object = get_internal<T, RealmObjectClass<T>>(object);
|
std::string name = property;
|
||||||
|
if (realm_object->get_object_schema().property_for_name(name)) {
|
||||||
NativeAccessor<T> accessor(ctx, realm_object->realm(), realm_object->get_object_schema());
|
NativeAccessor<T> accessor(ctx, realm_object->realm(), realm_object->get_object_schema());
|
||||||
std::string name = property;
|
|
||||||
auto result = realm_object->template get_property_value<ValueType>(accessor, name);
|
auto result = realm_object->template get_property_value<ValueType>(accessor, name);
|
||||||
return_value.set(result);
|
return_value.set(result);
|
||||||
} catch (InvalidPropertyException &ex) {
|
|
||||||
// getters for nonexistent properties in JS should always return undefined
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -300,20 +300,43 @@ inline void ObjectWrap<ClassType>::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<typename ClassType>
|
template<typename ClassType>
|
||||||
inline JSValueRef ObjectWrap<ClassType>::get_property(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) {
|
inline JSValueRef ObjectWrap<ClassType>::get_property(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) {
|
||||||
if (auto index_getter = s_class.index_accessor.getter) {
|
if (auto index_getter = s_class.index_accessor.getter) {
|
||||||
try {
|
int64_t num;
|
||||||
uint32_t index = validated_positive_index(jsc::String(property));
|
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);
|
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) {
|
if (auto string_getter = s_class.string_accessor.getter) {
|
||||||
return string_getter(ctx, object, property, exception);
|
return string_getter(ctx, object, property, exception);
|
||||||
|
@ -326,24 +349,24 @@ inline bool ObjectWrap<ClassType>::set_property(JSContextRef ctx, JSObjectRef ob
|
||||||
auto index_setter = s_class.index_accessor.setter;
|
auto index_setter = s_class.index_accessor.setter;
|
||||||
|
|
||||||
if (index_setter || s_class.index_accessor.getter) {
|
if (index_setter || s_class.index_accessor.getter) {
|
||||||
try {
|
int64_t num;
|
||||||
uint32_t index = validated_positive_index(jsc::String(property));
|
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<uint32_t>::max()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (index_setter) {
|
if (index_setter) {
|
||||||
return index_setter(ctx, object, index, value, exception);
|
return index_setter(ctx, object, index, value, exception);
|
||||||
}
|
}
|
||||||
else {
|
*exception = Exception::value(ctx, util::format("Cannot assign to read only index %1", index));
|
||||||
*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);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (std::invalid_argument &) {
|
|
||||||
// Property is not a number.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (auto string_setter = s_class.string_accessor.setter) {
|
if (auto string_setter = s_class.string_accessor.setter) {
|
||||||
return string_setter(ctx, object, property, value, exception);
|
return string_setter(ctx, object, property, value, exception);
|
||||||
|
|
Loading…
Reference in New Issue