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