Skip to content

new constructors for WebIDL bindings introduce undefined behavior by not setting default values #3937

Closed as not planned
@pablosichert

Description

@pablosichert

Describe the Bug

The definitions for WebIDL dictionaries contain information if fields are optional or required by prefixing them with required or marking the type ?. However, there's a third option: fields can be neither required nor ?, but have a default value after =.

Currently, code generation for constructor bindings does not set default values in the body of the new function. Therefore, creating a dictionary with new() and immediately reading a field that should have a default value is undefined behavior.

Steps to Reproduce

E.g. for the first dictionary declaration I could find going alphabetically in the enabled WebIDLs that uses default values:

dictionary AnalyserOptions : AudioNodeOptions {
unsigned long fftSize = 2048;
double maxDecibels = -30;
double minDecibels = -100;
double smoothingTimeConstant = 0.8;
};

use web_sys::{AnalyserOptions, AnalyserOptionsGetters as _};
let analyzer_options = AnalyserOptions::new();
let fft_size = analyzer_options.fft_size(); // Uncaught Error: expected a number argument, found undefined
println!("{}", fft_size);

This example is using the getters as implemented in #3933, but the same case can be constructed by many Web APIs that take a dictionary with properties containing default values as argument.

Expected Behavior

2048

Actual Behavior

imported JS function that was not marked as `catch` threw an error: expected a number argument, found undefined

Additional Context

The faulty generated code for AnalyserOptions::new that does not set default values:

impl AnalyserOptions {
#[doc = "Construct a new `AnalyserOptions`."]
#[doc = ""]
#[doc = "*This API requires the following crate features to be activated: `AnalyserOptions`*"]
pub fn new() -> Self {
#[allow(unused_mut)]
let mut ret: Self = ::wasm_bindgen::JsCast::unchecked_into(::js_sys::Object::new());
ret
}

I discovered this by working on WebIDL dictionary getters in #3933 and thinking about the implications of unsetting dictionary values in #3921 (comment).

Not allowing to safely read properties that are known to exist on a dictionary would require using Option in return values of property getters and require to be unnecessarily defensive when reading them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions