Dawn.node disallow constructing non-constructables
This prevents doing `new GPUDevice()` and `new GPUTexture()`
Bug: 419128706
Depends-On: Ia388562d8d7f02458e36b29db1a5acb8fcac03e2
Change-Id: Ie0b0969b3d1fae09913501fc8b6c1406e114c637
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/243295
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Gregg Tavares <gman@chromium.org>
diff --git a/src/dawn/node/interop/WebGPU.cpp.tmpl b/src/dawn/node/interop/WebGPU.cpp.tmpl
index 06e1885..991cdce 100644
--- a/src/dawn/node/interop/WebGPU.cpp.tmpl
+++ b/src/dawn/node/interop/WebGPU.cpp.tmpl
@@ -54,6 +54,11 @@
namespace {
+// This is passed to constructors so that constructor can
+// check if it's being called legitimately from C++ or
+// illegitimately from JavaScript.
+static void* kInternalConstructionMarker = nullptr;
+
{{template "Wrappers" $}}
} // namespace
@@ -201,7 +206,15 @@
return func;
}
- W{{$.Name}}(const Napi::CallbackInfo& info) : ObjectWrap(info) {}
+ W{{$.Name}}(const Napi::CallbackInfo& info) : ObjectWrap(info) {
+{{- if and (IsInterface $) (not (HasConstructor $))}}
+ // Check if the first argument is our internal Napi::External<void> marker
+ // to prevent JavaScript from constructing this non-constructable object.
+ if (info.Length() < 1 || !info[0].IsExternal() || info[0].As<Napi::External<void>>().Data() != &kInternalConstructionMarker) {
+ Napi::TypeError::New(info.Env(), "Failed to construct '{{$.Name}}': Illegal constructor").ThrowAsJavaScriptException();
+ }
+{{- end}}
+ }
{{- if $s := SetlikeOf $}}
Napi::Value has(const Napi::CallbackInfo& info) {
@@ -385,7 +398,10 @@
Interface<{{$.Name}}> {{$.Name}}::Bind(Napi::Env env, std::unique_ptr<{{$.Name}}>&& impl) {
auto* wrappers = Wrappers::For(env);
- auto object = wrappers->{{$.Name}}_ctor.New({});
+ // Pass in kInternalConstructionMarker to allow this instance to actually be constructed.
+ auto object = wrappers->{{$.Name}}_ctor.New({
+ Napi::External<void>::New(env, &kInternalConstructionMarker)
+ });
auto* wrapper = Wrappers::W{{$.Name}}::Unwrap(object);
wrapper->impl = std::move(impl);
diff --git a/tools/src/cmd/idlgen/main.go b/tools/src/cmd/idlgen/main.go
index 4ddf628..8536382 100644
--- a/tools/src/cmd/idlgen/main.go
+++ b/tools/src/cmd/idlgen/main.go
@@ -126,6 +126,7 @@
"EnumEntryName": enumEntryName,
"Eval": g.eval,
"HasAnnotation": hasAnnotation,
+ "HasConstructor": hasConstructor,
"FlattenedAttributesOf": g.flattenedAttributesOf,
"FlattenedConstantsOf": g.flattenedConstantsOf,
"FlattenedMethodsOf": g.flattenedMethodsOf,
@@ -579,6 +580,17 @@
panic("Unhandled AST node type in hasAnnotation")
}
+func hasConstructor(obj interface{}) bool {
+ iface := obj.(*ast.Interface)
+ for _, member := range iface.Members {
+ member := member.(*ast.Member)
+ if isInitializer(member) {
+ return true
+ }
+ }
+ return false
+}
+
// Method describes a WebIDL interface method
type Method struct {
// Name of the method