mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
fix: 修复 oxide_builtins 整数溢出 panic 点与安全转换
This commit is contained in:
@@ -63,7 +63,12 @@ pub(crate) fn get_instant_epoch_ns(obj: &JsObject) -> Option<i128> {
|
||||
return Some(unsafe { oxide_runtime_api::bigint_data(value) }.to_i128().unwrap_or(i128::MAX));
|
||||
}
|
||||
if value.is_int() || value.is_double() {
|
||||
return Some(to_number(value) as i128);
|
||||
let n = to_number(value);
|
||||
// f64 转 i128:超大值饱和到 i128 边界。
|
||||
if n.is_finite() && n >= i128::MIN as f64 && n <= i128::MAX as f64 {
|
||||
return Some(n as i128);
|
||||
}
|
||||
return Some(i128::MAX);
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -403,9 +408,28 @@ pub(crate) fn plain_date_time_object_parts<H: VmHost>(
|
||||
values[8] = values[8].clamp(0.0, 999.0);
|
||||
}
|
||||
let [year, month, day, hour, minute, second, millisecond, microsecond, nanosecond] = values;
|
||||
let (year, month, day) = (year as i32, month as u32, day as u32);
|
||||
let (hour, minute, second) = (hour as u32, minute as u32, second as u32);
|
||||
let (millisecond, microsecond, nanosecond) = (millisecond as u32, microsecond as u32, nanosecond as u32);
|
||||
// 分量值可能超出目标整型范围(f64 截断后仍超 i32/u32 上限),先做有界转换。
|
||||
// 超出范围后 valid_iso_date / valid_plain_time 会拒绝,此处兜住 debug 模式 panic。
|
||||
let year = if year.is_finite() && year >= i32::MIN as f64 && year <= i32::MAX as f64 {
|
||||
year as i32
|
||||
} else {
|
||||
return Err(crate::error::create_range_error(vm, "invalid date-time component"));
|
||||
};
|
||||
let mut to_u32 = |v: f64| -> Result<u32, JsValue> {
|
||||
if v.is_finite() && v >= 0.0 && v <= u32::MAX as f64 {
|
||||
Ok(v as u32)
|
||||
} else {
|
||||
Err(crate::error::create_range_error(vm, "invalid date-time component"))
|
||||
}
|
||||
};
|
||||
let month = to_u32(month)?;
|
||||
let day = to_u32(day)?;
|
||||
let hour = to_u32(hour)?;
|
||||
let minute = to_u32(minute)?;
|
||||
let second = to_u32(second)?;
|
||||
let millisecond = to_u32(millisecond)?;
|
||||
let microsecond = to_u32(microsecond)?;
|
||||
let nanosecond = to_u32(nanosecond)?;
|
||||
if !valid_iso_date(year, month, day)
|
||||
|| (!ignore_time && !valid_plain_time(hour, minute, second, millisecond, microsecond, nanosecond))
|
||||
{
|
||||
|
||||
@@ -147,18 +147,33 @@ pub fn plain_date_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
|
||||
}
|
||||
// 分量转换序:year → month → day;缺参归 undefined 经 number-only 路径
|
||||
// 统一落 RangeError(日期分量无缺省值,缺参不是合法分量)。
|
||||
let year = native_try!(temporal_number_component(
|
||||
let year_raw = native_try!(temporal_number_component(
|
||||
vm,
|
||||
if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() },
|
||||
)) as i32;
|
||||
let month = native_try!(temporal_number_component(
|
||||
));
|
||||
let month_raw = native_try!(temporal_number_component(
|
||||
vm,
|
||||
if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() },
|
||||
)) as u32;
|
||||
let day = native_try!(temporal_number_component(
|
||||
));
|
||||
let day_raw = native_try!(temporal_number_component(
|
||||
vm,
|
||||
if args.len() > 3 { vm.reg(args[3]) } else { JsValue::undefined() },
|
||||
)) as u32;
|
||||
));
|
||||
// f64 截断后可能超出目标整型范围,先做有界转换。
|
||||
let year = if year_raw >= i32::MIN as f64 && year_raw <= i32::MAX as f64 {
|
||||
year_raw as i32
|
||||
} else {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid year"));
|
||||
};
|
||||
let mut to_u32 = |v: f64| -> Result<u32, JsValue> {
|
||||
if v >= 0.0 && v <= u32::MAX as f64 {
|
||||
Ok(v as u32)
|
||||
} else {
|
||||
Err(crate::error::create_range_error(vm, "invalid date component"))
|
||||
}
|
||||
};
|
||||
let month = native_try!(to_u32(month_raw));
|
||||
let day = native_try!(to_u32(day_raw));
|
||||
if !valid_iso_date(year, month, day) {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid ISO date"));
|
||||
}
|
||||
|
||||
@@ -66,15 +66,27 @@ pub fn plain_date_time_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> Native
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid date-time component"));
|
||||
}
|
||||
|
||||
let year = year_value as i32;
|
||||
let month = month_value as u32;
|
||||
let day = day_value as u32;
|
||||
let hour = hour_value as u32;
|
||||
let minute = minute_value as u32;
|
||||
let second = second_value as u32;
|
||||
let millisecond = millisecond_value as u32;
|
||||
let microsecond = microsecond_value as u32;
|
||||
let nanosecond = nanosecond_value as u32;
|
||||
// f64 截断后可能超出目标整型范围,先做有界转换。
|
||||
let year = if year_value >= i32::MIN as f64 && year_value <= i32::MAX as f64 {
|
||||
year_value as i32
|
||||
} else {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid year"));
|
||||
};
|
||||
let mut to_u32 = |v: f64| -> Result<u32, JsValue> {
|
||||
if v >= 0.0 && v <= u32::MAX as f64 {
|
||||
Ok(v as u32)
|
||||
} else {
|
||||
Err(crate::error::create_range_error(vm, "invalid date-time component"))
|
||||
}
|
||||
};
|
||||
let month = native_try!(to_u32(month_value));
|
||||
let day = native_try!(to_u32(day_value));
|
||||
let hour = native_try!(to_u32(hour_value));
|
||||
let minute = native_try!(to_u32(minute_value));
|
||||
let second = native_try!(to_u32(second_value));
|
||||
let millisecond = native_try!(to_u32(millisecond_value));
|
||||
let microsecond = native_try!(to_u32(microsecond_value));
|
||||
let nanosecond = native_try!(to_u32(nanosecond_value));
|
||||
let non_negative = components[1..].iter().all(|value| *value >= 0.0);
|
||||
if !non_negative
|
||||
|| !valid_iso_date(year, month, day)
|
||||
|
||||
@@ -76,14 +76,29 @@ pub fn plain_month_day_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> Native
|
||||
vm,
|
||||
if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() },
|
||||
));
|
||||
// f64 截断后可能超出 u32 范围,先做有界转换。
|
||||
let mut to_u32 = |v: f64| -> Result<u32, JsValue> {
|
||||
if v >= 0.0 && v <= u32::MAX as f64 {
|
||||
Ok(v as u32)
|
||||
} else {
|
||||
Err(crate::error::create_range_error(vm, "invalid date component"))
|
||||
}
|
||||
};
|
||||
let month = native_try!(to_u32(month));
|
||||
let day = native_try!(to_u32(day));
|
||||
let calendar_raw = if args.len() > 3 { vm.reg(args[3]) } else { JsValue::undefined() };
|
||||
let calendar = native_try!(temporal_constructor_calendar_id(vm, calendar_raw));
|
||||
let ref_year = if args.len() > 4 && !vm.reg(args[4]).is_undefined() {
|
||||
native_try!(temporal_number_component(vm, vm.reg(args[4]))) as i32
|
||||
let ref_year_raw = if args.len() > 4 && !vm.reg(args[4]).is_undefined() {
|
||||
native_try!(temporal_number_component(vm, vm.reg(args[4])))
|
||||
} else {
|
||||
1972
|
||||
1972.0
|
||||
};
|
||||
if !valid_iso_date(ref_year, month as u32, day as u32) {
|
||||
let ref_year = if ref_year_raw >= i32::MIN as f64 && ref_year_raw <= i32::MAX as f64 {
|
||||
ref_year_raw as i32
|
||||
} else {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid year"));
|
||||
};
|
||||
if !valid_iso_date(ref_year, month, day) {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid ISO date"));
|
||||
}
|
||||
// 表示范围(ISODateWithinLimits):-271821-04-19 … +275760-09-13。
|
||||
@@ -97,8 +112,8 @@ pub fn plain_month_day_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> Native
|
||||
args,
|
||||
JsObject::OBJ_TYPE_PLAIN_MONTH_DAY,
|
||||
[
|
||||
JsValue::float(month),
|
||||
JsValue::float(day),
|
||||
JsValue::float(month as f64),
|
||||
JsValue::float(day as f64),
|
||||
JsValue::float(ref_year as f64),
|
||||
calendar_value,
|
||||
],
|
||||
@@ -516,7 +531,10 @@ pub fn plain_month_day_from<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
}
|
||||
code
|
||||
} else {
|
||||
let f = month_f.expect("month or monthCode is required checked above");
|
||||
let f = match month_f {
|
||||
Some(v) => v,
|
||||
None => return NativeResult::Err(crate::error::create_type_error(vm, "month is required")),
|
||||
};
|
||||
if f < 1.0 {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid month"));
|
||||
}
|
||||
|
||||
@@ -43,15 +43,29 @@ fn is_ambiguous_date_string(s: &str) -> bool {
|
||||
};
|
||||
match s.len() {
|
||||
4 if all_digits(0..4) => {
|
||||
let (month, day) = (two_digits(0).unwrap(), two_digits(2).unwrap());
|
||||
day_in_month(month, day)
|
||||
match (two_digits(0), two_digits(2)) {
|
||||
(Some(month), Some(day)) => day_in_month(month, day),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
6 if all_digits(0..6) => {
|
||||
match two_digits(4) {
|
||||
Some(m) => (1..=12).contains(&m),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
6 if all_digits(0..6) => (1..=12).contains(&two_digits(4).unwrap()),
|
||||
5 if bytes[2] == b'-' && all_digits(0..2) && all_digits(3..5) => {
|
||||
let (month, day) = (two_digits(0).unwrap(), two_digits(3).unwrap());
|
||||
day_in_month(month, day)
|
||||
match (two_digits(0), two_digits(3)) {
|
||||
(Some(month), Some(day)) => day_in_month(month, day),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
7 if bytes[4] == b'-' && all_digits(0..4) && all_digits(5..7) => {
|
||||
match two_digits(5) {
|
||||
Some(m) => (1..=12).contains(&m),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
7 if bytes[4] == b'-' && all_digits(0..4) && all_digits(5..7) => (1..=12).contains(&two_digits(5).unwrap()),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -297,12 +311,20 @@ pub fn plain_time_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
|
||||
{
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid time component"));
|
||||
}
|
||||
let hour = hour_value as u32;
|
||||
let minute = minute_value as u32;
|
||||
let second = second_value as u32;
|
||||
let ms = ms_value as u32;
|
||||
let us = us_value as u32;
|
||||
let ns = ns_value as u32;
|
||||
// f64 截断后可能超出 u32 范围,先做有界转换。
|
||||
let mut to_u32 = |v: f64| -> Result<u32, JsValue> {
|
||||
if v >= 0.0 && v <= u32::MAX as f64 {
|
||||
Ok(v as u32)
|
||||
} else {
|
||||
Err(crate::error::create_range_error(vm, "invalid time component"))
|
||||
}
|
||||
};
|
||||
let hour = native_try!(to_u32(hour_value));
|
||||
let minute = native_try!(to_u32(minute_value));
|
||||
let second = native_try!(to_u32(second_value));
|
||||
let ms = native_try!(to_u32(ms_value));
|
||||
let us = native_try!(to_u32(us_value));
|
||||
let ns = native_try!(to_u32(ns_value));
|
||||
if !valid_plain_time(hour, minute, second, ms, us, ns) {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid time component"));
|
||||
}
|
||||
|
||||
@@ -398,7 +398,12 @@ pub fn plain_year_month_from<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
None => (None, false),
|
||||
};
|
||||
// year 转换(TypeError/RangeError)在 monthCode 语法之后。
|
||||
let year = native_try!(temporal_number_component(vm, year_raw)) as i32;
|
||||
let year_raw = native_try!(temporal_number_component(vm, year_raw));
|
||||
let year = if year_raw >= i32::MIN as f64 && year_raw <= i32::MAX as f64 {
|
||||
year_raw as i32
|
||||
} else {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid year"));
|
||||
};
|
||||
let month_f = match month_raw.is_undefined() {
|
||||
true => None,
|
||||
false => Some(native_try!(temporal_number_component(vm, month_raw))),
|
||||
@@ -419,7 +424,10 @@ pub fn plain_year_month_from<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
}
|
||||
code
|
||||
} else {
|
||||
let f = month_f.expect("month or monthCode is required checked above");
|
||||
let f = match month_f {
|
||||
Some(v) => v,
|
||||
None => return NativeResult::Err(crate::error::create_type_error(vm, "month is required")),
|
||||
};
|
||||
if f < 1.0 {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid month"));
|
||||
}
|
||||
@@ -530,7 +538,12 @@ fn year_month_like_parts<H: VmHost>(
|
||||
None => (None, false),
|
||||
};
|
||||
// year 转换(TypeError/RangeError)在 monthCode 语法之后。
|
||||
let year = temporal_number_component(vm, year_raw)? as i32;
|
||||
let year_raw = temporal_number_component(vm, year_raw)?;
|
||||
let year = if year_raw >= i32::MIN as f64 && year_raw <= i32::MAX as f64 {
|
||||
year_raw as i32
|
||||
} else {
|
||||
return Err(crate::error::create_range_error(vm, "invalid year"));
|
||||
};
|
||||
let month_f = match month_raw.is_undefined() {
|
||||
true => None,
|
||||
false => Some(temporal_number_component(vm, month_raw)?),
|
||||
@@ -551,7 +564,7 @@ fn year_month_like_parts<H: VmHost>(
|
||||
}
|
||||
code
|
||||
} else {
|
||||
let f = month_f.expect("month or monthCode is required checked above");
|
||||
let f = month_f.ok_or_else(|| crate::error::create_type_error(vm, "month is required"))?;
|
||||
if f < 1.0 {
|
||||
return Err(crate::error::create_range_error(vm, "invalid month"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user