Skip to content

Commit 3af4dba

Browse files
committed
src: add FromV8Value<T>() for integral and enum types
Add a template utility method FromV8Value<T>() to replace the repetitive static_cast<...>(value.As<>()‑>Value()) pattern. It also additionally adds compile‑time range checks for integers. Refs: #57146 (comment)
1 parent 5077ea4 commit 3af4dba

File tree

8 files changed

+43
-17
lines changed

8 files changed

+43
-17
lines changed

src/crypto/crypto_keys.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ void KeyObjectHandle::InitEDRaw(const FunctionCallbackInfo<Value>& args) {
780780
Utf8Value name(env->isolate(), args[0]);
781781

782782
ArrayBufferOrViewContents<unsigned char> key_data(args[1]);
783-
KeyType type = static_cast<KeyType>(args[2].As<Int32>()->Value());
783+
KeyType type = FromV8Value<KeyType>(args[2]);
784784

785785
MarkPopErrorOnReturn mark_pop_error_on_return;
786786

src/node_file.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2881,10 +2881,10 @@ static void Chown(const FunctionCallbackInfo<Value>& args) {
28812881
ToNamespacedPath(env, &path);
28822882

28832883
CHECK(IsSafeJsInt(args[1]));
2884-
const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2884+
const uv_uid_t uid = FromV8Value<uv_uid_t>(args[1]);
28852885

28862886
CHECK(IsSafeJsInt(args[2]));
2887-
const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2887+
const uv_gid_t gid = FromV8Value<uv_gid_t>(args[2]);
28882888

28892889
if (argc > 3) { // chown(path, uid, gid, req)
28902890
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
@@ -2956,10 +2956,10 @@ static void LChown(const FunctionCallbackInfo<Value>& args) {
29562956
ToNamespacedPath(env, &path);
29572957

29582958
CHECK(IsSafeJsInt(args[1]));
2959-
const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2959+
const uv_uid_t uid = FromV8Value<uv_uid_t>(args[1]);
29602960

29612961
CHECK(IsSafeJsInt(args[2]));
2962-
const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2962+
const uv_gid_t gid = FromV8Value<uv_gid_t>(args[2]);
29632963

29642964
if (argc > 3) { // lchown(path, uid, gid, req)
29652965
FSReqBase* req_wrap_async = GetReqWrap(args, 3);

src/node_util.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ static void GetOwnNonIndexProperties(
6161

6262
Local<Array> properties;
6363

64-
PropertyFilter filter =
65-
static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
64+
PropertyFilter filter = FromV8Value<PropertyFilter>(args[1]);
6665

6766
if (!object->GetPropertyNames(
6867
context, KeyCollectionMode::kOwnOnly,

src/node_v8.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ using v8::HandleScope;
4040
using v8::HeapCodeStatistics;
4141
using v8::HeapSpaceStatistics;
4242
using v8::HeapStatistics;
43-
using v8::Int32;
4443
using v8::Integer;
4544
using v8::Isolate;
4645
using v8::Local;
@@ -492,8 +491,7 @@ static void GetCppHeapStatistics(const FunctionCallbackInfo<Value>& args) {
492491
CHECK(args[0]->IsInt32());
493492

494493
cppgc::HeapStatistics stats = isolate->GetCppHeap()->CollectStatistics(
495-
static_cast<cppgc::HeapStatistics::DetailLevel>(
496-
args[0].As<Int32>()->Value()));
494+
FromV8Value<cppgc::HeapStatistics::DetailLevel>(args[0]));
497495

498496
Local<Object> result;
499497
if (!ConvertHeapStatsToJSObject(isolate, stats).ToLocal(&result)) {

src/node_zlib.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ using v8::Function;
5353
using v8::FunctionCallbackInfo;
5454
using v8::FunctionTemplate;
5555
using v8::HandleScope;
56-
using v8::Int32;
5756
using v8::Integer;
5857
using v8::Isolate;
5958
using v8::Local;
@@ -687,8 +686,7 @@ class ZlibStream final : public CompressionStream<ZlibContext> {
687686
static void New(const FunctionCallbackInfo<Value>& args) {
688687
Environment* env = Environment::GetCurrent(args);
689688
CHECK(args[0]->IsInt32());
690-
node_zlib_mode mode =
691-
static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
689+
node_zlib_mode mode = FromV8Value<node_zlib_mode>(args[0]);
692690
new ZlibStream(env, args.This(), mode);
693691
}
694692

@@ -793,8 +791,7 @@ class BrotliCompressionStream final :
793791
static void New(const FunctionCallbackInfo<Value>& args) {
794792
Environment* env = Environment::GetCurrent(args);
795793
CHECK(args[0]->IsInt32());
796-
node_zlib_mode mode =
797-
static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
794+
node_zlib_mode mode = FromV8Value<node_zlib_mode>(args[0]);
798795
new BrotliCompressionStream(env, args.This(), mode);
799796
}
800797

src/process_wrap.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ class ProcessWrap : public HandleWrap {
173173
return Nothing<void>();
174174
}
175175
CHECK(fd_value->IsNumber());
176-
int fd = static_cast<int>(fd_value.As<Integer>()->Value());
176+
int fd = FromV8Value<int>(fd_value);
177177
options->stdio[i].flags = UV_INHERIT_FD;
178178
options->stdio[i].data.fd = fd;
179179
}

src/udp_wrap.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ void UDPWrap::Open(const FunctionCallbackInfo<Value>& args) {
354354
ASSIGN_OR_RETURN_UNWRAP(
355355
&wrap, args.This(), args.GetReturnValue().Set(UV_EBADF));
356356
CHECK(args[0]->IsNumber());
357-
int fd = static_cast<int>(args[0].As<Integer>()->Value());
357+
int fd = FromV8Value<int>(args[0]);
358358
int err = uv_udp_open(&wrap->handle_, fd);
359359

360360
args.GetReturnValue().Set(err);

src/util-inl.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,38 @@ constexpr std::string_view FastStringKey::as_string_view() const {
588588
return name_;
589589
}
590590

591+
// Converts a V8 numeric value to a corresponding C++ primitive or enum type.
592+
template <typename T,
593+
typename = std::enable_if_t<std::numeric_limits<T>::is_specialized ||
594+
std::is_enum_v<T>>>
595+
T FromV8Value(v8::Local<v8::Value> value) {
596+
if constexpr (std::is_enum_v<T>) {
597+
using Underlying = std::underlying_type_t<T>;
598+
return static_cast<T>(FromV8Value<Underlying>(value));
599+
} else if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>) {
600+
static_assert(
601+
std::numeric_limits<T>::max() <= std::numeric_limits<uint32_t>::max() &&
602+
std::numeric_limits<T>::min() >=
603+
std::numeric_limits<uint32_t>::min(),
604+
"Type is out of unsigned integer range");
605+
CHECK(value->IsUint32());
606+
return static_cast<T>(value.As<v8::Uint32>()->Value());
607+
} else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
608+
static_assert(
609+
std::numeric_limits<T>::max() <= std::numeric_limits<int32_t>::max() &&
610+
std::numeric_limits<T>::min() >=
611+
std::numeric_limits<int32_t>::min(),
612+
"Type is out of signed integer range");
613+
CHECK(value->IsInt32());
614+
return static_cast<T>(value.As<v8::Int32>()->Value());
615+
} else {
616+
static_assert(std::is_floating_point_v<T>,
617+
"Type must be arithmetic or enum.");
618+
CHECK(value->IsNumber());
619+
return static_cast<T>(value.As<v8::Number>()->Value());
620+
}
621+
}
622+
591623
// Inline so the compiler can fully optimize it away on Unix platforms.
592624
bool IsWindowsBatchFile(const char* filename) {
593625
#ifdef _WIN32

0 commit comments

Comments
 (0)