Repository: rust-random/getrandom
Pull request #86 (2019-08-14 15:00:40)

Add VxWorks support
I couldn't find a proper documentation for VxWorks, so I've mostly just copied code from `std`.

Relevant issue: openssl/openssl#7946

This PR will not work until rust-lang/libc#1473 lands.

cc @bpangWR @BaoshanPang

BaoshanPang: @newpavlov 

Thanks for working this, I am actually looking for the way to port rand for vxWorks with latest version, the layout of version 0.7.0 is quiet different than 0.6.1 which we have ported for.

I don't see any problem with the code, it is good to me.

 Can you teach me how to test it for vxWorks? I am seeing rand 0.6.1(and 0.6.5) is used when runing rust libstd unit test, but I can't figure out where/how rand 0.7.0 is used.

Thanks,
Baoshan 
newpavlov: If I understood you correctly, then you don't have to do anything. Assuming this PR is correct, after publishing the next version of `getrandom` with it, `rand v0.7` should start working on VxWorks automatically.

`libstd` only recently started using `rand v0.7`, I think after this PR: rust-lang/rust#61393.
BaoshanPang: >>libstd only recently started using rand v0.7, I think after this PR: rust-lang/rust#61393.
I see.  Thanks.
newpavlov: @n-salim 
Also do we have to provide any linking arguments to Cargo? See [build.rs](https://github.com/rust-random/getrandom/blob/master/build.rs). Note that in future `getrandom` may be used as a dependency of `std`.
n-salim: 
> Also do we have to provide any linking arguments to Cargo?
Good question. Luckily randBytes is part of VxWorks libc.a, which we already always link against.


newpavlov: >Luckily randBytes is part of VxWorks libc.a, which we already always link against.

How about adding `randBytes` to the `libc` crate then? It would allow us to simplify code in `getrandom` a bit. Also please take look at rust-lang/libc#1469.
BaoshanPang: >>How about adding randBytes to the libc crate then?

I will do it as part of libc#1469.
n-salim: Let's expose randABytes and randUBytes too.
BaoshanPang: > If I understood you correctly, then you don't have to do anything. Assuming this PR is correct, after publishing the next version of `getrandom` with it, `rand v0.7` should start working on VxWorks automatically.
> 
> `libstd` only recently started using `rand v0.7`, I think after this PR: [rust-lang/rust#61393](https://github.com/rust-lang/rust/pull/61393).

I just built the latest rust code , although there are both rand 0.7 and rand 0.6.1 listed in Cargo.lock, but the rand used is still 0.6.1 when building libstd unit test:

$ ./x.py test -i --stage 1 src/libstd
...
  Compiling rand v0.6.1

Patch:
diff --git a/.cargo/config b/.cargo/config
new file mode 100644
index 0000000..291ce5e
--- /dev/null
+++ b/.cargo/config
@@ -0,0 +1,5 @@
+[target.wasm32-unknown-unknown]
+runner = 'wasm-bindgen-test-runner'
+
+[target.wasm32-wasi]
+runner = 'wasmtime'
diff --git a/.travis.yml b/.travis.yml
index 19e566c..bdd9e72 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,34 +29,55 @@ matrix:
 
     - name: "WASM via emscripten, stdweb, wasm-bindgen and WASI"
       rust: nightly
+      addons:
+        firefox: latest
+        chrome: stable
       install:
         - rustup target add wasm32-unknown-unknown
         - rustup target add wasm32-unknown-emscripten
+        - rustup target add asmjs-unknown-emscripten
         - rustup target add wasm32-wasi
-        - nvm install 9
-        - ./utils/ci/install_cargo_web.sh
+        # Get latest geckodriver
+        - export VERSION=$(curl -s https://api.github.com/repos/mozilla/geckodriver/releases/latest | jq -r ".tag_name")
+        - wget -O geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/$VERSION/geckodriver-$VERSION-linux64.tar.gz
+        - tar -xzf geckodriver.tar.gz
+        # Get latest chromedirver
+        - export VERSION=$(wget -q -O - https://chromedriver.storage.googleapis.com/LATEST_RELEASE)
+        - wget -O chromedriver.zip https://chromedriver.storage.googleapis.com/$VERSION/chromedriver_linux64.zip
+        - unzip chromedriver.zip
+        # Get cargo-web
+        - export VERSION=0.6.26 # Pin version for stability
+        - wget -O cargo-web.gz https://github.com/koute/cargo-web/releases/download/$VERSION/cargo-web-x86_64-unknown-linux-gnu.gz
+        - gunzip cargo-web.gz
+        - chmod +x cargo-web
+        # Get wasmtime
+        - export VERSION=v0.3.0 # Pin version for stability
+        - wget -O wasmtime.tar.xz https://github.com/CraneStation/wasmtime/releases/download/$VERSION/wasmtime-$VERSION-x86_64-linux.tar.xz
+        - tar -xf wasmtime.tar.xz --strip-components=1
+        # Get wasm-bindgen-test-runner which matches our wasm-bindgen version
+        - export VERSION=$(cargo metadata --format-version=1 | jq -r '.packages[] | select ( .name == "wasm-bindgen" ) | .version')
+        - wget -O wasm-bindgen.tar.gz https://github.com/rustwasm/wasm-bindgen/releases/download/$VERSION/wasm-bindgen-$VERSION-x86_64-unknown-linux-musl.tar.gz
+        - tar -xzf wasm-bindgen.tar.gz --strip-components=1
+        # Place the runner binaries in our PATH
+        - mv cargo-web wasmtime wasm-bindgen-test-runner $HOME/.cargo/bin
+        # Download and setup emscripten
         - cargo web prepare-emscripten
-        - cargo web -V
-        - cargo list | grep install-update || cargo install -f cargo-update
-        - cargo install-update -i cargo-update wasm-bindgen-cli wasm-pack
-      addons:
-        chrome: stable
+      env: EMCC_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0"
       script:
-        # Testing wasm32-unknown-emscripten fails because of rust-lang/rust#49877
+        # We cannot run emscripten test binaries (see rust-lang/rust#63649).
         # However, we can still build and link all tests to make sure that works.
         # This is actually useful as it finds stuff such as rust-random/rand#669
-        - EMCC_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0" cargo web test --target wasm32-unknown-emscripten --no-run
-        #- cargo web test --target wasm32-unknown-emscripten
-        #- cargo web test --nodejs --target wasm32-unknown-emscripten
-        #- cargo build --target wasm32-unknown-unknown # without any features
-        - cargo build --target wasm32-wasi
-        - cargo build --target wasm32-unknown-unknown
-        - cargo build --target wasm32-unknown-unknown --features=wasm-bindgen
-        - cargo web test --target wasm32-unknown-unknown --features=stdweb
-        - cargo build --manifest-path tests/wasm_bindgen/Cargo.toml --target wasm32-unknown-unknown
-        - wasm-bindgen --nodejs target/wasm32-unknown-unknown/debug/getrandom_wasm_bindgen_test.wasm --out-dir tests/wasm_bindgen/js
-        - node tests/wasm_bindgen/js/index.js
-        - wasm-pack test --node tests/wasm_bindgen
+        - cargo web test --target wasm32-unknown-emscripten --no-run
+        - cargo web test --target asmjs-unknown-emscripten --no-run
+        # wasi tests
+        - cargo test --target wasm32-wasi
+        # stdweb tests (Node, Chrome)
+        - cargo web test --nodejs --target=wasm32-unknown-unknown --features=stdweb
+        - cargo web test --target=wasm32-unknown-unknown --features=stdweb
+        # wasm-bindgen tests (Node, Firefox, Chrome)
+        - cargo test --target wasm32-unknown-unknown --features=wasm-bindgen
+        - GECKODRIVER=$PWD/geckodriver cargo test --target wasm32-unknown-unknown --features=test-in-browser
+        - CHROMEDRIVER=$PWD/chromedriver cargo test --target wasm32-unknown-unknown --features=test-in-browser
 
     - name: "Linux, nightly, docs"
       rust: nightly
@@ -118,6 +139,7 @@ matrix:
         - cargo xbuild --target=x86_64-unknown-uefi
         - cargo xbuild --target=x86_64-unknown-hermit
         - cargo xbuild --target=x86_64-unknown-l4re-uclibc
+        - cargo xbuild --target=x86_64-wrs-vxworks
         # also test minimum dependency versions are usable
         - cargo generate-lockfile -Z minimal-versions
         - cargo build --target=x86_64-sun-solaris
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a7bdb29..6f43b26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [0.1.12] - 2019-08-18
+### Changed
+- Update wasi dependency from v0.5 to v0.7. [#100]
+
+[#100]: https://github.com/rust-random/getrandom/pull/100
+
 ## [0.1.11] - 2019-08-25
 ### Fixed
 - Implement `std`-dependent traits for selected targets even if `std`
diff --git a/Cargo.toml b/Cargo.toml
index cdf4e3c..95fc8d8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "getrandom"
-version = "0.1.11"
+version = "0.1.12"
 edition = "2018"
 authors = ["The Rand Project Developers"]
 license = "MIT OR Apache-2.0"
@@ -14,30 +14,32 @@ exclude = ["utils/*", ".*", "appveyor.yml"]
 travis-ci = { repository = "rust-random/getrandom" }
 appveyor = { repository = "rust-random/getrandom" }
 
-[workspace]
-members = ["tests/wasm_bindgen"]
-
 [dependencies]
 log = { version = "0.4", optional = true }
-cfg-if = "0.1"
+cfg-if = "0.1.2"
 
 # When built as part of libstd
 compiler_builtins = { version = "0.1", optional = true }
 core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" }
 
-[target.'cfg(any(unix, target_os = "redox"))'.dependencies]
-libc = { version = "0.2.62", default-features = false }
+[target.'cfg(unix)'.dependencies]
+libc = { version = "0.2.64", default-features = false }
 
 [target.'cfg(target_os = "wasi")'.dependencies]
-wasi = "0.5"
+wasi = "0.7"
 
 [target.wasm32-unknown-unknown.dependencies]
 wasm-bindgen = { version = "0.2.29", optional = true }
 stdweb = { version = "0.4.18", optional = true }
 
+[target.wasm32-unknown-unknown.dev-dependencies]
+wasm-bindgen-test = "0.2"
+
 [features]
 std = []
-# enables dummy implementation for unsupported targets
+# Enables dummy implementation for unsupported targets
 dummy = []
 # Unstable feature to support being a libstd dependency
 rustc-dep-of-std = ["compiler_builtins", "core"]
+# Unstable feature for testing
+test-in-browser = ["wasm-bindgen"]
diff --git a/src/freebsd.rs b/src/bsd_arandom.rs
similarity index 57%
rename from src/freebsd.rs
rename to src/bsd_arandom.rs
index 61feaf7..eb564ff 100644
--- a/src/freebsd.rs
+++ b/src/bsd_arandom.rs
@@ -6,12 +6,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Implementation for FreeBSD
-use crate::util_libc::{sys_fill_exact, Weak};
+//! Implementation for FreeBSD and NetBSD
+use crate::util_libc::sys_fill_exact;
 use crate::Error;
-use core::{mem, ptr};
-
-type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t;
+use core::ptr;
 
 fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t {
     static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND];
@@ -27,7 +25,7 @@ fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t {
         )
     };
     if ret == -1 {
-        error!("freebsd: kern.arandom syscall failed");
+        error!("sysctl kern.arandom: syscall failed");
         -1
     } else {
         len as libc::ssize_t
@@ -35,11 +33,17 @@ fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t {
 }
 
 pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
-    static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") };
-    if let Some(fptr) = GETRANDOM.ptr() {
-        let func: GetRandomFn = unsafe { mem::transmute(fptr) };
-        sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr(), buf.len(), 0) })
-    } else {
-        sys_fill_exact(dest, kern_arnd)
+    #[cfg(target_os = "freebsd")]
+    {
+        use crate::util_libc::Weak;
+        static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") };
+        type GetRandomFn =
+            unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t;
+
+        if let Some(fptr) = GETRANDOM.ptr() {
+            let func: GetRandomFn = unsafe { core::mem::transmute(fptr) };
+            return sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr(), buf.len(), 0) });
+        }
     }
+    sys_fill_exact(dest, kern_arnd)
 }
