Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm-bindgen: imported JS function that was not marked as catch threw an error: Cannot read property 'width' of undefined #1017

Open
insinfo opened this issue Jun 18, 2021 · 4 comments

Comments

@insinfo
Copy link

insinfo commented Jun 18, 2021

🐛 Bug description

I can't access a property of an HtmlCanvasElement with rust, I'm having trouble using the "photon_rs" library with javascript, because of this bug, so I thought it was a bug with the "photon_rs" lib, so I decided to clone the lib code "photon_rs" and analyze it to find the error, that's when I came across this problem and decided to create a small simple project "hello world", then I could determine that the problem is not in the lib "photon_rs", it seems that the problem is in the "wasm-pack"

wasm-bindgen: imported JS function that was not marked as `catch` threw an error: Cannot read property 'width' of undefined

Stack:
TypeError: Cannot read property 'width' of undefined
    at http://127.0.0.1:8080/teste.js:132:34
    at logError (http://127.0.0.1:8080/teste.js:44:18)
    at imports.wbg.__wbg_width_9eb2c66ac9dde633 (http://127.0.0.1:8080/teste.js:131:68)
    at web_sys::features::gen_HtmlCanvasElement::HtmlCanvasElement::width::hc1421e5da4eb229c (<anonymous>:wasm-function[215]:0xdb55)
    at teste::greet::hea5b9587a566489d (<anonymous>:wasm-function[33]:0x6085)
    at greet (<anonymous>:wasm-function[257]:0xe7cb)
    at http://127.0.0.1:8080/:19:24
teste.js:132 Uncaught TypeError: Cannot read property 'width' of undefined
    at teste.js:132
    at logError (teste.js:44)
    at imports.wbg.__wbg_width_9eb2c66ac9dde633 (teste.js:131)
    at web_sys::features::gen_HtmlCanvasElement::HtmlCanvasElement::width::hc1421e5da4eb229c (<anonymous>:wasm-function[215]:0xdb55)
    at teste::greet::hea5b9587a566489d (<anonymous>:wasm-function[33]:0x6085)
    at greet (<anonymous>:wasm-function[257]:0xe7cb)
    at (index):19

🤔 Expected Behavior

access all properties of HTML elements

👟 Steps to reproduce

lib.rs
mod utils;
use wasm_bindgen::prelude::*;
use web_sys::{HtmlCanvasElement};
//for production use: wasm-pack build --target no-modules --release
//for dev use: wasm-pack build --target no-modules --debug

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
extern "C" {
    // Use `js_namespace` here to bind `console.log(..)` instead of just
    // `log(..)`
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);

    // The `console.log` is quite polymorphic, so we can bind it with multiple
    // signatures. Note that we need to use `js_name` to ensure we always call
    // `log` in JS.
    #[wasm_bindgen(js_namespace = console, js_name = log)]
    fn log_u32(a: u32);

    // Multiple arguments too!
    #[wasm_bindgen(js_namespace = console, js_name = log)]
    fn log_many(a: &str, b: &str);
}

macro_rules! console_log {
    // Note that this is using the `log` function imported above during
    // `bare_bones`
    ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}

#[wasm_bindgen]
pub fn greet(canvas: HtmlCanvasElement) {
    //alert("Hello, teste!");
    console_log!("greet {:?}", canvas.width());
}
Cargo.toml
[package]
name = "teste"
version = "0.1.0"
authors = ["insinfo <insinfo2008@gmail.com>"]
edition = "2018"

[lib]
crate-type = ["cdylib", "rlib"]

[features]
default = ["console_error_panic_hook"]

[dependencies]
wasm-bindgen = "0.2.74" #0.2.63
js-sys = "0.3.51"


# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.6", optional = true }

# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
#
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
wee_alloc = { version = "0.4.5", optional = true }

[dev-dependencies]
wasm-bindgen-test = "0.3.24"
wasm-bindgen-futures = "0.4.24"

[dependencies.web-sys]
version = "0.3.51"
features = [
  "Document",
  "Element",
  "HtmlElement",
  "Node",
  "Window",
  "CanvasRenderingContext2d",
  "ImageData",
  "HtmlCanvasElement",
  "HtmlImageElement",
  "console",
  'CssStyleDeclaration',
  'EventTarget',
]

[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
index.html
<!DOCTYPE html>
<html>

<head>
    <title>teste</title>
    <script id="script-teste" src="teste.js" ></script>
    <script>
       
        var modulo;
        async function init() {
            var scri = document.querySelector('#script-teste');
            var url = scri.src.replace(/\.js$/, '_bg.wasm');
            modulo = await wasm_bindgen(url);
        }
        init();
        window.onload = function (e) {
            setTimeout(function (e) {
                var canvas = document.getElementById("canvas");
                modulo.greet(canvas);
            }, 1000);

        };
    </script>
</head>

<body>
    <h1>teste</h1>
    <img id="img"
        src="https://dyl80ryjxr1ke.cloudfront.net/external_assets/hero_examples/hair_beach_v391182663/original.jpeg"
        width="640" height="480">
    <canvas id="canvas" width="640" height="480"></canvas>
</body>

</html>
generated index.js with: wasm-pack build --target no-modules --debug
let wasm_bindgen;
(function() {
    const __exports = {};
    let wasm;

    const heap = new Array(32).fill(undefined);

    heap.push(undefined, null, true, false);

function getObject(idx) { return heap[idx]; }

let heap_next = heap.length;

function dropObject(idx) {
    if (idx < 36) return;
    heap[idx] = heap_next;
    heap_next = idx;
}

function takeObject(idx) {
    const ret = getObject(idx);
    dropObject(idx);
    return ret;
}

let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });

cachedTextDecoder.decode();

let cachegetUint8Memory0 = null;
function getUint8Memory0() {
    if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
        cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
    }
    return cachegetUint8Memory0;
}

function getStringFromWasm0(ptr, len) {
    return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}

function logError(f, args) {
    try {
        return f.apply(this, args);
    } catch (e) {
        let error = (function () {
            try {
                return e instanceof Error ? `${e.message}\n\nStack:\n${e.stack}` : e.toString();
            } catch(_) {
                return "<failed to stringify thrown value>";
            }
        }());
        console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:", error);
        throw e;
    }
}

function addHeapObject(obj) {
    if (heap_next === heap.length) heap.push(heap.length + 1);
    const idx = heap_next;
    heap_next = heap[idx];

    if (typeof(heap_next) !== 'number') throw new Error('corrupt heap');

    heap[idx] = obj;
    return idx;
}
/**
* @param {HTMLCanvasElement} canvas
*/
__exports.greet = function(canvas) {
    wasm.greet(addHeapObject(canvas));
};

function _assertNum(n) {
    if (typeof(n) !== 'number') throw new Error('expected a number argument');
}

async function load(module, imports) {
    if (typeof Response === 'function' && module instanceof Response) {
        if (typeof WebAssembly.instantiateStreaming === 'function') {
            try {
                return await WebAssembly.instantiateStreaming(module, imports);

            } catch (e) {
                if (module.headers.get('Content-Type') != 'application/wasm') {
                    console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);

                } else {
                    throw e;
                }
            }
        }

        const bytes = await module.arrayBuffer();
        return await WebAssembly.instantiate(bytes, imports);

    } else {
        const instance = await WebAssembly.instantiate(module, imports);

        if (instance instanceof WebAssembly.Instance) {
            return { instance, module };

        } else {
            return instance;
        }
    }
}