diff --git a/src/error.rs b/src/error.rs
index c68a767..3902506 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -60,22 +60,29 @@ impl Error {
     }
 }
 
-#[cfg(any(unix, target_os = "redox"))]
-fn os_err_desc(errno: i32, buf: &mut [u8]) -> Option<&str> {
-    let buf_ptr = buf.as_mut_ptr() as *mut libc::c_char;
-    if unsafe { libc::strerror_r(errno, buf_ptr, buf.len()) } != 0 {
-        return None;
-    }
-
-    // Take up to trailing null byte
-    let n = buf.len();
-    let idx = buf.iter().position(|&b| b == 0).unwrap_or(n);
-    core::str::from_utf8(&buf[..idx]).ok()
-}
+cfg_if! {
+    if #[cfg(unix)] {
+        fn os_err_desc(errno: i32, buf: &mut [u8]) -> Option<&str> {
+            let buf_ptr = buf.as_mut_ptr() as *mut libc::c_char;
+            if unsafe { libc::strerror_r(errno, buf_ptr, buf.len()) } != 0 {
+                return None;
+            }
 
-#[cfg(not(any(unix, target_os = "redox")))]
-fn os_err_desc(_errno: i32, _buf: &mut [u8]) -> Option<&str> {
-    None
+            // Take up to trailing null byte
+            let n = buf.len();
+            let idx = buf.iter().position(|&b| b == 0).unwrap_or(n);
+            core::str::from_utf8(&buf[..idx]).ok()
+        }
+    } else if #[cfg(target_os = "wasi")] {
+        fn os_err_desc(errno: i32, _buf: &mut [u8]) -> Option<&str> {
+            core::num::NonZeroU16::new(errno as u16)
+                .and_then(wasi::wasi_unstable::error_str)
+        }
+    } else {
+        fn os_err_desc(_errno: i32, _buf: &mut [u8]) -> Option<&str> {
+            None
+        }
+    }
 }
 
 impl fmt::Debug for Error {
@@ -138,6 +145,7 @@ pub(crate) const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7);
 pub(crate) const BINDGEN_GRV_UNDEF: Error = internal_error!(8);
 pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9);
 pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10);
+pub(crate) const RAND_SECURE_FATAL: Error = internal_error!(11);
 
 fn internal_desc(error: Error) -> Option<&'static str> {
     match error {
@@ -152,6 +160,7 @@ fn internal_desc(error: Error) -> Option<&'static str> {
         BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"),
         STDWEB_NO_RNG => Some("stdweb: no randomness source available"),
         STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"),
+        RAND_SECURE_FATAL => Some("randSecure: random number generator module is not initialized"),
         _ => None,
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 023a623..b99ce19 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -18,7 +18,7 @@
 //! | iOS              | [`SecRandomCopyBytes`][4]
 //! | FreeBSD          | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
 //! | OpenBSD          | [`getentropy`][6]
-//! | NetBSD           | [`/dev/urandom`][7] after successfully polling `/dev/random`
+//! | NetBSD           | [`kern.arandom`][7]
 //! | Dragonfly BSD    | [`/dev/random`][8]
 //! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
 //! | Fuchsia OS       | [`cprng_draw`][11]
@@ -27,6 +27,7 @@
 //! | Haiku            | `/dev/random` (identical to `/dev/urandom`)
 //! | L4RE, SGX, UEFI  | [RDRAND][18]
 //! | Hermit           | [RDRAND][18] as [`sys_rand`][22] is currently broken.
+//! | VxWorks          | `randABytes` after checking entropy pool initialization with `randSecure`
 //! | Web browsers     | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14])
 //! | Node.js          | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16])
 //! | WASI             | [`__wasi_random_get`][17]
@@ -104,7 +105,7 @@
 //! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
 //! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
 //! [6]: https://man.openbsd.org/getentropy.2
-//! [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current
+//! [7]: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7+NetBSD-8.0
 //! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
 //! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
 //! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
@@ -160,6 +161,10 @@ pub use crate::error::Error;
 #[allow(dead_code)]
 mod util;
 
+#[cfg(target_os = "vxworks")]
+#[allow(dead_code)]
+mod util_libc;
+
 cfg_if! {
     // Unlike the other Unix, Fuchsia and iOS don't use the libc to make any calls.
     if #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "emscripten",
@@ -198,7 +203,7 @@ cfg_if! {
     } else if #[cfg(target_os = "emscripten")] {
         #[path = "use_file.rs"] mod imp;
     } else if #[cfg(target_os = "freebsd")] {
-        #[path = "freebsd.rs"] mod imp;
+        #[path = "bsd_arandom.rs"] mod imp;
     } else if #[cfg(target_os = "fuchsia")] {
         #[path = "fuchsia.rs"] mod imp;
     } else if #[cfg(target_os = "haiku")] {
@@ -212,7 +217,7 @@ cfg_if! {
     } else if #[cfg(target_os = "macos")] {
         #[path = "macos.rs"] mod imp;
     } else if #[cfg(target_os = "netbsd")] {
-        #[path = "use_file.rs"] mod imp;
+        #[path = "bsd_arandom.rs"] mod imp;
     } else if #[cfg(target_os = "openbsd")] {
         #[path = "openbsd.rs"] mod imp;
     } else if #[cfg(target_os = "redox")] {
@@ -221,6 +226,8 @@ cfg_if! {
         #[path = "solaris_illumos.rs"] mod imp;
     } else if #[cfg(target_os = "wasi")] {
         #[path = "wasi.rs"] mod imp;
+    } else if #[cfg(target_os = "vxworks")] {
+        #[path = "vxworks.rs"] mod imp;
     } else if #[cfg(all(windows, getrandom_uwp))] {
         #[path = "windows_uwp.rs"] mod imp;
     } else if #[cfg(windows)] {
@@ -258,7 +265,9 @@ cfg_if! {
 /// source.
 ///
 /// This function returns an error on any failure, including partial reads. We
-/// make no guarantees regarding the contents of `dest` on error.
+/// make no guarantees regarding the contents of `dest` on error. If `dest` is
+/// empty, `getrandom` immediately returns success, making no calls to the
+/// underlying operating system.
 ///
 /// Blocking is possible, at least during early boot; see module documentation.
 ///
@@ -266,5 +275,8 @@ cfg_if! {
 /// significantly slower than a user-space CSPRNG; for the latter consider
 /// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
 pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> {
+    if dest.is_empty() {
+        return Ok(());
+    }
     imp::getrandom_inner(dest)
 }
diff --git a/src/use_file.rs b/src/use_file.rs
index 21e3534..d3adaf2 100644
--- a/src/use_file.rs
+++ b/src/use_file.rs
@@ -39,7 +39,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
 }
 
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux", target_os = "netbsd"))] {
+    if #[cfg(any(target_os = "android", target_os = "linux"))] {
         fn init_file() -> Option<libc::c_int> {
             // Poll /dev/random to make sure it is ok to read from /dev/urandom.
             let mut pfd = libc::pollfd {
diff --git a/src/util_libc.rs b/src/util_libc.rs
index d662fc6..5a05170 100644
--- a/src/util_libc.rs
+++ b/src/util_libc.rs
@@ -26,7 +26,10 @@ cfg_if! {
 }
 
 pub fn last_os_error() -> Error {
+    #[cfg(not(target_os = "vxworks"))]
     let errno = unsafe { *errno_location() };
+    #[cfg(target_os = "vxworks")]
+    let errno = unsafe { libc::errnoGet() };
     if errno > 0 {
         Error::from(NonZeroU32::new(errno as u32).unwrap())
     } else {
diff --git a/src/vxworks.rs b/src/vxworks.rs
new file mode 100644
index 0000000..a2fe52a
--- /dev/null
+++ b/src/vxworks.rs
@@ -0,0 +1,35 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Implementation for VxWorks
+use crate::error::{Error, RAND_SECURE_FATAL};
+use crate::util_libc::last_os_error;
+use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
+
+pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
+    static RNG_INIT: AtomicBool = AtomicBool::new(false);
+    while !RNG_INIT.load(Relaxed) {
+        let ret = unsafe { libc::randSecure() };
+        if ret < 0 {
+            return Err(RAND_SECURE_FATAL);
+        } else if ret > 0 {
+            RNG_INIT.store(true, Relaxed);
+            break;
+        }
+        unsafe { libc::usleep(10) };
+    }
+
+    // Prevent overflow of i32
+    for chunk in dest.chunks_mut(i32::max_value() as usize) {
+        let ret = unsafe { libc::randABytes(chunk.as_mut_ptr(), chunk.len() as i32) };
+        if ret != 0 {
+            return Err(last_os_error());
+        }
+    }
+    Ok(())
+}
diff --git a/src/wasi.rs b/src/wasi.rs
index a050afc..713c1ab 100644
--- a/src/wasi.rs
+++ b/src/wasi.rs
@@ -8,15 +8,12 @@
 
 //! Implementation for WASI
 use crate::Error;
-use core::num::NonZeroU32;
+use core::num;
 use wasi::wasi_unstable::random_get;
 
 pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
-    let ret = random_get(dest);
-    if let Some(code) = NonZeroU32::new(ret as u32) {
-        error!("WASI: random_get failed with return value {}", code);
-        Err(Error::from(code))
-    } else {
-        Ok(()) // Zero means success for WASI
-    }
+    random_get(dest).map_err(|e: num::NonZeroU16| {
+        // convert wasi's NonZeroU16 error into getrandom's NonZeroU32 error
+        num::NonZeroU32::new(e.get() as u32).unwrap().into()
+    })
 }
diff --git a/utils/ci/install_cargo_web.sh b/utils/ci/install_cargo_web.sh
deleted file mode 100755
index b35f069..0000000
--- a/utils/ci/install_cargo_web.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-set -euo pipefail
-IFS=$'\n\t'
-
-CARGO_WEB_RELEASE=$(curl -L -s -H 'Accept: application/json' https://github.com/koute/cargo-web/releases/latest)
-CARGO_WEB_VERSION=$(echo $CARGO_WEB_RELEASE | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/')
-CARGO_WEB_URL="https://github.com/koute/cargo-web/releases/download/$CARGO_WEB_VERSION/cargo-web-x86_64-unknown-linux-gnu.gz"
-
-echo "Downloading cargo-web from: $CARGO_WEB_URL"
-curl -L $CARGO_WEB_URL | gzip -d > cargo-web
-chmod +x cargo-web
-
-mkdir -p ~/.cargo/bin
-mv cargo-web ~/.cargo/bin


Test patch:
diff --git a/tests/mod.rs b/tests/common.rs
similarity index 80%
rename from tests/mod.rs
rename to tests/common.rs
index 66a3656..afefa03 100644
--- a/tests/mod.rs
+++ b/tests/common.rs
@@ -1,13 +1,19 @@
-extern crate getrandom;
+#[cfg(feature = "wasm-bindgen")]
+use wasm_bindgen_test::*;
 
 use getrandom::getrandom;
 
+#[cfg(feature = "test-in-browser")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
 #[test]
 fn test_zero() {
     // Test that APIs are happy with zero-length requests
     getrandom(&mut [0u8; 0]).unwrap();
 }
 
+#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
 #[test]
 fn test_diff() {
     let mut v1 = [0u8; 1000];
@@ -25,6 +31,7 @@ fn test_diff() {
     assert!(n_diff_bits >= v1.len() as u32);
 }
 
+#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
 #[test]
 fn test_huge() {
     let mut huge = [0u8; 100_000];
diff --git a/tests/wasm_bindgen/Cargo.toml b/tests/wasm_bindgen/Cargo.toml
deleted file mode 100644
index 4b735c8..0000000
--- a/tests/wasm_bindgen/Cargo.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[package]
-name = "getrandom_wasm_bindgen_test"
-description = "Minimal test crate for getrandom using wasm-bindgen"
-version = "0.1.0"
-authors = ["The Rand Project Developers"]
-publish = false
-license = "MIT/Apache-2.0"
-
-[lib]
-crate-type = ["cdylib"]
-
-[dependencies]
-getrandom = { path = "../..", features = ["wasm-bindgen"] }
-wasm-bindgen = "0.2"
-wasm-bindgen-test = "0.2"
diff --git a/tests/wasm_bindgen/js/index.js b/tests/wasm_bindgen/js/index.js
deleted file mode 100644
index d3390f6..0000000
--- a/tests/wasm_bindgen/js/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-'use strict';
-
-const getrandom_wasm_bindgen_test = require('./getrandom_wasm_bindgen_test');
-
-console.log(getrandom_wasm_bindgen_test.test_gen());
diff --git a/tests/wasm_bindgen/src/lib.rs b/tests/wasm_bindgen/src/lib.rs
deleted file mode 100644
index 3629cbb..0000000
--- a/tests/wasm_bindgen/src/lib.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Crate to test WASM with the `wasm-bindgen` lib.
-
-#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png")]
-
-extern crate getrandom;
-extern crate wasm_bindgen;
-extern crate wasm_bindgen_test;
-
-use std::slice;
-use wasm_bindgen::prelude::*;
-use wasm_bindgen_test::*;
-
-use getrandom::getrandom;
-
-#[wasm_bindgen]
-pub fn test_gen() -> i32 {
-    let mut int: i32 = 0;
-    unsafe {
-        let ptr = &mut int as *mut i32 as *mut u8;
-        let slice = slice::from_raw_parts_mut(ptr, 4);
-        getrandom(slice).unwrap();
-    }
-    int
-}
-
-#[wasm_bindgen_test]
-fn test_call() {
-    let mut buf = [0u8; 0];
-    getrandom(&mut buf).unwrap();
-}
-
-#[wasm_bindgen_test]
-fn test_diff() {
-    let mut v1 = [0u8; 1000];
-    getrandom(&mut v1).unwrap();
-
-    let mut v2 = [0u8; 1000];
-    getrandom(&mut v2).unwrap();
-
-    let mut n_diff_bits = 0;
-    for i in 0..v1.len() {
-        n_diff_bits += (v1[i] ^ v2[i]).count_ones();
-    }
-
-    // Check at least 1 bit per byte differs. p(failure) < 1e-1000 with random input.
-    assert!(n_diff_bits >= v1.len() as u32);
-}