async function init(input) {
    if (typeof input === 'undefined') {
        let src;
        if (typeof document === 'undefined') {
            src = location.href;
        } else {
            src = document.currentScript.src;
        }
        input = src.replace(/\.js$/, '_bg.wasm');
    }
    const imports = {};
    imports.wbg = {};
    imports.wbg.__wbg_alert_96651bef84688e4c = function() { return logError(function (arg0, arg1) {
        alert(getStringFromWasm0(arg0, arg1));
    }, arguments) };
    imports.wbg.__wbg_log_cc87b1cd273573ca = function() { return logError(function (arg0, arg1) {
        console.log(getStringFromWasm0(arg0, arg1));
    }, arguments) };
    imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
        takeObject(arg0);
    };
    imports.wbg.__wbg_width_9eb2c66ac9dde633 = function() { return logError(function (arg0) {
        var ret = getObject(arg0).width;
        _assertNum(ret);
        return ret;
    }, arguments) };
    imports.wbg.__wbindgen_throw = function(arg0, arg1) {
        throw new Error(getStringFromWasm0(arg0, arg1));
    };

    if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
        input = fetch(input);
    }



    const { instance, module } = await load(await input, imports);

    wasm = instance.exports;
    init.__wbindgen_wasm_module = module;

    return wasm;
}

wasm_bindgen = Object.assign(init, __exports);

})();

🌍 Your environment

Windows 10
wasm-pack version: wasm-pack 0.9.1
rustc version: rustc 1.53.0 (53cb7b09b 2021-06-17)

https://github.com/insinfo/photon-test
silvia-odwyer/photon#99

@insinfo
Copy link
Author

insinfo commented Jun 18, 2021

after a lot of brainstorming, I found out where the problem was, the "wasm-pack" is generating the javascript with error on this line: "wasm_bindgen = Object.assign(init, __exports);"

so to solve the problem I replace this line, so:

   //wasm_bindgen = Object.assign(init, __exports);
   wasm_bindgen = init;

   /**
     * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
     * @param obj1
     * @param obj2
     * @returns obj3 a new object based on obj1 and obj2
     */
    function merge_options(obj1, obj2) {
        var obj3 = {};
        for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
        for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
        return obj3;
    }
    

and this line "return wasm;" that is why

 //return wasm;
 return merge_options(wasm, __exports);

this should ideally be fixed in a patch release.

@lencx
Copy link

lencx commented Jun 19, 2021

@insinfo
Copy link
Author

insinfo commented Jun 19, 2021

@lencx
I didn't understand what you meant exactly?

my code on github is already with the correction that I informed here.

I don't use npm , webpack, react or anything like that.
Of the 20 projects I work on at the company, 15 are AngularDart and others are pure Javascript or Flutter

My web frontend projects are done with AngularDart or pure javascript, both my personal projects and my projects in the company where I work.

@lencx
Copy link

lencx commented Jun 20, 2021

Sorry, because just looking at the code example you gave, I don’t know if you don’t use npm, webpack, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants