diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/wasmparser-0.48.2 | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wasmparser-0.48.2')
45 files changed, 11959 insertions, 0 deletions
diff --git a/third_party/rust/wasmparser-0.48.2/.cargo-checksum.json b/third_party/rust/wasmparser-0.48.2/.cargo-checksum.json new file mode 100644 index 0000000000..fde1c00452 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CODE_OF_CONDUCT.md":"a13aaaf393818bd91207c618724d3fb74944ca5161201822a84af951bcf655ef","Cargo.lock":"dff00d1ea3a556fcd8d06289744bbbebc74d5190f40fbe4d73e4cfdb2ded27eb","Cargo.toml":"370cbad7937cff335bc9ebe3e73ec96cfe62c76f2f205bdb4dc7c7970879fdeb","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","ORG_CODE_OF_CONDUCT.md":"59c4c4435538496193cd73e89b2cd971d1011dba573158cf108abe6af6603e6b","README.md":"90c9b0e3dd91a63b6a8088b72200b3118fa0bbdf3320cd98609bd4cc4ef09902","SECURITY.md":"4d75afb09dd28eb5982e3a1f768ee398d90204669ceef3240a16b31dcf04148a","benches/benchmark.rs":"951abd671bd1a5a33d09379b023de000e89fc5f99a5950f0b3b2f571021aa402","compare-master.sh":"165490eab36ef4eceb2913a6c5cdeff479a05e1e0119a7f4551b03dbcda51ad4","examples/dump.rs":"de2bbdba75e21b9ff92b32697b3d9941f8695b8f7e3a8dee8fc5d7f4c3a0649c","examples/simple.rs":"c79ae542913e72cfcd03711543d173b2e8f62783e6c206459953bdb94dbb8c0c","format-all.sh":"6b02a40629ef3d2c0b9671222582a6217d526317a41262ae06c7a95de53bcbeb","src/binary_reader.rs":"2be55559e5336617dacdfd64be9170a6f81a08d9642f562174f4d821b89f0da4","src/lib.rs":"8bb5301d5d66746160466e38b0e956e14e4997bf2385431ec9070cea13fc632e","src/limits.rs":"34e5cda95fb67669011ba95ca60f48fc777f3e3fa279ff68a1f2a072032a4abd","src/module_resources.rs":"940d0d6a7972f512488cea953a15d128247cfc6bd7945be063219e281d65eb9b","src/operators_validator.rs":"b6631a0bdafc115dea886557fc60de9a6e9f6b5d51b4ed800f23645192a250b1","src/parser.rs":"2680fb91b237e273bc5c06af6ad44605843ad53d59edb6af66e3b133b4096167","src/primitives.rs":"ea2e1b35418aab82554688d2f15efd3ac6b90268d655bec536b20f73fc05de91","src/readers/code_section.rs":"2034c399b76428ac993c22f551f3c541b132d8b4ccc74e34f0043e25534d107b","src/readers/data_count_section.rs":"27ef37517b6beac21245008b14b5416b851c52d0af8e2ae85c1456674e1c9a9e","src/readers/data_section.rs":"e7e2a539d2d3049d4a8f68df9ea2f21d97e7061657bbd91845e1df3e9c1f2ebc","src/readers/element_section.rs":"e685af8a189f0cfa9f250c3fd221f9f14d20886f609c4c86a75c7408a106b8e0","src/readers/export_section.rs":"7c74f7a11406a95c162f6ad4f77aafd0b1eee309f33b69f06bea12b23925e143","src/readers/function_section.rs":"57c0479ba8d7f61908ed74e86cbc26553fdd6d2d952f032ce29385a39f82efd3","src/readers/global_section.rs":"5fa18bed0fffadcc2dbdcbaedbe4e4398992fd1ce9e611b0319333a7681082ac","src/readers/import_section.rs":"1db4bf7290d04783d5cf526050d025b15a1daaf2bd97fca1a92ecb873d48f641","src/readers/init_expr.rs":"7020c80013dad4518a5f969c3ab4d624b46d778f03e632871cf343964f63441c","src/readers/linking_section.rs":"9df71f3ee5356f0d273c099212213353080001e261ca697caddf6b847fb5af09","src/readers/memory_section.rs":"83212f86cfc40d18fb392e9234c880afdf443f4af38a727ba346f9c740ef8718","src/readers/mod.rs":"b9f835365b9b04411d7b141a3c9b52695e9bf8ef1f07094a10a18b901d0ac420","src/readers/module.rs":"2d272e6b0119361c99ea12f3288433c14b55a8e6336aedc961fe5cdbffe4b5e3","src/readers/name_section.rs":"297f57393d5fef745ec265438108aa6eb7ed2762c03c3beb539493612442f3da","src/readers/operators.rs":"53bf7ea87529980a3a3e1afd92ddf488ae4dc04a40cda39dbf548e4d20c8a55c","src/readers/producers_section.rs":"674f402fc4545c94487f827153871b37adab44ed5eff4070a436eb18e514023a","src/readers/reloc_section.rs":"0ef818a8b83a4542c4c29c23642436a92d3e7c37bc0248e817ed5a9d65ec38ce","src/readers/section_reader.rs":"3d2260449fa0455d710ba6d97810372ec36cba70722c10dd236c3a18ca0eb56f","src/readers/sourcemappingurl_section.rs":"ababe84d51e4817ad19f827aa2b5239578e7f202e5ec06dd688b618885138434","src/readers/start_section.rs":"3eeae00e1aa0fcb2e0d93b7b0eaac30a60d3f1431c71c589cd3f73adb363d532","src/readers/table_section.rs":"e564876825a7b31df2b5dc850279b523e26dc50a08da935cc8d635a49e809951","src/readers/type_section.rs":"2fa33a7b793f3bfa01c259b5dbc38633b7343931886ab41f0cb96dd78db3bf6e","src/tests.rs":"0f8b8aa5434a5a0a0ebe159d13c655a0fba532292f988704b4afee3f09e013e0","src/validator.rs":"e8b8f019891e1138ebf8dcc6331b193226db1f790bfd274de0fe56de92b3fae5","test-all.sh":"f36e3e9bf9c39456bab3ac170d3a09911becf2b7e0d0e2a58854ce1750da0d1f"},"package":"073da89bf1c84db000dd68ce660c1b4a08e3a2d28fd1e3394ab9e7abdde4a0f8"}
\ No newline at end of file diff --git a/third_party/rust/wasmparser-0.48.2/CODE_OF_CONDUCT.md b/third_party/rust/wasmparser-0.48.2/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..5c5ebdd259 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/CODE_OF_CONDUCT.md @@ -0,0 +1,49 @@ +# Contributor Covenant Code of Conduct + +*Note*: this Code of Conduct pertains to individuals' behavior. Please also see the [Organizational Code of Conduct][OCoC]. + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Bytecode Alliance CoC team at [report@bytecodealliance.org](mailto:report@bytecodealliance.org). The CoC team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The CoC team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the Bytecode Alliance's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[OCoC]: ORG_CODE_OF_CONDUCT.md +[homepage]: https://www.contributor-covenant.org +[version]: https://www.contributor-covenant.org/version/1/4/ diff --git a/third_party/rust/wasmparser-0.48.2/Cargo.lock b/third_party/rust/wasmparser-0.48.2/Cargo.lock new file mode 100644 index 0000000000..073870dbc5 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/Cargo.lock @@ -0,0 +1,532 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "atty" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bstr" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cast" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion-plot" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "leb128" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memoffset" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xoshiro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-automata" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tinytemplate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "2.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasmparser" +version = "0.48.2" +dependencies = [ + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wast 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wast" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "leb128 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" +"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" +"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" +"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" +"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" +"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" +"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum leb128 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6" +"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" +"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" +"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" +"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" +"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" +"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" +"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" +"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" +"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +"checksum wast 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed3db7029d1d31a15c10126e78b58e51781faefafbc8afb20fb01291b779984" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/rust/wasmparser-0.48.2/Cargo.toml b/third_party/rust/wasmparser-0.48.2/Cargo.toml new file mode 100644 index 0000000000..c96e977d25 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "wasmparser" +version = "0.48.2" +authors = ["Yury Delendik <ydelendik@mozilla.com>"] +exclude = ["fuzz/**/*", "tests/**/*", "testsuite/**/*"] +description = "A simple event-driven library for parsing WebAssembly binary files.\n" +keywords = ["parser", "WebAssembly", "wasm"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmparser.rs" + +[[bench]] +name = "benchmark" +harness = false +[dev-dependencies.criterion] +version = "0.3" + +[dev-dependencies.wast] +version = "6.0.0" + +[features] +deterministic = [] +[badges.travis-ci] +repository = "bytecodealliance/wasmparser.rs" diff --git a/third_party/rust/wasmparser-0.48.2/LICENSE b/third_party/rust/wasmparser-0.48.2/LICENSE new file mode 100644 index 0000000000..be1d7c438a --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/LICENSE @@ -0,0 +1,219 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. diff --git a/third_party/rust/wasmparser-0.48.2/ORG_CODE_OF_CONDUCT.md b/third_party/rust/wasmparser-0.48.2/ORG_CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..e05e40c3c4 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/ORG_CODE_OF_CONDUCT.md @@ -0,0 +1,139 @@ +# Bytecode Alliance Organizational Code of Conduct (OCoC) + +*Note*: this Code of Conduct pertains to organizations' behavior. Please also see the [Individual Code of Conduct](CODE_OF_CONDUCT.md). + +## Preamble + +The Bytecode Alliance (BA) welcomes involvement from organizations, +including commercial organizations. This document is an +*organizational* code of conduct, intended particularly to provide +guidance to commercial organizations. It is distinct from the +[Individual Code of Conduct (ICoC)](CODE_OF_CONDUCT.md), and does not +replace the ICoC. This OCoC applies to any group of people acting in +concert as a BA member or as a participant in BA activities, whether +or not that group is formally incorporated in some jurisdiction. + +The code of conduct described below is not a set of rigid rules, and +we did not write it to encompass every conceivable scenario that might +arise. For example, it is theoretically possible there would be times +when asserting patents is in the best interest of the BA community as +a whole. In such instances, consult with the BA, strive for +consensus, and interpret these rules with an intent that is generous +to the community the BA serves. + +While we may revise these guidelines from time to time based on +real-world experience, overall they are based on a simple principle: + +*Bytecode Alliance members should observe the distinction between + public community functions and private functions — especially + commercial ones — and should ensure that the latter support, or at + least do not harm, the former.* + +## Guidelines + + * **Do not cause confusion about Wasm standards or interoperability.** + + Having an interoperable WebAssembly core is a high priority for + the BA, and members should strive to preserve that core. It is fine + to develop additional non-standard features or APIs, but they + should always be clearly distinguished from the core interoperable + Wasm. + + Treat the WebAssembly name and any BA-associated names with + respect, and follow BA trademark and branding guidelines. If you + distribute a customized version of software originally produced by + the BA, or if you build a product or service using BA-derived + software, use names that clearly distinguish your work from the + original. (You should still provide proper attribution to the + original, of course, wherever such attribution would normally be + given.) + + Further, do not use the WebAssembly name or BA-associated names in + other public namespaces in ways that could cause confusion, e.g., + in company names, names of commercial service offerings, domain + names, publicly-visible social media accounts or online service + accounts, etc. It may sometimes be reasonable, however, to + register such a name in a new namespace and then immediately donate + control of that account to the BA, because that would help the project + maintain its identity. + + * **Do not restrict contributors.** If your company requires + employees or contractors to sign non-compete agreements, those + agreements must not prevent people from participating in the BA or + contributing to related projects. + + This does not mean that all non-compete agreements are incompatible + with this code of conduct. For example, a company may restrict an + employee's ability to solicit the company's customers. However, an + agreement must not block any form of technical or social + participation in BA activities, including but not limited to the + implementation of particular features. + + The accumulation of experience and expertise in individual persons, + who are ultimately free to direct their energy and attention as + they decide, is one of the most important drivers of progress in + open source projects. A company that limits this freedom may hinder + the success of the BA's efforts. + + * **Do not use patents as offensive weapons.** If any BA participant + prevents the adoption or development of BA technologies by + asserting its patents, that undermines the purpose of the + coalition. The collaboration fostered by the BA cannot include + members who act to undermine its work. + + * **Practice responsible disclosure** for security vulnerabilities. + Use designated, non-public reporting channels to disclose technical + vulnerabilities, and give the project a reasonable period to + respond, remediate, and patch. + + Vulnerability reporters may patch their company's own offerings, as + long as that patching does not significantly delay the reporting of + the vulnerability. Vulnerability information should never be used + for unilateral commercial advantage. Vendors may legitimately + compete on the speed and reliability with which they deploy + security fixes, but withholding vulnerability information damages + everyone in the long run by risking harm to the BA project's + reputation and to the security of all users. + + * **Respect the letter and spirit of open source practice.** While + there is not space to list here all possible aspects of standard + open source practice, some examples will help show what we mean: + + * Abide by all applicable open source license terms. Do not engage + in copyright violation or misattribution of any kind. + + * Do not claim others' ideas or designs as your own. + + * When others engage in publicly visible work (e.g., an upcoming + demo that is coordinated in a public issue tracker), do not + unilaterally announce early releases or early demonstrations of + that work ahead of their schedule in order to secure private + advantage (such as marketplace advantage) for yourself. + + The BA reserves the right to determine what constitutes good open + source practices and to take action as it deems appropriate to + encourage, and if necessary enforce, such practices. + +## Enforcement + +Instances of organizational behavior in violation of the OCoC may +be reported by contacting the Bytecode Alliance CoC team at +[report@bytecodealliance.org](mailto:report@bytecodealliance.org). The +CoC team will review and investigate all complaints, and will respond +in a way that it deems appropriate to the circumstances. The CoC team +is obligated to maintain confidentiality with regard to the reporter of +an incident. Further details of specific enforcement policies may be +posted separately. + +When the BA deems an organization in violation of this OCoC, the BA +will, at its sole discretion, determine what action to take. The BA +will decide what type, degree, and duration of corrective action is +needed, if any, before a violating organization can be considered for +membership (if it was not already a member) or can have its membership +reinstated (if it was a member and the BA canceled its membership due +to the violation). + +In practice, the BA's first approach will be to start a conversation, +with punitive enforcement used only as a last resort. Violations +often turn out to be unintentional and swiftly correctable with all +parties acting in good faith. diff --git a/third_party/rust/wasmparser-0.48.2/README.md b/third_party/rust/wasmparser-0.48.2/README.md new file mode 100644 index 0000000000..679d64b0a9 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/README.md @@ -0,0 +1,70 @@ +# The WebAssembly binary file decoder in Rust + +**A [Bytecode Alliance](https://bytecodealliance.org/) project** + +[![Build Status](https://travis-ci.org/yurydelendik/wasmparser.rs.svg?branch=master)](https://travis-ci.org/yurydelendik/wasmparser.rs) +[![crates.io link](https://img.shields.io/crates/v/wasmparser.svg)](https://crates.io/crates/wasmparser) + +The decoder library provides lightweight and fast decoding/parsing of WebAssembly binary files. + +The other goal is minimal memory footprint. For this reason, there is no AST or IR of WebAssembly data. + +See also its sibling at https://github.com/wasdk/wasmparser + + +## Documentation + +The documentation and examples can be found at the https://docs.rs/wasmparser/ + + +## Example + +```rust +use wasmparser::WasmDecoder; +use wasmparser::Parser; +use wasmparser::ParserState; + +fn get_name(bytes: &[u8]) -> &str { + str::from_utf8(bytes).ok().unwrap() +} + +fn main() { + let ref buf: Vec<u8> = read_wasm_bytes(); + let mut parser = Parser::new(buf); + loop { + let state = parser.read(); + match *state { + ParserState::BeginWasm { .. } => { + println!("====== Module"); + } + ParserState::ExportSectionEntry { field, ref kind, .. } => { + println!(" Export {} {:?}", get_name(field), kind); + } + ParserState::ImportSectionEntry { module, field, .. } => { + println!(" Import {}::{}", get_name(module), get_name(field)) + } + ParserState::EndWasm => break, + _ => ( /* println!(" Other {:?}", state) */ ) + } + } +} +``` + + +## Fuzzing + +To fuzz test wasmparser.rs, switch to a nightly Rust compiler and install [cargo-fuzz]: + +``` +cargo install cargo-fuzz +``` + +Then, from the root of the repository, run: + +``` +cargo fuzz run parse +``` + +If you want to use files as seeds for the fuzzer, add them to `fuzz/corpus/parse/` and restart cargo-fuzz. + +[cargo-fuzz]: https://github.com/rust-fuzz/cargo-fuzz diff --git a/third_party/rust/wasmparser-0.48.2/SECURITY.md b/third_party/rust/wasmparser-0.48.2/SECURITY.md new file mode 100644 index 0000000000..3513b9cb35 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/SECURITY.md @@ -0,0 +1,29 @@ +# Security Policy + +Building secure foundations for software development is at the core of what we do in the Bytecode Alliance. Contributions of external security researchers are a vital part of that. + +## Scope + +If you believe you've found a security issue in any website, service, or software owned or operated by the Bytecode Alliance, we encourage you to notify us. + +## How to Submit a Report + +To submit a vulnerability report to the Bytecode Alliance, please contact us at [security@bytecodealliance.org](mailto:security@bytecodealliance.org). Your submission will be reviewed and validated by a member of our security team. + +## Safe Harbor + +The Bytecode Alliance supports safe harbor for security researchers who: + +* Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services. +* Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information. +* Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third-party. + +We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you. + +Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy. + +## Preferences + +* Please provide detailed reports with reproducible steps and a clearly defined impact. +* Submit one vulnerability per report. +* Social engineering (e.g. phishing, vishing, smishing) is prohibited. diff --git a/third_party/rust/wasmparser-0.48.2/benches/benchmark.rs b/third_party/rust/wasmparser-0.48.2/benches/benchmark.rs new file mode 100644 index 0000000000..ee67ce85e3 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/benches/benchmark.rs @@ -0,0 +1,99 @@ +pub fn read_file_data(path: &PathBuf) -> Vec<u8> { + let mut data = Vec::new(); + let mut f = File::open(path).ok().unwrap(); + f.read_to_end(&mut data).unwrap(); + data +} + +const VALIDATOR_CONFIG: Option<ValidatingParserConfig> = Some(ValidatingParserConfig { + operator_config: OperatorValidatorConfig { + enable_threads: true, + enable_reference_types: true, + enable_simd: true, + enable_bulk_memory: true, + enable_multi_value: true, + }, +}); + +#[macro_use] +extern crate criterion; +extern crate wasmparser; + +use criterion::Criterion; +use wasmparser::{ + validate, OperatorValidatorConfig, Parser, ParserState, ValidatingParser, + ValidatingParserConfig, WasmDecoder, +}; + +use std::fs::{read_dir, File}; +use std::io::Read; +use std::path::PathBuf; + +fn read_all_wasm<'a, T>(mut d: T) +where + T: WasmDecoder<'a>, +{ + loop { + match *d.read() { + ParserState::Error(e) => panic!("unexpected error {:?}", e), + ParserState::EndWasm => return, + _ => (), + } + } +} + +fn it_works_benchmark(c: &mut Criterion) { + let mut data: Vec<Vec<u8>> = vec![]; + for entry in read_dir("tests").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + data.push(read_file_data(&dir.path())); + } + c.bench_function("it works benchmark", move |b| { + for d in &mut data { + b.iter(|| read_all_wasm(Parser::new(d.as_slice()))); + } + }); +} + +fn validator_not_fails_benchmark(c: &mut Criterion) { + let mut data: Vec<Vec<u8>> = vec![]; + for entry in read_dir("tests").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + data.push(read_file_data(&dir.path())); + } + c.bench_function("validator no fails benchmark", move |b| { + for d in &mut data { + b.iter(|| read_all_wasm(ValidatingParser::new(d.as_slice(), VALIDATOR_CONFIG))); + } + }); +} + +fn validate_benchmark(c: &mut Criterion) { + let mut data: Vec<Vec<u8>> = vec![vec![]]; + for entry in read_dir("tests").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + data.push(read_file_data(&dir.path())); + } + c.bench_function("validate benchmark", move |b| { + for d in &mut data { + b.iter(|| validate(&d, VALIDATOR_CONFIG)); + } + }); +} + +criterion_group!( + benchmark, + it_works_benchmark, + validator_not_fails_benchmark, + validate_benchmark +); +criterion_main!(benchmark); diff --git a/third_party/rust/wasmparser-0.48.2/compare-master.sh b/third_party/rust/wasmparser-0.48.2/compare-master.sh new file mode 100755 index 0000000000..e06c5e45a3 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/compare-master.sh @@ -0,0 +1,12 @@ +#/bin/bash + +# record current bench results +cargo bench --bench benchmark -- --noplot --save-baseline after + +# switch to master and record its bench results +git checkout master && \ +cargo bench --bench benchmark -- --noplot --save-baseline before + +# compare +cargo install critcmp --force && \ +critcmp before after diff --git a/third_party/rust/wasmparser-0.48.2/examples/dump.rs b/third_party/rust/wasmparser-0.48.2/examples/dump.rs new file mode 100644 index 0000000000..f0defb4000 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/examples/dump.rs @@ -0,0 +1,57 @@ +extern crate wasmparser; + +use std::env; +use std::fs::File; +use std::io; +use std::io::prelude::*; +use std::str; +use wasmparser::Parser; +use wasmparser::ParserState; +use wasmparser::WasmDecoder; + +fn main() { + let args = env::args().collect::<Vec<_>>(); + if args.len() != 2 { + println!("Usage: {} in.wasm", args[0]); + return; + } + + let buf: Vec<u8> = read_wasm(&args[1]).unwrap(); + let mut parser = Parser::new(&buf); + loop { + print!("0x{:08x}\t", parser.current_position()); + let state = parser.read(); + match *state { + ParserState::ExportSectionEntry { + field, + ref kind, + index, + } => { + println!( + "ExportSectionEntry {{ field: \"{}\", kind: {:?}, index: {} }}", + field, kind, index + ); + } + ParserState::ImportSectionEntry { + module, + field, + ref ty, + } => { + println!( + "ImportSectionEntry {{ module: \"{}\", field: \"{}\", ty: {:?} }}", + module, field, ty + ); + } + ParserState::EndWasm => break, + ParserState::Error(err) => panic!("Error: {:?}", err), + _ => println!("{:?}", state), + } + } +} + +fn read_wasm(file: &str) -> io::Result<Vec<u8>> { + let mut data = Vec::new(); + let mut f = File::open(file)?; + f.read_to_end(&mut data)?; + Ok(data) +} diff --git a/third_party/rust/wasmparser-0.48.2/examples/simple.rs b/third_party/rust/wasmparser-0.48.2/examples/simple.rs new file mode 100644 index 0000000000..132aa41f9f --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/examples/simple.rs @@ -0,0 +1,47 @@ +extern crate wasmparser; + +use std::env; +use std::fs::File; +use std::io; +use std::io::prelude::*; +use std::str; +use wasmparser::Parser; +use wasmparser::ParserState; +use wasmparser::WasmDecoder; + +fn main() { + let args = env::args().collect::<Vec<_>>(); + if args.len() != 2 { + println!("Usage: {} in.wasm", args[0]); + return; + } + + let buf: Vec<u8> = read_wasm(&args[1]).unwrap(); + let mut parser = Parser::new(&buf); + loop { + let state = parser.read(); + match *state { + ParserState::BeginWasm { .. } => { + println!("====== Module"); + } + ParserState::ExportSectionEntry { + field, ref kind, .. + } => { + println!(" Export {} {:?}", field, kind); + } + ParserState::ImportSectionEntry { module, field, .. } => { + println!(" Import {}::{}", module, field) + } + ParserState::EndWasm => break, + ParserState::Error(err) => panic!("Error: {:?}", err), + _ => ( /* println!(" Other {:?}", state); */ ), + } + } +} + +fn read_wasm(file: &str) -> io::Result<Vec<u8>> { + let mut data = Vec::new(); + let mut f = File::open(file)?; + f.read_to_end(&mut data)?; + Ok(data) +} diff --git a/third_party/rust/wasmparser-0.48.2/format-all.sh b/third_party/rust/wasmparser-0.48.2/format-all.sh new file mode 100755 index 0000000000..64c967ad24 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/format-all.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -euo pipefail + +# Format all sources using rustfmt. + +topdir=$(dirname "$0") +cd "$topdir" + +# Make sure we can find rustfmt. +export PATH="$PATH:$HOME/.cargo/bin" + +exec cargo +stable fmt --all -- "$@" diff --git a/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs b/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs new file mode 100644 index 0000000000..3cb6bdc1f1 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/binary_reader.rs @@ -0,0 +1,1775 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::boxed::Box; +use std::convert::TryInto; +use std::str; +use std::vec::Vec; + +use crate::limits::{ + MAX_WASM_FUNCTION_LOCALS, MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS, + MAX_WASM_FUNCTION_SIZE, MAX_WASM_STRING_SIZE, +}; + +use crate::primitives::{ + BinaryReaderError, BrTable, CustomSectionKind, ExternalKind, FuncType, GlobalType, Ieee32, + Ieee64, LinkingType, MemoryImmediate, MemoryType, NameType, Operator, RelocType, + ResizableLimits, Result, SIMDLaneIndex, SectionCode, TableType, Type, TypeOrFuncType, V128, +}; + +const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE; + +fn is_name(name: &str, expected: &'static str) -> bool { + name == expected +} + +fn is_name_prefix(name: &str, prefix: &'static str) -> bool { + name.starts_with(prefix) +} + +const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm"; +const WASM_EXPERIMENTAL_VERSION: u32 = 0xd; +const WASM_SUPPORTED_VERSION: u32 = 0x1; + +pub(crate) struct SectionHeader<'a> { + pub code: SectionCode<'a>, + pub payload_start: usize, + pub payload_len: usize, +} + +/// Bytecode range in the WebAssembly module. +#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Range { + /// The start bound of the range. + pub start: usize, + /// The end bound of the range. + pub end: usize, +} + +impl Range { + /// Constructs a new instance of `Range`. + /// + /// # Panics + /// If `start` is greater than `end`. + pub fn new(start: usize, end: usize) -> Range { + assert!(start <= end); + Range { start, end } + } + + /// Returns a new slice between `start` and `end - 1` from `data`. + pub fn slice<'a>(&self, data: &'a [u8]) -> &'a [u8] { + &data[self.start..self.end] + } +} + +/// A binary reader of the WebAssembly structures and types. +#[derive(Clone, Debug)] +pub struct BinaryReader<'a> { + pub(crate) buffer: &'a [u8], + pub(crate) position: usize, + pub(crate) original_offset: usize, +} + +impl<'a> BinaryReader<'a> { + /// Constructs `BinaryReader` type. + /// + /// # Examples + /// ``` + /// let fn_body = &vec![0x41, 0x00, 0x10, 0x00, 0x0B]; + /// let mut reader = wasmparser::BinaryReader::new(fn_body); + /// while !reader.eof() { + /// let op = reader.read_operator(); + /// println!("{:?}", op) + /// } + /// ``` + pub fn new(data: &[u8]) -> BinaryReader { + BinaryReader { + buffer: data, + position: 0, + original_offset: 0, + } + } + + /// Constructs a `BinaryReader` with an explicit starting offset. + pub fn new_with_offset(data: &[u8], original_offset: usize) -> BinaryReader { + BinaryReader { + buffer: data, + position: 0, + original_offset, + } + } + + pub fn original_position(&self) -> usize { + self.original_offset + self.position + } + + /// Returns a range from the starting offset to the end of the buffer. + pub fn range(&self) -> Range { + Range { + start: self.original_offset, + end: self.original_offset + self.buffer.len(), + } + } + + fn ensure_has_byte(&self) -> Result<()> { + if self.position < self.buffer.len() { + Ok(()) + } else { + Err(BinaryReaderError { + message: "Unexpected EOF", + offset: self.original_position(), + }) + } + } + + fn ensure_has_bytes(&self, len: usize) -> Result<()> { + if self.position + len <= self.buffer.len() { + Ok(()) + } else { + Err(BinaryReaderError { + message: "Unexpected EOF", + offset: self.original_position(), + }) + } + } + + fn read_var_u1(&mut self) -> Result<u32> { + let b = self.read_u8()?; + if (b & 0xFE) != 0 { + return Err(BinaryReaderError { + message: "Invalid var_u1", + offset: self.original_position() - 1, + }); + } + Ok(b) + } + + fn read_var_i7(&mut self) -> Result<i32> { + let b = self.read_u8()?; + if (b & 0x80) != 0 { + return Err(BinaryReaderError { + message: "Invalid var_i7", + offset: self.original_position() - 1, + }); + } + Ok((b << 25) as i32 >> 25) + } + + pub(crate) fn read_var_u7(&mut self) -> Result<u32> { + let b = self.read_u8()?; + if (b & 0x80) != 0 { + return Err(BinaryReaderError { + message: "Invalid var_u7", + offset: self.original_position() - 1, + }); + } + Ok(b) + } + + pub fn read_type(&mut self) -> Result<Type> { + let code = self.read_var_i7()?; + match code { + -0x01 => Ok(Type::I32), + -0x02 => Ok(Type::I64), + -0x03 => Ok(Type::F32), + -0x04 => Ok(Type::F64), + -0x05 => Ok(Type::V128), + -0x10 => Ok(Type::AnyFunc), + -0x11 => Ok(Type::AnyRef), + -0x12 => Ok(Type::NullRef), + -0x20 => Ok(Type::Func), + -0x40 => Ok(Type::EmptyBlockType), + _ => Err(BinaryReaderError { + message: "Invalid type", + offset: self.original_position() - 1, + }), + } + } + + /// Read a `count` indicating the number of times to call `read_local_decl`. + pub fn read_local_count(&mut self) -> Result<usize> { + let local_count = self.read_var_u32()? as usize; + if local_count > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "local_count is out of bounds", + offset: self.original_position() - 1, + }); + } + Ok(local_count) + } + + /// Read a `(count, value_type)` declaration of local variables of the same type. + pub fn read_local_decl(&mut self, locals_total: &mut usize) -> Result<(u32, Type)> { + let count = self.read_var_u32()?; + let value_type = self.read_type()?; + *locals_total = + locals_total + .checked_add(count as usize) + .ok_or_else(|| BinaryReaderError { + message: "locals_total is out of bounds", + offset: self.original_position() - 1, + })?; + if *locals_total > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals_total is out of bounds", + offset: self.original_position() - 1, + }); + } + Ok((count, value_type)) + } + + pub(crate) fn read_external_kind(&mut self) -> Result<ExternalKind> { + let code = self.read_u8()?; + match code { + 0 => Ok(ExternalKind::Function), + 1 => Ok(ExternalKind::Table), + 2 => Ok(ExternalKind::Memory), + 3 => Ok(ExternalKind::Global), + _ => Err(BinaryReaderError { + message: "Invalid external kind", + offset: self.original_position() - 1, + }), + } + } + + pub(crate) fn read_func_type(&mut self) -> Result<FuncType> { + let form = self.read_type()?; + let params_len = self.read_var_u32()? as usize; + if params_len > MAX_WASM_FUNCTION_PARAMS { + return Err(BinaryReaderError { + message: "function params size is out of bound", + offset: self.original_position() - 1, + }); + } + let mut params: Vec<Type> = Vec::with_capacity(params_len); + for _ in 0..params_len { + params.push(self.read_type()?); + } + let returns_len = self.read_var_u32()? as usize; + if returns_len > MAX_WASM_FUNCTION_RETURNS { + return Err(BinaryReaderError { + message: "function returns size is out of bound", + offset: self.original_position() - 1, + }); + } + let mut returns: Vec<Type> = Vec::with_capacity(returns_len); + for _ in 0..returns_len { + returns.push(self.read_type()?); + } + Ok(FuncType { + form, + params: params.into_boxed_slice(), + returns: returns.into_boxed_slice(), + }) + } + + fn read_resizable_limits(&mut self, max_present: bool) -> Result<ResizableLimits> { + let initial = self.read_var_u32()?; + let maximum = if max_present { + Some(self.read_var_u32()?) + } else { + None + }; + Ok(ResizableLimits { initial, maximum }) + } + + pub(crate) fn read_table_type(&mut self) -> Result<TableType> { + let element_type = self.read_type()?; + let flags = self.read_var_u32()?; + if (flags & !0x1) != 0 { + return Err(BinaryReaderError { + message: "invalid table resizable limits flags", + offset: self.original_position() - 1, + }); + } + let limits = self.read_resizable_limits((flags & 0x1) != 0)?; + Ok(TableType { + element_type, + limits, + }) + } + + pub(crate) fn read_memory_type(&mut self) -> Result<MemoryType> { + let flags = self.read_var_u32()?; + if (flags & !0x3) != 0 { + return Err(BinaryReaderError { + message: "invalid table resizable limits flags", + offset: self.original_position() - 1, + }); + } + let limits = self.read_resizable_limits((flags & 0x1) != 0)?; + let shared = (flags & 0x2) != 0; + Ok(MemoryType { limits, shared }) + } + + pub(crate) fn read_global_type(&mut self) -> Result<GlobalType> { + Ok(GlobalType { + content_type: self.read_type()?, + mutable: self.read_var_u1()? != 0, + }) + } + + fn read_memarg(&mut self) -> Result<MemoryImmediate> { + Ok(MemoryImmediate { + flags: self.read_var_u32()?, + offset: self.read_var_u32()?, + }) + } + + pub(crate) fn read_section_code(&mut self, id: u32, offset: usize) -> Result<SectionCode<'a>> { + match id { + 0 => { + let name = self.read_string()?; + let kind = if is_name(name, "name") { + CustomSectionKind::Name + } else if is_name(name, "producers") { + CustomSectionKind::Producers + } else if is_name(name, "sourceMappingURL") { + CustomSectionKind::SourceMappingURL + } else if is_name_prefix(name, "reloc.") { + CustomSectionKind::Reloc + } else if is_name(name, "linking") { + CustomSectionKind::Linking + } else { + CustomSectionKind::Unknown + }; + Ok(SectionCode::Custom { name, kind }) + } + 1 => Ok(SectionCode::Type), + 2 => Ok(SectionCode::Import), + 3 => Ok(SectionCode::Function), + 4 => Ok(SectionCode::Table), + 5 => Ok(SectionCode::Memory), + 6 => Ok(SectionCode::Global), + 7 => Ok(SectionCode::Export), + 8 => Ok(SectionCode::Start), + 9 => Ok(SectionCode::Element), + 10 => Ok(SectionCode::Code), + 11 => Ok(SectionCode::Data), + 12 => Ok(SectionCode::DataCount), + _ => Err(BinaryReaderError { + message: "Invalid section code", + offset, + }), + } + } + + fn read_br_table(&mut self) -> Result<BrTable<'a>> { + let targets_len = self.read_var_u32()? as usize; + if targets_len > MAX_WASM_BR_TABLE_SIZE { + return Err(BinaryReaderError { + message: "br_table size is out of bound", + offset: self.original_position() - 1, + }); + } + let start = self.position; + for _ in 0..targets_len { + self.skip_var_32()?; + } + self.skip_var_32()?; + Ok(BrTable { + buffer: &self.buffer[start..self.position], + cnt: targets_len as usize, + }) + } + + /// Returns whether the `BinaryReader` has reached the end of the file. + pub fn eof(&self) -> bool { + self.position >= self.buffer.len() + } + + /// Returns the `BinaryReader`'s current position. + pub fn current_position(&self) -> usize { + self.position + } + + /// Returns the number of bytes remaining in the `BinaryReader`. + pub fn bytes_remaining(&self) -> usize { + self.buffer.len() - self.position + } + + /// Advances the `BinaryReader` `size` bytes, and returns a slice from the + /// current position of `size` length. + /// + /// # Errors + /// If `size` exceeds the remaining length in `BinaryReader`. + pub fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> { + self.ensure_has_bytes(size)?; + let start = self.position; + self.position += size; + Ok(&self.buffer[start..self.position]) + } + + /// Advances the `BinaryReader` four bytes and returns a `u32`. + /// # Errors + /// If `BinaryReader` has less than four bytes remaining. + pub fn read_u32(&mut self) -> Result<u32> { + self.ensure_has_bytes(4)?; + let word = u32::from_le_bytes( + self.buffer[self.position..self.position + 4] + .try_into() + .unwrap(), + ); + self.position += 4; + Ok(word) + } + + /// Advances the `BinaryReader` eight bytes and returns a `u64`. + /// # Errors + /// If `BinaryReader` has less than eight bytes remaining. + pub fn read_u64(&mut self) -> Result<u64> { + self.ensure_has_bytes(8)?; + let word = u64::from_le_bytes( + self.buffer[self.position..self.position + 8] + .try_into() + .unwrap(), + ); + self.position += 8; + Ok(word) + } + + /// Advances the `BinaryReader` a single byte, and returns the data as + /// a `u32`. + /// # Errors + /// If `BinaryReader` has no bytes remaining. + pub fn read_u8(&mut self) -> Result<u32> { + self.ensure_has_byte()?; + let b = u32::from(self.buffer[self.position]); + self.position += 1; + Ok(b) + } + + /// Advances the `BinaryReader` up to two bytes to parse a variable + /// length integer as a `u8`. + /// # Errors + /// If `BinaryReader` has less than one or two bytes remaining, or the + /// integer is larger than eight bits. + pub fn read_var_u8(&mut self) -> Result<u32> { + // Optimization for single byte i32. + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(byte); + } + + let result = (self.read_u8()? << 7) | (byte & 0x7F); + if result >= 0x100 { + return Err(BinaryReaderError { + message: "Invalid var_u8", + offset: self.original_position() - 1, + }); + } + Ok(result) + } + + /// Advances the `BinaryReader` up to four bytes to parse a variable + /// length integer as a `u32`. + /// # Errors + /// If `BinaryReader` has less than one or up to four bytes remaining, or + /// the integer is larger than 32 bits. + pub fn read_var_u32(&mut self) -> Result<u32> { + // Optimization for single byte i32. + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(byte); + } + + let mut result = byte & 0x7F; + let mut shift = 7; + loop { + let byte = self.read_u8()?; + result |= ((byte & 0x7F) as u32) << shift; + if shift >= 25 && (byte >> (32 - shift)) != 0 { + // The continuation bit or unused bits are set. + return Err(BinaryReaderError { + message: "Invalid var_u32", + offset: self.original_position() - 1, + }); + } + shift += 7; + if (byte & 0x80) == 0 { + break; + } + } + Ok(result) + } + + /// Advances the `BinaryReader` up to four bytes over a variable length 32 + /// bit integer, discarding the result. + /// # Errors + /// If `BinaryReader` has less than one or up to four bytes remaining, or + /// the integer is larger than 32 bits. + pub fn skip_var_32(&mut self) -> Result<()> { + for _ in 0..5 { + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(()); + } + } + Err(BinaryReaderError { + message: "Invalid var_32", + offset: self.original_position() - 1, + }) + } + + /// Alias method for `BinaryReader::skip_var_u32`. + pub fn skip_type(&mut self) -> Result<()> { + self.skip_var_32() + } + + /// Advances the `BinaryReader` `len` bytes, skipping the result. + /// # Errors + /// If `BinaryReader` has less than `len` bytes remaining. + pub fn skip_bytes(&mut self, len: usize) -> Result<()> { + self.ensure_has_bytes(len)?; + self.position += len; + Ok(()) + } + + /// Advances the `BinaryReader` past a WebAssembly string. This method does + /// not perform any utf-8 validation. + /// # Errors + /// If `BinaryReader` has less than four bytes, the string's length exceeds + /// the remaining bytes, or the string length + /// exceeds `limits::MAX_WASM_STRING_SIZE`. + pub fn skip_string(&mut self) -> Result<()> { + let len = self.read_var_u32()? as usize; + if len > MAX_WASM_STRING_SIZE { + return Err(BinaryReaderError { + message: "string size in out of bounds", + offset: self.original_position() - 1, + }); + } + self.skip_bytes(len) + } + + pub(crate) fn skip_to(&mut self, position: usize) { + assert!( + self.position <= position && position <= self.buffer.len(), + "skip_to allowed only into region past current position" + ); + self.position = position; + } + + /// Advances the `BinaryReader` up to four bytes to parse a variable + /// length integer as a `i32`. + /// # Errors + /// If `BinaryReader` has less than one or up to four bytes remaining, or + /// the integer is larger than 32 bits. + pub fn read_var_i32(&mut self) -> Result<i32> { + // Optimization for single byte i32. + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(((byte as i32) << 25) >> 25); + } + + let mut result = (byte & 0x7F) as i32; + let mut shift = 7; + loop { + let byte = self.read_u8()?; + result |= ((byte & 0x7F) as i32) << shift; + if shift >= 25 { + let continuation_bit = (byte & 0x80) != 0; + let sign_and_unused_bit = (byte << 1) as i8 >> (32 - shift); + if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) { + return Err(BinaryReaderError { + message: "Invalid var_i32", + offset: self.original_position() - 1, + }); + } + return Ok(result); + } + shift += 7; + if (byte & 0x80) == 0 { + break; + } + } + let ashift = 32 - shift; + Ok((result << ashift) >> ashift) + } + + /// Advances the `BinaryReader` up to four bytes to parse a variable + /// length integer as a signed 33 bit integer, returned as a `i64`. + /// # Errors + /// If `BinaryReader` has less than one or up to five bytes remaining, or + /// the integer is larger than 33 bits. + pub fn read_var_s33(&mut self) -> Result<i64> { + // Optimization for single byte. + let byte = self.read_u8()?; + if (byte & 0x80) == 0 { + return Ok(((byte as i8) << 1) as i64 >> 1); + } + + let mut result = (byte & 0x7F) as i64; + let mut shift = 7; + loop { + let byte = self.read_u8()?; + result |= ((byte & 0x7F) as i64) << shift; + if shift >= 25 { + let continuation_bit = (byte & 0x80) != 0; + let sign_and_unused_bit = (byte << 1) as i8 >> (33 - shift); + if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) { + return Err(BinaryReaderError { + message: "Invalid var_s33", + offset: self.original_position() - 1, + }); + } + return Ok(result); + } + shift += 7; + if (byte & 0x80) == 0 { + break; + } + } + let ashift = 64 - shift; + Ok((result << ashift) >> ashift) + } + + /// Advances the `BinaryReader` up to eight bytes to parse a variable + /// length integer as a 64 bit integer, returned as a `i64`. + /// # Errors + /// If `BinaryReader` has less than one or up to eight bytes remaining, or + /// the integer is larger than 64 bits. + pub fn read_var_i64(&mut self) -> Result<i64> { + let mut result: i64 = 0; + let mut shift = 0; + loop { + let byte = self.read_u8()?; + result |= i64::from(byte & 0x7F) << shift; + if shift >= 57 { + let continuation_bit = (byte & 0x80) != 0; + let sign_and_unused_bit = ((byte << 1) as i8) >> (64 - shift); + if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) { + return Err(BinaryReaderError { + message: "Invalid var_i64", + offset: self.original_position() - 1, + }); + } + return Ok(result); + } + shift += 7; + if (byte & 0x80) == 0 { + break; + } + } + let ashift = 64 - shift; + Ok((result << ashift) >> ashift) + } + + /// Advances the `BinaryReader` up to four bytes to parse a variable + /// length integer as a 32 bit floating point integer, returned as `Ieee32`. + /// # Errors + /// If `BinaryReader` has less than one or up to four bytes remaining, or + /// the integer is larger than 32 bits. + pub fn read_f32(&mut self) -> Result<Ieee32> { + let value = self.read_u32()?; + Ok(Ieee32(value)) + } + + /// Advances the `BinaryReader` up to four bytes to parse a variable + /// length integer as a 32 bit floating point integer, returned as `Ieee32`. + /// # Errors + /// If `BinaryReader` has less than one or up to four bytes remaining, or + /// the integer is larger than 32 bits. + pub fn read_f64(&mut self) -> Result<Ieee64> { + let value = self.read_u64()?; + Ok(Ieee64(value)) + } + + /// Reads a WebAssembly string from the module. + /// # Errors + /// If `BinaryReader` has less than up to four bytes remaining, the string's + /// length exceeds the remaining bytes, the string's length exceeds + /// `limits::MAX_WASM_STRING_SIZE`, or the string contains invalid utf-8. + pub fn read_string(&mut self) -> Result<&'a str> { + let len = self.read_var_u32()? as usize; + if len > MAX_WASM_STRING_SIZE { + return Err(BinaryReaderError { + message: "string size in out of bounds", + offset: self.original_position() - 1, + }); + } + let bytes = self.read_bytes(len)?; + str::from_utf8(bytes).map_err(|_| BinaryReaderError { + message: "non-utf8 string", + offset: self.original_position() - 1, + }) + } + + fn read_memarg_of_align(&mut self, max_align: u32) -> Result<MemoryImmediate> { + let imm = self.read_memarg()?; + if imm.flags > max_align { + return Err(BinaryReaderError { + message: "Unexpected memarg alignment", + offset: self.original_position() - 1, + }); + } + Ok(imm) + } + + fn read_0xfe_operator(&mut self) -> Result<Operator<'a>> { + let code = self.read_u8()? as u8; + Ok(match code { + 0x00 => Operator::AtomicNotify { + memarg: self.read_memarg_of_align(2)?, + }, + 0x01 => Operator::I32AtomicWait { + memarg: self.read_memarg_of_align(2)?, + }, + 0x02 => Operator::I64AtomicWait { + memarg: self.read_memarg_of_align(3)?, + }, + 0x03 => Operator::AtomicFence { + flags: self.read_u8()? as u8, + }, + 0x10 => Operator::I32AtomicLoad { + memarg: self.read_memarg_of_align(2)?, + }, + 0x11 => Operator::I64AtomicLoad { + memarg: self.read_memarg_of_align(3)?, + }, + 0x12 => Operator::I32AtomicLoad8U { + memarg: self.read_memarg_of_align(0)?, + }, + 0x13 => Operator::I32AtomicLoad16U { + memarg: self.read_memarg_of_align(1)?, + }, + 0x14 => Operator::I64AtomicLoad8U { + memarg: self.read_memarg_of_align(0)?, + }, + 0x15 => Operator::I64AtomicLoad16U { + memarg: self.read_memarg_of_align(1)?, + }, + 0x16 => Operator::I64AtomicLoad32U { + memarg: self.read_memarg_of_align(2)?, + }, + 0x17 => Operator::I32AtomicStore { + memarg: self.read_memarg_of_align(2)?, + }, + 0x18 => Operator::I64AtomicStore { + memarg: self.read_memarg_of_align(3)?, + }, + 0x19 => Operator::I32AtomicStore8 { + memarg: self.read_memarg_of_align(0)?, + }, + 0x1a => Operator::I32AtomicStore16 { + memarg: self.read_memarg_of_align(1)?, + }, + 0x1b => Operator::I64AtomicStore8 { + memarg: self.read_memarg_of_align(0)?, + }, + 0x1c => Operator::I64AtomicStore16 { + memarg: self.read_memarg_of_align(1)?, + }, + 0x1d => Operator::I64AtomicStore32 { + memarg: self.read_memarg_of_align(2)?, + }, + 0x1e => Operator::I32AtomicRmwAdd { + memarg: self.read_memarg_of_align(2)?, + }, + 0x1f => Operator::I64AtomicRmwAdd { + memarg: self.read_memarg_of_align(3)?, + }, + 0x20 => Operator::I32AtomicRmw8AddU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x21 => Operator::I32AtomicRmw16AddU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x22 => Operator::I64AtomicRmw8AddU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x23 => Operator::I64AtomicRmw16AddU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x24 => Operator::I64AtomicRmw32AddU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x25 => Operator::I32AtomicRmwSub { + memarg: self.read_memarg_of_align(2)?, + }, + 0x26 => Operator::I64AtomicRmwSub { + memarg: self.read_memarg_of_align(3)?, + }, + 0x27 => Operator::I32AtomicRmw8SubU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x28 => Operator::I32AtomicRmw16SubU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x29 => Operator::I64AtomicRmw8SubU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x2a => Operator::I64AtomicRmw16SubU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x2b => Operator::I64AtomicRmw32SubU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x2c => Operator::I32AtomicRmwAnd { + memarg: self.read_memarg_of_align(2)?, + }, + 0x2d => Operator::I64AtomicRmwAnd { + memarg: self.read_memarg_of_align(3)?, + }, + 0x2e => Operator::I32AtomicRmw8AndU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x2f => Operator::I32AtomicRmw16AndU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x30 => Operator::I64AtomicRmw8AndU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x31 => Operator::I64AtomicRmw16AndU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x32 => Operator::I64AtomicRmw32AndU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x33 => Operator::I32AtomicRmwOr { + memarg: self.read_memarg_of_align(2)?, + }, + 0x34 => Operator::I64AtomicRmwOr { + memarg: self.read_memarg_of_align(3)?, + }, + 0x35 => Operator::I32AtomicRmw8OrU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x36 => Operator::I32AtomicRmw16OrU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x37 => Operator::I64AtomicRmw8OrU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x38 => Operator::I64AtomicRmw16OrU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x39 => Operator::I64AtomicRmw32OrU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x3a => Operator::I32AtomicRmwXor { + memarg: self.read_memarg_of_align(2)?, + }, + 0x3b => Operator::I64AtomicRmwXor { + memarg: self.read_memarg_of_align(3)?, + }, + 0x3c => Operator::I32AtomicRmw8XorU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x3d => Operator::I32AtomicRmw16XorU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x3e => Operator::I64AtomicRmw8XorU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x3f => Operator::I64AtomicRmw16XorU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x40 => Operator::I64AtomicRmw32XorU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x41 => Operator::I32AtomicRmwXchg { + memarg: self.read_memarg_of_align(2)?, + }, + 0x42 => Operator::I64AtomicRmwXchg { + memarg: self.read_memarg_of_align(3)?, + }, + 0x43 => Operator::I32AtomicRmw8XchgU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x44 => Operator::I32AtomicRmw16XchgU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x45 => Operator::I64AtomicRmw8XchgU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x46 => Operator::I64AtomicRmw16XchgU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x47 => Operator::I64AtomicRmw32XchgU { + memarg: self.read_memarg_of_align(2)?, + }, + 0x48 => Operator::I32AtomicRmwCmpxchg { + memarg: self.read_memarg_of_align(2)?, + }, + 0x49 => Operator::I64AtomicRmwCmpxchg { + memarg: self.read_memarg_of_align(3)?, + }, + 0x4a => Operator::I32AtomicRmw8CmpxchgU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x4b => Operator::I32AtomicRmw16CmpxchgU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x4c => Operator::I64AtomicRmw8CmpxchgU { + memarg: self.read_memarg_of_align(0)?, + }, + 0x4d => Operator::I64AtomicRmw16CmpxchgU { + memarg: self.read_memarg_of_align(1)?, + }, + 0x4e => Operator::I64AtomicRmw32CmpxchgU { + memarg: self.read_memarg_of_align(2)?, + }, + + _ => { + return Err(BinaryReaderError { + message: "Unknown 0xFE opcode", + offset: self.original_position() - 1, + }); + } + }) + } + + fn read_blocktype(&mut self) -> Result<TypeOrFuncType> { + let position = self.position; + if let Ok(ty) = self.read_type() { + Ok(TypeOrFuncType::Type(ty)) + } else { + self.position = position; + let idx = self.read_var_s33()?; + if idx < 0 || idx > (std::u32::MAX as i64) { + return Err(BinaryReaderError { + message: "invalid function type", + offset: position, + }); + } + Ok(TypeOrFuncType::FuncType(idx as u32)) + } + } + + /// Reads the next available `Operator`. + /// # Errors + /// If `BinaryReader` has less bytes remaining than required to parse + /// the `Operator`. + pub fn read_operator(&mut self) -> Result<Operator<'a>> { + let code = self.read_u8()? as u8; + Ok(match code { + 0x00 => Operator::Unreachable, + 0x01 => Operator::Nop, + 0x02 => Operator::Block { + ty: self.read_blocktype()?, + }, + 0x03 => Operator::Loop { + ty: self.read_blocktype()?, + }, + 0x04 => Operator::If { + ty: self.read_blocktype()?, + }, + 0x05 => Operator::Else, + 0x0b => Operator::End, + 0x0c => Operator::Br { + relative_depth: self.read_var_u32()?, + }, + 0x0d => Operator::BrIf { + relative_depth: self.read_var_u32()?, + }, + 0x0e => Operator::BrTable { + table: self.read_br_table()?, + }, + 0x0f => Operator::Return, + 0x10 => Operator::Call { + function_index: self.read_var_u32()?, + }, + 0x11 => Operator::CallIndirect { + index: self.read_var_u32()?, + table_index: self.read_var_u32()?, + }, + 0x1a => Operator::Drop, + 0x1b => Operator::Select, + 0x1c => { + let results = self.read_var_u32()?; + if results != 1 { + return Err(BinaryReaderError { + message: "bad number of results", + offset: self.position, + }); + } + Operator::TypedSelect { + ty: self.read_type()?, + } + } + 0x20 => Operator::LocalGet { + local_index: self.read_var_u32()?, + }, + 0x21 => Operator::LocalSet { + local_index: self.read_var_u32()?, + }, + 0x22 => Operator::LocalTee { + local_index: self.read_var_u32()?, + }, + 0x23 => Operator::GlobalGet { + global_index: self.read_var_u32()?, + }, + 0x24 => Operator::GlobalSet { + global_index: self.read_var_u32()?, + }, + 0x25 => Operator::TableGet { + table: self.read_var_u32()?, + }, + 0x26 => Operator::TableSet { + table: self.read_var_u32()?, + }, + 0x28 => Operator::I32Load { + memarg: self.read_memarg()?, + }, + 0x29 => Operator::I64Load { + memarg: self.read_memarg()?, + }, + 0x2a => Operator::F32Load { + memarg: self.read_memarg()?, + }, + 0x2b => Operator::F64Load { + memarg: self.read_memarg()?, + }, + 0x2c => Operator::I32Load8S { + memarg: self.read_memarg()?, + }, + 0x2d => Operator::I32Load8U { + memarg: self.read_memarg()?, + }, + 0x2e => Operator::I32Load16S { + memarg: self.read_memarg()?, + }, + 0x2f => Operator::I32Load16U { + memarg: self.read_memarg()?, + }, + 0x30 => Operator::I64Load8S { + memarg: self.read_memarg()?, + }, + 0x31 => Operator::I64Load8U { + memarg: self.read_memarg()?, + }, + 0x32 => Operator::I64Load16S { + memarg: self.read_memarg()?, + }, + 0x33 => Operator::I64Load16U { + memarg: self.read_memarg()?, + }, + 0x34 => Operator::I64Load32S { + memarg: self.read_memarg()?, + }, + 0x35 => Operator::I64Load32U { + memarg: self.read_memarg()?, + }, + 0x36 => Operator::I32Store { + memarg: self.read_memarg()?, + }, + 0x37 => Operator::I64Store { + memarg: self.read_memarg()?, + }, + 0x38 => Operator::F32Store { + memarg: self.read_memarg()?, + }, + 0x39 => Operator::F64Store { + memarg: self.read_memarg()?, + }, + 0x3a => Operator::I32Store8 { + memarg: self.read_memarg()?, + }, + 0x3b => Operator::I32Store16 { + memarg: self.read_memarg()?, + }, + 0x3c => Operator::I64Store8 { + memarg: self.read_memarg()?, + }, + 0x3d => Operator::I64Store16 { + memarg: self.read_memarg()?, + }, + 0x3e => Operator::I64Store32 { + memarg: self.read_memarg()?, + }, + 0x3f => Operator::MemorySize { + reserved: self.read_var_u1()?, + }, + 0x40 => Operator::MemoryGrow { + reserved: self.read_var_u1()?, + }, + 0x41 => Operator::I32Const { + value: self.read_var_i32()?, + }, + 0x42 => Operator::I64Const { + value: self.read_var_i64()?, + }, + 0x43 => Operator::F32Const { + value: self.read_f32()?, + }, + 0x44 => Operator::F64Const { + value: self.read_f64()?, + }, + 0x45 => Operator::I32Eqz, + 0x46 => Operator::I32Eq, + 0x47 => Operator::I32Ne, + 0x48 => Operator::I32LtS, + 0x49 => Operator::I32LtU, + 0x4a => Operator::I32GtS, + 0x4b => Operator::I32GtU, + 0x4c => Operator::I32LeS, + 0x4d => Operator::I32LeU, + 0x4e => Operator::I32GeS, + 0x4f => Operator::I32GeU, + 0x50 => Operator::I64Eqz, + 0x51 => Operator::I64Eq, + 0x52 => Operator::I64Ne, + 0x53 => Operator::I64LtS, + 0x54 => Operator::I64LtU, + 0x55 => Operator::I64GtS, + 0x56 => Operator::I64GtU, + 0x57 => Operator::I64LeS, + 0x58 => Operator::I64LeU, + 0x59 => Operator::I64GeS, + 0x5a => Operator::I64GeU, + 0x5b => Operator::F32Eq, + 0x5c => Operator::F32Ne, + 0x5d => Operator::F32Lt, + 0x5e => Operator::F32Gt, + 0x5f => Operator::F32Le, + 0x60 => Operator::F32Ge, + 0x61 => Operator::F64Eq, + 0x62 => Operator::F64Ne, + 0x63 => Operator::F64Lt, + 0x64 => Operator::F64Gt, + 0x65 => Operator::F64Le, + 0x66 => Operator::F64Ge, + 0x67 => Operator::I32Clz, + 0x68 => Operator::I32Ctz, + 0x69 => Operator::I32Popcnt, + 0x6a => Operator::I32Add, + 0x6b => Operator::I32Sub, + 0x6c => Operator::I32Mul, + 0x6d => Operator::I32DivS, + 0x6e => Operator::I32DivU, + 0x6f => Operator::I32RemS, + 0x70 => Operator::I32RemU, + 0x71 => Operator::I32And, + 0x72 => Operator::I32Or, + 0x73 => Operator::I32Xor, + 0x74 => Operator::I32Shl, + 0x75 => Operator::I32ShrS, + 0x76 => Operator::I32ShrU, + 0x77 => Operator::I32Rotl, + 0x78 => Operator::I32Rotr, + 0x79 => Operator::I64Clz, + 0x7a => Operator::I64Ctz, + 0x7b => Operator::I64Popcnt, + 0x7c => Operator::I64Add, + 0x7d => Operator::I64Sub, + 0x7e => Operator::I64Mul, + 0x7f => Operator::I64DivS, + 0x80 => Operator::I64DivU, + 0x81 => Operator::I64RemS, + 0x82 => Operator::I64RemU, + 0x83 => Operator::I64And, + 0x84 => Operator::I64Or, + 0x85 => Operator::I64Xor, + 0x86 => Operator::I64Shl, + 0x87 => Operator::I64ShrS, + 0x88 => Operator::I64ShrU, + 0x89 => Operator::I64Rotl, + 0x8a => Operator::I64Rotr, + 0x8b => Operator::F32Abs, + 0x8c => Operator::F32Neg, + 0x8d => Operator::F32Ceil, + 0x8e => Operator::F32Floor, + 0x8f => Operator::F32Trunc, + 0x90 => Operator::F32Nearest, + 0x91 => Operator::F32Sqrt, + 0x92 => Operator::F32Add, + 0x93 => Operator::F32Sub, + 0x94 => Operator::F32Mul, + 0x95 => Operator::F32Div, + 0x96 => Operator::F32Min, + 0x97 => Operator::F32Max, + 0x98 => Operator::F32Copysign, + 0x99 => Operator::F64Abs, + 0x9a => Operator::F64Neg, + 0x9b => Operator::F64Ceil, + 0x9c => Operator::F64Floor, + 0x9d => Operator::F64Trunc, + 0x9e => Operator::F64Nearest, + 0x9f => Operator::F64Sqrt, + 0xa0 => Operator::F64Add, + 0xa1 => Operator::F64Sub, + 0xa2 => Operator::F64Mul, + 0xa3 => Operator::F64Div, + 0xa4 => Operator::F64Min, + 0xa5 => Operator::F64Max, + 0xa6 => Operator::F64Copysign, + 0xa7 => Operator::I32WrapI64, + 0xa8 => Operator::I32TruncF32S, + 0xa9 => Operator::I32TruncF32U, + 0xaa => Operator::I32TruncF64S, + 0xab => Operator::I32TruncF64U, + 0xac => Operator::I64ExtendI32S, + 0xad => Operator::I64ExtendI32U, + 0xae => Operator::I64TruncF32S, + 0xaf => Operator::I64TruncF32U, + 0xb0 => Operator::I64TruncF64S, + 0xb1 => Operator::I64TruncF64U, + 0xb2 => Operator::F32ConvertI32S, + 0xb3 => Operator::F32ConvertI32U, + 0xb4 => Operator::F32ConvertI64S, + 0xb5 => Operator::F32ConvertI64U, + 0xb6 => Operator::F32DemoteF64, + 0xb7 => Operator::F64ConvertI32S, + 0xb8 => Operator::F64ConvertI32U, + 0xb9 => Operator::F64ConvertI64S, + 0xba => Operator::F64ConvertI64U, + 0xbb => Operator::F64PromoteF32, + 0xbc => Operator::I32ReinterpretF32, + 0xbd => Operator::I64ReinterpretF64, + 0xbe => Operator::F32ReinterpretI32, + 0xbf => Operator::F64ReinterpretI64, + + 0xc0 => Operator::I32Extend8S, + 0xc1 => Operator::I32Extend16S, + 0xc2 => Operator::I64Extend8S, + 0xc3 => Operator::I64Extend16S, + 0xc4 => Operator::I64Extend32S, + + 0xd0 => Operator::RefNull, + 0xd1 => Operator::RefIsNull, + 0xd2 => Operator::RefFunc { + function_index: self.read_var_u32()?, + }, + + 0xfc => self.read_0xfc_operator()?, + 0xfd => self.read_0xfd_operator()?, + 0xfe => self.read_0xfe_operator()?, + + _ => { + return Err(BinaryReaderError { + message: "Unknown opcode", + offset: self.original_position() - 1, + }); + } + }) + } + + fn read_0xfc_operator(&mut self) -> Result<Operator<'a>> { + let code = self.read_u8()? as u8; + Ok(match code { + 0x00 => Operator::I32TruncSatF32S, + 0x01 => Operator::I32TruncSatF32U, + 0x02 => Operator::I32TruncSatF64S, + 0x03 => Operator::I32TruncSatF64U, + 0x04 => Operator::I64TruncSatF32S, + 0x05 => Operator::I64TruncSatF32U, + 0x06 => Operator::I64TruncSatF64S, + 0x07 => Operator::I64TruncSatF64U, + + 0x08 => { + let segment = self.read_var_u32()?; + let mem = self.read_u8()?; + if mem != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryInit { segment } + } + 0x09 => { + let segment = self.read_var_u32()?; + Operator::DataDrop { segment } + } + 0x0a => { + let dst = self.read_u8()?; + if dst != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + let src = self.read_u8()?; + if src != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryCopy + } + 0x0b => { + let mem = self.read_u8()?; + if mem != 0 { + return Err(BinaryReaderError { + message: "reserved byte must be zero", + offset: self.original_position() - 1, + }); + } + Operator::MemoryFill + } + 0x0c => { + let segment = self.read_var_u32()?; + let table = self.read_var_u32()?; + Operator::TableInit { segment, table } + } + 0x0d => { + let segment = self.read_var_u32()?; + Operator::ElemDrop { segment } + } + 0x0e => { + let dst_table = self.read_var_u32()?; + let src_table = self.read_var_u32()?; + Operator::TableCopy { + src_table, + dst_table, + } + } + + 0x0f => { + let table = self.read_var_u32()?; + Operator::TableGrow { table } + } + 0x10 => { + let table = self.read_var_u32()?; + Operator::TableSize { table } + } + + 0x11 => { + let table = self.read_var_u32()?; + Operator::TableFill { table } + } + + _ => { + return Err(BinaryReaderError { + message: "Unknown 0xfc opcode", + offset: self.original_position() - 1, + }); + } + }) + } + + fn read_lane_index(&mut self, max: u32) -> Result<SIMDLaneIndex> { + let index = self.read_u8()?; + if index >= max { + return Err(BinaryReaderError { + message: "invalid lane index", + offset: self.original_position() - 1, + }); + } + Ok(index as SIMDLaneIndex) + } + + fn read_v128(&mut self) -> Result<V128> { + let mut bytes = [0; 16]; + bytes.clone_from_slice(self.read_bytes(16)?); + Ok(V128(bytes)) + } + + fn read_0xfd_operator(&mut self) -> Result<Operator<'a>> { + let code = self.read_var_u8()? as u8; + Ok(match code { + 0x00 => Operator::V128Load { + memarg: self.read_memarg()?, + }, + 0x01 => Operator::V128Store { + memarg: self.read_memarg()?, + }, + 0x02 => Operator::V128Const { + value: self.read_v128()?, + }, + 0x04 => Operator::I8x16Splat, + 0x05 => Operator::I8x16ExtractLaneS { + lane: self.read_lane_index(16)?, + }, + 0x06 => Operator::I8x16ExtractLaneU { + lane: self.read_lane_index(16)?, + }, + 0x07 => Operator::I8x16ReplaceLane { + lane: self.read_lane_index(16)?, + }, + 0x08 => Operator::I16x8Splat, + 0x09 => Operator::I16x8ExtractLaneS { + lane: self.read_lane_index(8)?, + }, + 0x0a => Operator::I16x8ExtractLaneU { + lane: self.read_lane_index(8)?, + }, + 0x0b => Operator::I16x8ReplaceLane { + lane: self.read_lane_index(8)?, + }, + 0x0c => Operator::I32x4Splat, + 0x0d => Operator::I32x4ExtractLane { + lane: self.read_lane_index(4)?, + }, + 0x0e => Operator::I32x4ReplaceLane { + lane: self.read_lane_index(4)?, + }, + 0x0f => Operator::I64x2Splat, + 0x10 => Operator::I64x2ExtractLane { + lane: self.read_lane_index(2)?, + }, + 0x11 => Operator::I64x2ReplaceLane { + lane: self.read_lane_index(2)?, + }, + 0x12 => Operator::F32x4Splat, + 0x13 => Operator::F32x4ExtractLane { + lane: self.read_lane_index(4)?, + }, + 0x14 => Operator::F32x4ReplaceLane { + lane: self.read_lane_index(4)?, + }, + 0x15 => Operator::F64x2Splat, + 0x16 => Operator::F64x2ExtractLane { + lane: self.read_lane_index(2)?, + }, + 0x17 => Operator::F64x2ReplaceLane { + lane: self.read_lane_index(2)?, + }, + 0x18 => Operator::I8x16Eq, + 0x19 => Operator::I8x16Ne, + 0x1a => Operator::I8x16LtS, + 0x1b => Operator::I8x16LtU, + 0x1c => Operator::I8x16GtS, + 0x1d => Operator::I8x16GtU, + 0x1e => Operator::I8x16LeS, + 0x1f => Operator::I8x16LeU, + 0x20 => Operator::I8x16GeS, + 0x21 => Operator::I8x16GeU, + 0x22 => Operator::I16x8Eq, + 0x23 => Operator::I16x8Ne, + 0x24 => Operator::I16x8LtS, + 0x25 => Operator::I16x8LtU, + 0x26 => Operator::I16x8GtS, + 0x27 => Operator::I16x8GtU, + 0x28 => Operator::I16x8LeS, + 0x29 => Operator::I16x8LeU, + 0x2a => Operator::I16x8GeS, + 0x2b => Operator::I16x8GeU, + 0x2c => Operator::I32x4Eq, + 0x2d => Operator::I32x4Ne, + 0x2e => Operator::I32x4LtS, + 0x2f => Operator::I32x4LtU, + 0x30 => Operator::I32x4GtS, + 0x31 => Operator::I32x4GtU, + 0x32 => Operator::I32x4LeS, + 0x33 => Operator::I32x4LeU, + 0x34 => Operator::I32x4GeS, + 0x35 => Operator::I32x4GeU, + 0x40 => Operator::F32x4Eq, + 0x41 => Operator::F32x4Ne, + 0x42 => Operator::F32x4Lt, + 0x43 => Operator::F32x4Gt, + 0x44 => Operator::F32x4Le, + 0x45 => Operator::F32x4Ge, + 0x46 => Operator::F64x2Eq, + 0x47 => Operator::F64x2Ne, + 0x48 => Operator::F64x2Lt, + 0x49 => Operator::F64x2Gt, + 0x4a => Operator::F64x2Le, + 0x4b => Operator::F64x2Ge, + 0x4c => Operator::V128Not, + 0x4d => Operator::V128And, + 0x4e => Operator::V128Or, + 0x4f => Operator::V128Xor, + 0x50 => Operator::V128Bitselect, + 0x51 => Operator::I8x16Neg, + 0x52 => Operator::I8x16AnyTrue, + 0x53 => Operator::I8x16AllTrue, + 0x54 => Operator::I8x16Shl, + 0x55 => Operator::I8x16ShrS, + 0x56 => Operator::I8x16ShrU, + 0x57 => Operator::I8x16Add, + 0x58 => Operator::I8x16AddSaturateS, + 0x59 => Operator::I8x16AddSaturateU, + 0x5a => Operator::I8x16Sub, + 0x5b => Operator::I8x16SubSaturateS, + 0x5c => Operator::I8x16SubSaturateU, + 0x5d => Operator::I8x16Mul, + 0x62 => Operator::I16x8Neg, + 0x63 => Operator::I16x8AnyTrue, + 0x64 => Operator::I16x8AllTrue, + 0x65 => Operator::I16x8Shl, + 0x66 => Operator::I16x8ShrS, + 0x67 => Operator::I16x8ShrU, + 0x68 => Operator::I16x8Add, + 0x69 => Operator::I16x8AddSaturateS, + 0x6a => Operator::I16x8AddSaturateU, + 0x6b => Operator::I16x8Sub, + 0x6c => Operator::I16x8SubSaturateS, + 0x6d => Operator::I16x8SubSaturateU, + 0x6e => Operator::I16x8Mul, + 0x73 => Operator::I32x4Neg, + 0x74 => Operator::I32x4AnyTrue, + 0x75 => Operator::I32x4AllTrue, + 0x76 => Operator::I32x4Shl, + 0x77 => Operator::I32x4ShrS, + 0x78 => Operator::I32x4ShrU, + 0x79 => Operator::I32x4Add, + 0x7c => Operator::I32x4Sub, + 0x7f => Operator::I32x4Mul, + 0x84 => Operator::I64x2Neg, + 0x85 => Operator::I64x2AnyTrue, + 0x86 => Operator::I64x2AllTrue, + 0x87 => Operator::I64x2Shl, + 0x88 => Operator::I64x2ShrS, + 0x89 => Operator::I64x2ShrU, + 0x8a => Operator::I64x2Add, + 0x8d => Operator::I64x2Sub, + 0x90 => Operator::I64x2Mul, + 0x95 => Operator::F32x4Abs, + 0x96 => Operator::F32x4Neg, + 0x97 => Operator::F32x4Sqrt, + 0x9a => Operator::F32x4Add, + 0x9b => Operator::F32x4Sub, + 0x9c => Operator::F32x4Mul, + 0x9d => Operator::F32x4Div, + 0x9e => Operator::F32x4Min, + 0x9f => Operator::F32x4Max, + 0xa0 => Operator::F64x2Abs, + 0xa1 => Operator::F64x2Neg, + 0xa2 => Operator::F64x2Sqrt, + 0xa5 => Operator::F64x2Add, + 0xa6 => Operator::F64x2Sub, + 0xa7 => Operator::F64x2Mul, + 0xa8 => Operator::F64x2Div, + 0xa9 => Operator::F64x2Min, + 0xaa => Operator::F64x2Max, + 0xab => Operator::I32x4TruncSatF32x4S, + 0xac => Operator::I32x4TruncSatF32x4U, + 0xad => Operator::I64x2TruncSatF64x2S, + 0xae => Operator::I64x2TruncSatF64x2U, + 0xaf => Operator::F32x4ConvertI32x4S, + 0xb0 => Operator::F32x4ConvertI32x4U, + 0xb1 => Operator::F64x2ConvertI64x2S, + 0xb2 => Operator::F64x2ConvertI64x2U, + 0xc0 => Operator::V8x16Swizzle, + 0x03 | 0xc1 => { + let mut lanes = [0 as SIMDLaneIndex; 16]; + for lane in &mut lanes { + *lane = self.read_lane_index(32)? + } + Operator::V8x16Shuffle { lanes } + } + 0xc2 => Operator::V8x16LoadSplat { + memarg: self.read_memarg_of_align(0)?, + }, + 0xc3 => Operator::V16x8LoadSplat { + memarg: self.read_memarg_of_align(1)?, + }, + 0xc4 => Operator::V32x4LoadSplat { + memarg: self.read_memarg_of_align(2)?, + }, + 0xc5 => Operator::V64x2LoadSplat { + memarg: self.read_memarg_of_align(3)?, + }, + 0xc6 => Operator::I8x16NarrowI16x8S, + 0xc7 => Operator::I8x16NarrowI16x8U, + 0xc8 => Operator::I16x8NarrowI32x4S, + 0xc9 => Operator::I16x8NarrowI32x4U, + 0xca => Operator::I16x8WidenLowI8x16S, + 0xcb => Operator::I16x8WidenHighI8x16S, + 0xcc => Operator::I16x8WidenLowI8x16U, + 0xcd => Operator::I16x8WidenHighI8x16U, + 0xce => Operator::I32x4WidenLowI16x8S, + 0xcf => Operator::I32x4WidenHighI16x8S, + 0xd0 => Operator::I32x4WidenLowI16x8U, + 0xd1 => Operator::I32x4WidenHighI16x8U, + 0xd2 => Operator::I16x8Load8x8S { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd3 => Operator::I16x8Load8x8U { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd4 => Operator::I32x4Load16x4S { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd5 => Operator::I32x4Load16x4U { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd6 => Operator::I64x2Load32x2S { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd7 => Operator::I64x2Load32x2U { + memarg: self.read_memarg_of_align(3)?, + }, + 0xd8 => Operator::V128AndNot, + 0xd9 => Operator::I8x16RoundingAverageU, + 0xda => Operator::I16x8RoundingAverageU, + _ => { + return Err(BinaryReaderError { + message: "Unknown 0xfd opcode", + offset: self.original_position() - 1, + }); + } + }) + } + + pub(crate) fn read_file_header(&mut self) -> Result<u32> { + let magic_number = self.read_bytes(4)?; + if magic_number != WASM_MAGIC_NUMBER { + return Err(BinaryReaderError { + message: "Bad magic number", + offset: self.original_position() - 4, + }); + } + let version = self.read_u32()?; + if version != WASM_SUPPORTED_VERSION && version != WASM_EXPERIMENTAL_VERSION { + return Err(BinaryReaderError { + message: "Bad version number", + offset: self.original_position() - 4, + }); + } + Ok(version) + } + + pub(crate) fn read_section_header(&mut self) -> Result<SectionHeader<'a>> { + let id_position = self.position; + let id = self.read_var_u7()?; + let payload_len = self.read_var_u32()? as usize; + let payload_start = self.position; + let code = self.read_section_code(id, id_position)?; + Ok(SectionHeader { + code, + payload_start, + payload_len, + }) + } + + pub(crate) fn read_name_type(&mut self) -> Result<NameType> { + let code = self.read_var_u7()?; + match code { + 0 => Ok(NameType::Module), + 1 => Ok(NameType::Function), + 2 => Ok(NameType::Local), + _ => Err(BinaryReaderError { + message: "Invalid name type", + offset: self.original_position() - 1, + }), + } + } + + pub(crate) fn read_linking_type(&mut self) -> Result<LinkingType> { + let ty = self.read_var_u32()?; + Ok(match ty { + 1 => LinkingType::StackPointer(self.read_var_u32()?), + _ => { + return Err(BinaryReaderError { + message: "Invalid linking type", + offset: self.original_position() - 1, + }); + } + }) + } + + pub(crate) fn read_reloc_type(&mut self) -> Result<RelocType> { + let code = self.read_var_u7()?; + match code { + 0 => Ok(RelocType::FunctionIndexLEB), + 1 => Ok(RelocType::TableIndexSLEB), + 2 => Ok(RelocType::TableIndexI32), + 3 => Ok(RelocType::GlobalAddrLEB), + 4 => Ok(RelocType::GlobalAddrSLEB), + 5 => Ok(RelocType::GlobalAddrI32), + 6 => Ok(RelocType::TypeIndexLEB), + 7 => Ok(RelocType::GlobalIndexLEB), + _ => Err(BinaryReaderError { + message: "Invalid reloc type", + offset: self.original_position() - 1, + }), + } + } + + pub(crate) fn skip_init_expr(&mut self) -> Result<()> { + // TODO add skip_operator() method and/or validate init_expr operators. + loop { + if let Operator::End = self.read_operator()? { + return Ok(()); + } + } + } +} + +impl<'a> BrTable<'a> { + /// Returns the number of `br_table` entries, not including the default + /// label + pub fn len(&self) -> usize { + self.cnt + } + + /// Returns whether `BrTable` doesn't have any labels apart from the default one. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Reads br_table entries. + /// + /// # Examples + /// ```rust + /// let buf = vec![0x0e, 0x02, 0x01, 0x02, 0x00]; + /// let mut reader = wasmparser::BinaryReader::new(&buf); + /// let op = reader.read_operator().unwrap(); + /// if let wasmparser::Operator::BrTable { ref table } = op { + /// let br_table_depths = table.read_table().unwrap(); + /// assert!(br_table_depths.0 == vec![1,2].into_boxed_slice() && + /// br_table_depths.1 == 0); + /// } else { + /// unreachable!(); + /// } + /// ``` + pub fn read_table(&self) -> Result<(Box<[u32]>, u32)> { + let mut reader = BinaryReader::new(self.buffer); + let mut table = Vec::new(); + while !reader.eof() { + table.push(reader.read_var_u32()?); + } + let default_target = table.pop().ok_or_else(|| BinaryReaderError { + message: "br_table missing default target", + offset: reader.original_position(), + })?; + Ok((table.into_boxed_slice(), default_target)) + } +} + +/// Iterator for `BrTable`. +/// +/// #Examples +/// ```rust +/// let buf = vec![0x0e, 0x02, 0x01, 0x02, 0x00]; +/// let mut reader = wasmparser::BinaryReader::new(&buf); +/// let op = reader.read_operator().unwrap(); +/// if let wasmparser::Operator::BrTable { ref table } = op { +/// for depth in table { +/// println!("BrTable depth: {}", depth); +/// } +/// } +/// ``` +#[derive(Clone, Debug)] +pub struct BrTableIterator<'a> { + reader: BinaryReader<'a>, +} + +impl<'a> IntoIterator for &'a BrTable<'a> { + type Item = u32; + type IntoIter = BrTableIterator<'a>; + + fn into_iter(self) -> Self::IntoIter { + BrTableIterator { + reader: BinaryReader::new(self.buffer), + } + } +} + +impl<'a> Iterator for BrTableIterator<'a> { + type Item = u32; + + fn next(&mut self) -> Option<u32> { + if self.reader.eof() { + return None; + } + self.reader.read_var_u32().ok() + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/lib.rs b/third_party/rust/wasmparser-0.48.2/src/lib.rs new file mode 100644 index 0000000000..e581b932da --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/lib.rs @@ -0,0 +1,131 @@ +/* Copyright 2017 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! A simple event-driven library for parsing WebAssembly binary files +//! (or streams). +//! +//! The parser library reports events as they happend and only stores +//! parsing information for a brief period of time, making it very fast +//! and memory-efficient. The event-driven model, however, has some drawbacks. +//! If you need random access to the entire WebAssembly data-structure, +//! this is not the right library for you. You could however, build such +//! a data-structure using this library. + +pub use crate::binary_reader::BinaryReader; +pub use crate::binary_reader::Range; +use crate::binary_reader::SectionHeader; + +pub use crate::parser::ElemSectionEntryTable; +pub use crate::parser::LocalName; +pub use crate::parser::NameEntry; +pub use crate::parser::Parser; +pub use crate::parser::ParserInput; +pub use crate::parser::ParserState; +pub use crate::parser::RelocEntry; +pub use crate::parser::WasmDecoder; + +pub use crate::primitives::BinaryReaderError; +pub use crate::primitives::BrTable; +pub use crate::primitives::CustomSectionKind; +pub use crate::primitives::ExternalKind; +pub use crate::primitives::FuncType; +pub use crate::primitives::GlobalType; +pub use crate::primitives::Ieee32; +pub use crate::primitives::Ieee64; +pub use crate::primitives::ImportSectionEntryType; +pub use crate::primitives::LinkingType; +pub use crate::primitives::MemoryImmediate; +pub use crate::primitives::MemoryType; +pub use crate::primitives::NameType; +pub use crate::primitives::Naming; +pub use crate::primitives::Operator; +pub use crate::primitives::RelocType; +pub use crate::primitives::ResizableLimits; +pub use crate::primitives::Result; +pub use crate::primitives::SectionCode; +pub use crate::primitives::TableType; +pub use crate::primitives::Type; +pub use crate::primitives::TypeOrFuncType; +pub use crate::primitives::V128; + +pub use crate::validator::validate; +pub use crate::validator::validate_function_body; +pub use crate::validator::ValidatingOperatorParser; +pub use crate::validator::ValidatingParser; +pub use crate::validator::ValidatingParserConfig; + +pub use crate::module_resources::WasmFuncType; +pub use crate::module_resources::WasmGlobalType; +pub use crate::module_resources::WasmMemoryType; +pub use crate::module_resources::WasmModuleResources; +pub use crate::module_resources::WasmTableType; +pub use crate::module_resources::WasmType; + +pub(crate) use crate::module_resources::{wasm_func_type_inputs, wasm_func_type_outputs}; + +pub use crate::operators_validator::OperatorValidatorConfig; + +pub use crate::readers::CodeSectionReader; +pub use crate::readers::CustomSectionContent; +pub use crate::readers::Data; +pub use crate::readers::DataKind; +pub use crate::readers::DataSectionReader; +pub use crate::readers::Element; +pub use crate::readers::ElementItem; +pub use crate::readers::ElementItems; +pub use crate::readers::ElementItemsReader; +pub use crate::readers::ElementKind; +pub use crate::readers::ElementSectionReader; +pub use crate::readers::Export; +pub use crate::readers::ExportSectionReader; +pub use crate::readers::FunctionBody; +pub use crate::readers::FunctionSectionReader; +pub use crate::readers::Global; +pub use crate::readers::GlobalSectionReader; +pub use crate::readers::Import; +pub use crate::readers::ImportSectionReader; +pub use crate::readers::InitExpr; +pub use crate::readers::LinkingSectionReader; +pub use crate::readers::LocalsReader; +pub use crate::readers::MemorySectionReader; +pub use crate::readers::ModuleReader; +pub use crate::readers::Name; +pub use crate::readers::NameSectionReader; +pub use crate::readers::NamingReader; +pub use crate::readers::OperatorsReader; +pub use crate::readers::ProducersField; +pub use crate::readers::ProducersFieldValue; +pub use crate::readers::ProducersFieldValuesReader; +pub use crate::readers::ProducersSectionReader; +pub use crate::readers::Reloc; +pub use crate::readers::RelocSectionReader; +pub use crate::readers::Section; +pub use crate::readers::SectionContent; +pub use crate::readers::SectionIterator; +pub use crate::readers::SectionIteratorLimited; +pub use crate::readers::SectionReader; +pub use crate::readers::SectionWithLimitedItems; +pub use crate::readers::TableSectionReader; +pub use crate::readers::TypeSectionReader; + +mod binary_reader; +mod limits; +mod module_resources; +mod operators_validator; +mod parser; +mod primitives; +mod readers; +mod tests; +mod validator; diff --git a/third_party/rust/wasmparser-0.48.2/src/limits.rs b/third_party/rust/wasmparser-0.48.2/src/limits.rs new file mode 100644 index 0000000000..38594a6362 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/limits.rs @@ -0,0 +1,34 @@ +/* Copyright 2017 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// The following limits are imposed by wasmparser on WebAssembly modules. +// The limits are agreed upon with other engines for consistency. +pub const MAX_WASM_TYPES: usize = 1_000_000; +pub const MAX_WASM_FUNCTIONS: usize = 1_000_000; +pub const _MAX_WASM_IMPORTS: usize = 100_000; +pub const _MAX_WASM_EXPORTS: usize = 100_000; +pub const MAX_WASM_GLOBALS: usize = 1_000_000; +pub const _MAX_WASM_DATA_SEGMENTS: usize = 100_000; +pub const MAX_WASM_MEMORY_PAGES: usize = 65536; +pub const MAX_WASM_STRING_SIZE: usize = 100_000; +pub const _MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB +pub const MAX_WASM_FUNCTION_SIZE: usize = 128 * 1024; +pub const MAX_WASM_FUNCTION_LOCALS: usize = 50000; +pub const MAX_WASM_FUNCTION_PARAMS: usize = 1000; +pub const MAX_WASM_FUNCTION_RETURNS: usize = 1000; +pub const _MAX_WASM_TABLE_SIZE: usize = 10_000_000; +pub const MAX_WASM_TABLE_ENTRIES: usize = 10_000_000; +pub const MAX_WASM_TABLES: usize = 1; +pub const MAX_WASM_MEMORIES: usize = 1; diff --git a/third_party/rust/wasmparser-0.48.2/src/module_resources.rs b/third_party/rust/wasmparser-0.48.2/src/module_resources.rs new file mode 100644 index 0000000000..09b193757d --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/module_resources.rs @@ -0,0 +1,370 @@ +/* Copyright 2019 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// Types that qualify as Wasm types for validation purposes. +/// +/// Must be comparable with `wasmparser` given Wasm types and +/// must be comparable to themselves. +pub trait WasmType: PartialEq<crate::Type> + PartialEq + Eq { + /// Converts the custom type into a `wasmparser` known type. + /// + /// # Note + /// + /// This interface is required as bridge until transitioning is complete. + fn to_parser_type(&self) -> crate::Type; +} + +/// Types that qualify as Wasm function types for validation purposes. +pub trait WasmFuncType { + /// A type that is comparable with Wasm types. + type Type: WasmType; + + /// Returns the number of input types. + fn len_inputs(&self) -> usize; + /// Returns the number of output types. + fn len_outputs(&self) -> usize; + /// Returns the type at given index if any. + /// + /// # Note + /// + /// The returned type may be wrapped by the user crate and thus + /// the actually returned type only has to be comparable to a Wasm type. + fn input_at(&self, at: u32) -> Option<&Self::Type>; + /// Returns the type at given index if any. + /// + /// # Note + /// + /// The returned type may be wrapped by the user crate and thus + /// the actually returned type only has to be comparable to a Wasm type. + fn output_at(&self, at: u32) -> Option<&Self::Type>; +} + +/// Iterator over the inputs of a Wasm function type. +pub(crate) struct WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + /// The iterated-over function type. + func_type: &'a F, + /// The current starting index. + start: u32, + /// The current ending index. + end: u32, +} + +impl<'a, F, T> WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn new(func_type: &'a F) -> Self { + Self { + func_type, + start: 0, + end: func_type.len_inputs() as u32, + } + } +} + +impl<'a, F, T> Iterator for WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + if self.start == self.end { + return None; + } + let ty = self + .func_type + .input_at(self.start) + // Expected since `self.start != self.end`. + .expect("we expect to receive an input type at this point"); + self.start += 1; + Some(ty) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<'a, F, T> DoubleEndedIterator for WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn next_back(&mut self) -> Option<Self::Item> { + if self.start == self.end { + return None; + } + let ty = self + .func_type + .input_at(self.end) + // Expected since `self.start != self.end`. + .expect("we expect to receive an input type at this point"); + self.end -= 1; + Some(ty) + } +} + +impl<'a, F, T> ExactSizeIterator for WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn len(&self) -> usize { + (self.end as usize) - (self.start as usize) + } +} + +/// Iterator over the outputs of a Wasm function type. +pub(crate) struct WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + /// The iterated-over function type. + func_type: &'a F, + /// The current starting index. + start: u32, + /// The current ending index. + end: u32, +} + +impl<'a, F, T> WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn new(func_type: &'a F) -> Self { + Self { + func_type, + start: 0, + end: func_type.len_outputs() as u32, + } + } +} + +impl<'a, F, T> Iterator for WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + if self.start == self.end { + return None; + } + let ty = self + .func_type + .output_at(self.start) + // Expected since `self.start != self.end`. + .expect("we expect to receive an input type at this point"); + self.start += 1; + Some(ty) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<'a, F, T> DoubleEndedIterator for WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn next_back(&mut self) -> Option<Self::Item> { + if self.start == self.end { + return None; + } + let ty = self + .func_type + .output_at(self.end) + // Expected since `self.start != self.end`. + .expect("we expect to receive an input type at this point"); + self.end -= 1; + Some(ty) + } +} + +impl<'a, F, T> ExactSizeIterator for WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + fn len(&self) -> usize { + (self.end as usize) - (self.start as usize) + } +} + +/// Returns an iterator over the input types of a Wasm function type. +pub(crate) fn wasm_func_type_inputs<'a, F, T>(func_type: &'a F) -> WasmFuncTypeInputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + WasmFuncTypeInputs::new(func_type) +} + +/// Returns an iterator over the output types of a Wasm function type. +pub(crate) fn wasm_func_type_outputs<'a, F, T>(func_type: &'a F) -> WasmFuncTypeOutputs<'a, F, T> +where + F: WasmFuncType<Type = T>, + T: WasmType + 'a, +{ + WasmFuncTypeOutputs::new(func_type) +} + +/// Types that qualify as Wasm table types for validation purposes. +pub trait WasmTableType { + /// A type that is comparable with Wasm types. + type Type: WasmType; + + /// Returns the element type of the table. + fn element_type(&self) -> &Self::Type; + /// Returns the initial limit of the table. + fn initial_limit(&self) -> u32; + /// Returns the maximum limit of the table if any. + fn maximum_limit(&self) -> Option<u32>; +} + +/// Types that qualify as Wasm memory types for validation purposes. +pub trait WasmMemoryType { + /// Returns `true` if the linear memory is shared. + fn is_shared(&self) -> bool; + /// Returns the initial limit of the linear memory. + fn initial_limit(&self) -> u32; + /// Returns the maximum limit of the linear memory if any. + fn maximum_limit(&self) -> Option<u32>; +} + +/// Types that qualify as Wasm global types for validation purposes. +pub trait WasmGlobalType { + /// A type that is comparable with Wasm types. + type Type: WasmType; + + /// Returns `true` if the global variable is mutable. + fn is_mutable(&self) -> bool; + /// Returns the content type of the global variable. + fn content_type(&self) -> &Self::Type; +} + +/// Types that qualify as Wasm valiation database. +/// +/// # Note +/// +/// The `wasmparser` crate provides a builtin validation framework but allows +/// users of this crate to also feed the parsed Wasm into their own data +/// structure while parsing and also validate at the same time without +/// the need of an additional parsing or validation step or copying data around. +pub trait WasmModuleResources { + /// The function type used for validation. + type FuncType: WasmFuncType; + /// The table type used for validation. + type TableType: WasmTableType; + /// The memory type used for validation. + type MemoryType: WasmMemoryType; + /// The global type used for validation. + type GlobalType: WasmGlobalType; + + /// Returns the type at given index. + fn type_at(&self, at: u32) -> Option<&Self::FuncType>; + /// Returns the table at given index if any. + fn table_at(&self, at: u32) -> Option<&Self::TableType>; + /// Returns the linear memory at given index. + fn memory_at(&self, at: u32) -> Option<&Self::MemoryType>; + /// Returns the global variable at given index. + fn global_at(&self, at: u32) -> Option<&Self::GlobalType>; + /// Returns the function signature ID at given index. + fn func_type_id_at(&self, at: u32) -> Option<u32>; + + /// Returns the number of elements. + fn element_count(&self) -> u32; + /// Returns the number of bytes in the Wasm data section. + fn data_count(&self) -> u32; +} + +impl WasmType for crate::Type { + fn to_parser_type(&self) -> crate::Type { + *self + } +} + +impl WasmFuncType for crate::FuncType { + type Type = crate::Type; + + fn len_inputs(&self) -> usize { + self.params.len() + } + + fn len_outputs(&self) -> usize { + self.returns.len() + } + + fn input_at(&self, at: u32) -> Option<&Self::Type> { + self.params.get(at as usize) + } + + fn output_at(&self, at: u32) -> Option<&Self::Type> { + self.returns.get(at as usize) + } +} + +impl WasmGlobalType for crate::GlobalType { + type Type = crate::Type; + + fn is_mutable(&self) -> bool { + self.mutable + } + + fn content_type(&self) -> &Self::Type { + &self.content_type + } +} + +impl WasmTableType for crate::TableType { + type Type = crate::Type; + + fn element_type(&self) -> &Self::Type { + &self.element_type + } + + fn initial_limit(&self) -> u32 { + self.limits.initial + } + + fn maximum_limit(&self) -> Option<u32> { + self.limits.maximum + } +} + +impl WasmMemoryType for crate::MemoryType { + fn is_shared(&self) -> bool { + self.shared + } + + fn initial_limit(&self) -> u32 { + self.limits.initial + } + fn maximum_limit(&self) -> Option<u32> { + self.limits.maximum + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs b/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs new file mode 100644 index 0000000000..71f9bc319c --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/operators_validator.rs @@ -0,0 +1,1896 @@ +/* Copyright 2019 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::cmp::min; +use std::result; +use std::str; + +use crate::primitives::{MemoryImmediate, Operator, SIMDLaneIndex, Type, TypeOrFuncType}; +use crate::{ + wasm_func_type_inputs, wasm_func_type_outputs, WasmFuncType, WasmGlobalType, WasmMemoryType, + WasmModuleResources, WasmTableType, WasmType, +}; + +/// Test if `subtype` is a subtype of `supertype`. +pub(crate) fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool { + match supertype { + Type::AnyRef => { + subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::NullRef + } + Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::NullRef, + _ => subtype == supertype, + } +} + +#[derive(Debug)] +struct BlockState { + start_types: Vec<Type>, + return_types: Vec<Type>, + stack_starts_at: usize, + jump_to_top: bool, + is_else_allowed: bool, + is_dead_code: bool, + polymorphic_values: Option<usize>, +} + +impl BlockState { + fn is_stack_polymorphic(&self) -> bool { + self.polymorphic_values.is_some() + } +} + +#[derive(Debug)] +struct FuncState { + local_types: Vec<Type>, + blocks: Vec<BlockState>, + stack_types: Vec<Type>, + end_function: bool, +} + +impl FuncState { + fn block_at(&self, depth: usize) -> &BlockState { + assert!(depth < self.blocks.len()); + &self.blocks[self.blocks.len() - 1 - depth] + } + fn last_block(&self) -> &BlockState { + self.blocks.last().unwrap() + } + fn assert_stack_type_at(&self, index: usize, expected: Type) -> bool { + let stack_starts_at = self.last_block().stack_starts_at; + if self.last_block().is_stack_polymorphic() + && stack_starts_at + index >= self.stack_types.len() + { + return true; + } + assert!(stack_starts_at + index < self.stack_types.len()); + is_subtype_supertype( + self.stack_types[self.stack_types.len() - 1 - index], + expected, + ) + } + fn assert_block_stack_len(&self, depth: usize, minimal_len: usize) -> bool { + assert!(depth < self.blocks.len()); + let blocks_end = self.blocks.len(); + let block_offset = blocks_end - 1 - depth; + for i in block_offset..blocks_end { + if self.blocks[i].is_stack_polymorphic() { + return true; + } + } + let block_starts_at = self.blocks[block_offset].stack_starts_at; + self.stack_types.len() >= block_starts_at + minimal_len + } + fn assert_last_block_stack_len_exact(&self, len: usize) -> bool { + let block_starts_at = self.last_block().stack_starts_at; + if self.last_block().is_stack_polymorphic() { + let polymorphic_values = self.last_block().polymorphic_values.unwrap(); + self.stack_types.len() + polymorphic_values <= block_starts_at + len + } else { + self.stack_types.len() == block_starts_at + len + } + } + fn remove_frame_stack_types(&mut self, remove_count: usize) -> OperatorValidatorResult<()> { + if remove_count == 0 { + return Ok(()); + } + let last_block = self.blocks.last_mut().unwrap(); + if last_block.is_stack_polymorphic() { + let len = self.stack_types.len(); + let remove_non_polymorphic = len + .checked_sub(last_block.stack_starts_at) + .ok_or("invalid block signature")? + .min(remove_count); + self.stack_types.truncate(len - remove_non_polymorphic); + let polymorphic_values = last_block.polymorphic_values.unwrap(); + let remove_polymorphic = min(remove_count - remove_non_polymorphic, polymorphic_values); + last_block.polymorphic_values = Some(polymorphic_values - remove_polymorphic); + } else { + assert!(self.stack_types.len() >= last_block.stack_starts_at + remove_count); + let keep = self.stack_types.len() - remove_count; + self.stack_types.truncate(keep); + } + Ok(()) + } + fn push_block<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( + &mut self, + ty: TypeOrFuncType, + block_type: BlockType, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + let (start_types, return_types) = match ty { + TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]), + TypeOrFuncType::Type(ty) => (vec![], vec![ty]), + TypeOrFuncType::FuncType(idx) => { + let ty = resources + .type_at(idx) + // Note: This was an out-of-bounds memory access before + // the change to return `Option` at `type_at`. So + // I assumed that invalid indices at this point are + // bugs. + .expect("function type index is out of bounds"); + ( + wasm_func_type_inputs(ty) + .map(WasmType::to_parser_type) + .collect::<Vec<_>>(), + wasm_func_type_outputs(ty) + .map(WasmType::to_parser_type) + .collect::<Vec<_>>(), + ) + } + }; + if block_type == BlockType::If { + let last_block = self.blocks.last().unwrap(); + if !last_block.is_stack_polymorphic() + || self.stack_types.len() > last_block.stack_starts_at + { + self.stack_types.pop(); + } + assert!(self.stack_types.len() >= last_block.stack_starts_at); + } + for (i, ty) in start_types.iter().rev().enumerate() { + if !self.assert_stack_type_at(i, *ty) { + return Err("stack operand type mismatch"); + } + } + let stack_starts_at = self.stack_types.len() - start_types.len(); + self.blocks.push(BlockState { + start_types, + return_types, + stack_starts_at, + jump_to_top: block_type == BlockType::Loop, + is_else_allowed: block_type == BlockType::If, + is_dead_code: false, + polymorphic_values: None, + }); + Ok(()) + } + fn pop_block(&mut self) { + assert!(self.blocks.len() > 1); + let last_block = self.blocks.pop().unwrap(); + if last_block.is_stack_polymorphic() { + assert!( + self.stack_types.len() + <= last_block.return_types.len() + last_block.stack_starts_at + ); + } else { + assert!( + self.stack_types.len() + == last_block.return_types.len() + last_block.stack_starts_at + ); + } + let keep = last_block.stack_starts_at; + self.stack_types.truncate(keep); + self.stack_types.extend_from_slice(&last_block.return_types); + } + fn reset_block(&mut self) { + assert!(self.last_block().is_else_allowed); + let last_block = self.blocks.last_mut().unwrap(); + let keep = last_block.stack_starts_at; + self.stack_types.truncate(keep); + self.stack_types + .extend(last_block.start_types.iter().cloned()); + last_block.is_else_allowed = false; + last_block.polymorphic_values = None; + } + fn change_frame(&mut self, remove_count: usize) -> OperatorValidatorResult<()> { + self.remove_frame_stack_types(remove_count) + } + fn change_frame_with_type( + &mut self, + remove_count: usize, + ty: Type, + ) -> OperatorValidatorResult<()> { + self.remove_frame_stack_types(remove_count)?; + self.stack_types.push(ty); + Ok(()) + } + fn change_frame_with_types<I>( + &mut self, + remove_count: usize, + new_items: I, + ) -> OperatorValidatorResult<()> + where + I: Iterator<Item = Type>, + { + self.remove_frame_stack_types(remove_count)?; + self.stack_types.extend(new_items); + Ok(()) + } + fn change_frame_to_exact_types_from(&mut self, depth: usize) -> OperatorValidatorResult<()> { + let types = self.block_at(depth).return_types.clone(); + let last_block = self.blocks.last_mut().unwrap(); + let keep = last_block.stack_starts_at; + self.stack_types.truncate(keep); + self.stack_types.extend_from_slice(&types); + last_block.polymorphic_values = None; + Ok(()) + } + fn change_frame_after_select(&mut self, ty: Option<Type>) -> OperatorValidatorResult<()> { + self.remove_frame_stack_types(3)?; + if ty.is_none() { + let last_block = self.blocks.last_mut().unwrap(); + assert!(last_block.is_stack_polymorphic()); + last_block.polymorphic_values = Some(last_block.polymorphic_values.unwrap() + 1); + return Ok(()); + } + self.stack_types.push(ty.unwrap()); + Ok(()) + } + fn start_dead_code(&mut self) { + let last_block = self.blocks.last_mut().unwrap(); + let keep = last_block.stack_starts_at; + self.stack_types.truncate(keep); + last_block.is_dead_code = true; + last_block.polymorphic_values = Some(0); + } + fn end_function(&mut self) { + self.end_function = true; + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +enum BlockType { + Block, + Loop, + If, +} + +pub enum FunctionEnd { + No, + Yes, +} + +type OperatorValidatorResult<T> = result::Result<T, &'static str>; + +#[derive(Copy, Clone, Debug)] +pub struct OperatorValidatorConfig { + pub enable_threads: bool, + pub enable_reference_types: bool, + pub enable_simd: bool, + pub enable_bulk_memory: bool, + pub enable_multi_value: bool, + + #[cfg(feature = "deterministic")] + pub deterministic_only: bool, +} + +pub(crate) const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig = + OperatorValidatorConfig { + enable_threads: false, + enable_reference_types: false, + enable_simd: false, + enable_bulk_memory: false, + enable_multi_value: false, + + #[cfg(feature = "deterministic")] + deterministic_only: true, + }; + +#[derive(Debug)] +pub(crate) struct OperatorValidator { + func_state: FuncState, + config: OperatorValidatorConfig, +} + +impl OperatorValidator { + pub fn new<F, T>( + func_type: &F, + locals: &[(u32, Type)], + config: OperatorValidatorConfig, + ) -> OperatorValidator + where + F: WasmFuncType<Type = T>, + T: WasmType, + { + let local_types = { + let mut local_types = wasm_func_type_inputs(func_type) + .map(WasmType::to_parser_type) + .collect::<Vec<_>>(); + for local in locals { + for _ in 0..local.0 { + local_types.push(local.1); + } + } + local_types + }; + let mut blocks = Vec::new(); + let last_returns = wasm_func_type_outputs(func_type) + .map(WasmType::to_parser_type) + .collect::<Vec<_>>(); + blocks.push(BlockState { + start_types: vec![], + return_types: last_returns, + stack_starts_at: 0, + jump_to_top: false, + is_else_allowed: false, + is_dead_code: false, + polymorphic_values: None, + }); + + OperatorValidator { + func_state: FuncState { + local_types, + blocks, + stack_types: Vec::new(), + end_function: false, + }, + config, + } + } + + pub fn is_dead_code(&self) -> bool { + self.func_state.last_block().is_dead_code + } + + fn check_frame_size(&self, require_count: usize) -> OperatorValidatorResult<()> { + if !self.func_state.assert_block_stack_len(0, require_count) { + Err("not enough operands") + } else { + Ok(()) + } + } + + fn check_operands_1(&self, operand: Type) -> OperatorValidatorResult<()> { + self.check_frame_size(1)?; + if !self.func_state.assert_stack_type_at(0, operand) { + return Err("stack operand type mismatch"); + } + Ok(()) + } + + fn check_operands_2(&self, operand1: Type, operand2: Type) -> OperatorValidatorResult<()> { + self.check_frame_size(2)?; + if !self.func_state.assert_stack_type_at(1, operand1) { + return Err("stack operand type mismatch"); + } + if !self.func_state.assert_stack_type_at(0, operand2) { + return Err("stack operand type mismatch"); + } + Ok(()) + } + + fn check_operands_3( + &self, + operand1: Type, + operand2: Type, + operand3: Type, + ) -> OperatorValidatorResult<()> { + self.check_frame_size(3)?; + if !self.func_state.assert_stack_type_at(2, operand1) { + return Err("stack operand type mismatch"); + } + if !self.func_state.assert_stack_type_at(1, operand2) { + return Err("stack operand type mismatch"); + } + if !self.func_state.assert_stack_type_at(0, operand3) { + return Err("stack operand type mismatch"); + } + Ok(()) + } + + fn check_operands<I>(&self, expected_types: I) -> OperatorValidatorResult<()> + where + I: ExactSizeIterator<Item = Type>, + { + let len = expected_types.len(); + self.check_frame_size(len)?; + for (i, expected_type) in expected_types.enumerate() { + if !self + .func_state + .assert_stack_type_at(len - 1 - i, expected_type) + { + return Err("stack operand type mismatch"); + } + } + Ok(()) + } + + fn check_block_return_types( + &self, + block: &BlockState, + reserve_items: usize, + ) -> OperatorValidatorResult<()> { + if !self.config.enable_multi_value && block.return_types.len() > 1 { + return Err("blocks, loops, and ifs may only return at most one \ + value when multi-value is not enabled"); + } + let len = block.return_types.len(); + for i in 0..len { + if !self + .func_state + .assert_stack_type_at(len - 1 - i + reserve_items, block.return_types[i]) + { + return Err("stack item type does not match block item type"); + } + } + Ok(()) + } + + fn check_block_return(&self) -> OperatorValidatorResult<()> { + let len = self.func_state.last_block().return_types.len(); + if !self.func_state.assert_last_block_stack_len_exact(len) { + return Err("stack size does not match block type"); + } + self.check_block_return_types(self.func_state.last_block(), 0) + } + + fn check_jump_from_block( + &self, + relative_depth: u32, + reserve_items: usize, + ) -> OperatorValidatorResult<()> { + if relative_depth as usize >= self.func_state.blocks.len() { + return Err("invalid block depth"); + } + let block = self.func_state.block_at(relative_depth as usize); + if block.jump_to_top { + if !self.func_state.assert_block_stack_len(0, reserve_items) { + return Err("stack size does not match target loop type"); + } + return Ok(()); + } + + let len = block.return_types.len(); + if !self + .func_state + .assert_block_stack_len(0, len + reserve_items) + { + return Err("stack size does not match target block type"); + } + self.check_block_return_types(block, reserve_items) + } + + fn match_block_return(&self, depth1: u32, depth2: u32) -> OperatorValidatorResult<()> { + if depth1 as usize >= self.func_state.blocks.len() { + return Err("invalid block depth"); + } + if depth2 as usize >= self.func_state.blocks.len() { + return Err("invalid block depth"); + } + let block1 = self.func_state.block_at(depth1 as usize); + let block2 = self.func_state.block_at(depth2 as usize); + let return_types1 = &block1.return_types; + let return_types2 = &block2.return_types; + if block1.jump_to_top || block2.jump_to_top { + if block1.jump_to_top { + if !block2.jump_to_top && !return_types2.is_empty() { + return Err("block types do not match"); + } + } else if !return_types1.is_empty() { + return Err("block types do not match"); + } + } else if *return_types1 != *return_types2 { + return Err("block types do not match"); + } + Ok(()) + } + + fn check_memory_index< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &self, + memory_index: u32, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + if resources.memory_at(memory_index).is_none() { + return Err("no linear memories are present"); + } + Ok(()) + } + + fn check_shared_memory_index< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &self, + memory_index: u32, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + match resources.memory_at(memory_index) { + Some(memory) if !memory.is_shared() => { + return Err("atomic accesses require shared memory") + } + None => return Err("no linear memories are present"), + _ => Ok(()), + } + } + + fn check_memarg<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( + &self, + memarg: MemoryImmediate, + max_align: u32, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + self.check_memory_index(0, resources)?; + let align = memarg.flags; + if align > max_align { + return Err("alignment must not be larger than natural"); + } + Ok(()) + } + + #[cfg(feature = "deterministic")] + fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.deterministic_only { + return Err("deterministic_only support is not enabled"); + } + Ok(()) + } + + #[inline(always)] + #[cfg(not(feature = "deterministic"))] + fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> { + Ok(()) + } + + fn check_threads_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_threads { + return Err("threads support is not enabled"); + } + Ok(()) + } + + fn check_reference_types_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_reference_types { + return Err("reference types support is not enabled"); + } + Ok(()) + } + + fn check_simd_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_simd { + return Err("SIMD support is not enabled"); + } + Ok(()) + } + + fn check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()> { + if !self.config.enable_bulk_memory { + return Err("bulk memory support is not enabled"); + } + Ok(()) + } + + fn check_shared_memarg_wo_align< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &self, + _: MemoryImmediate, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + self.check_shared_memory_index(0, resources)?; + Ok(()) + } + + fn check_simd_lane_index(&self, index: SIMDLaneIndex, max: u8) -> OperatorValidatorResult<()> { + if index >= max { + return Err("SIMD index out of bounds"); + } + Ok(()) + } + + fn check_block_type<F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( + &self, + ty: TypeOrFuncType, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<()> { + match ty { + TypeOrFuncType::Type(Type::EmptyBlockType) + | TypeOrFuncType::Type(Type::I32) + | TypeOrFuncType::Type(Type::I64) + | TypeOrFuncType::Type(Type::F32) + | TypeOrFuncType::Type(Type::F64) => Ok(()), + TypeOrFuncType::Type(Type::AnyRef) | TypeOrFuncType::Type(Type::AnyFunc) => { + self.check_reference_types_enabled() + } + TypeOrFuncType::Type(Type::V128) => self.check_simd_enabled(), + TypeOrFuncType::FuncType(idx) => match resources.type_at(idx) { + None => Err("type index out of bounds"), + Some(ty) if !self.config.enable_multi_value => { + if ty.len_outputs() > 1 { + return Err("blocks, loops, and ifs may only return at most one \ + value when multi-value is not enabled"); + } + if ty.len_inputs() > 0 { + return Err("blocks, loops, and ifs accept no parameters \ + when multi-value is not enabled"); + } + Ok(()) + } + Some(_) => Ok(()), + }, + _ => Err("invalid block return type"), + } + } + + fn check_block_params< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &self, + ty: TypeOrFuncType, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + skip: usize, + ) -> OperatorValidatorResult<()> { + if let TypeOrFuncType::FuncType(idx) = ty { + let func_ty = resources + .type_at(idx) + // Note: This was an out-of-bounds memory access before + // the change to return `Option` at `type_at`. So + // I assumed that invalid indices at this point are + // bugs. + .expect("function type index is out of bounds"); + let len = func_ty.len_inputs(); + self.check_frame_size(len + skip)?; + for (i, ty) in wasm_func_type_inputs(func_ty).enumerate() { + if !self + .func_state + .assert_stack_type_at(len - 1 - i + skip, ty.to_parser_type()) + { + return Err("stack operand type mismatch for block"); + } + } + } + Ok(()) + } + + fn check_select(&self) -> OperatorValidatorResult<Option<Type>> { + self.check_frame_size(3)?; + let func_state = &self.func_state; + let last_block = func_state.last_block(); + + let ty = if last_block.is_stack_polymorphic() { + match func_state.stack_types.len() - last_block.stack_starts_at { + 0 => return Ok(None), + 1 => { + self.check_operands_1(Type::I32)?; + return Ok(None); + } + 2 => { + self.check_operands_1(Type::I32)?; + func_state.stack_types[func_state.stack_types.len() - 2] + } + _ => { + let ty = func_state.stack_types[func_state.stack_types.len() - 3]; + self.check_operands_2(ty, Type::I32)?; + ty + } + } + } else { + let ty = func_state.stack_types[func_state.stack_types.len() - 3]; + self.check_operands_2(ty, Type::I32)?; + ty + }; + + if !ty.is_valid_for_old_select() { + return Err("invalid type for select"); + } + + Ok(Some(ty)) + } + + pub(crate) fn process_operator< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, + >( + &mut self, + operator: &Operator, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> OperatorValidatorResult<FunctionEnd> { + if self.func_state.end_function { + return Err("unexpected operator"); + } + match *operator { + Operator::Unreachable => self.func_state.start_dead_code(), + Operator::Nop => (), + Operator::Block { ty } => { + self.check_block_type(ty, resources)?; + self.check_block_params(ty, resources, 0)?; + self.func_state + .push_block(ty, BlockType::Block, resources)?; + } + Operator::Loop { ty } => { + self.check_block_type(ty, resources)?; + self.check_block_params(ty, resources, 0)?; + self.func_state.push_block(ty, BlockType::Loop, resources)?; + } + Operator::If { ty } => { + self.check_block_type(ty, resources)?; + self.check_operands_1(Type::I32)?; + self.check_block_params(ty, resources, 1)?; + self.func_state.push_block(ty, BlockType::If, resources)?; + } + Operator::Else => { + if !self.func_state.last_block().is_else_allowed { + return Err("unexpected else: if block is not started"); + } + self.check_block_return()?; + self.func_state.reset_block() + } + Operator::End => { + self.check_block_return()?; + if self.func_state.blocks.len() == 1 { + self.func_state.end_function(); + return Ok(FunctionEnd::Yes); + } + + let last_block = &self.func_state.last_block(); + if last_block.is_else_allowed && last_block.start_types != last_block.return_types { + return Err("else is expected: if block has a type that can't be implemented with a no-op"); + } + self.func_state.pop_block() + } + Operator::Br { relative_depth } => { + self.check_jump_from_block(relative_depth, 0)?; + self.func_state.start_dead_code() + } + Operator::BrIf { relative_depth } => { + self.check_operands_1(Type::I32)?; + self.check_jump_from_block(relative_depth, 1)?; + if self.func_state.last_block().is_stack_polymorphic() { + self.func_state + .change_frame_to_exact_types_from(relative_depth as usize)?; + } else { + self.func_state.change_frame(1)?; + } + } + Operator::BrTable { ref table } => { + self.check_operands_1(Type::I32)?; + let mut depth0: Option<u32> = None; + for relative_depth in table { + if depth0.is_none() { + self.check_jump_from_block(relative_depth, 1)?; + depth0 = Some(relative_depth); + continue; + } + self.match_block_return(relative_depth, depth0.unwrap())?; + } + self.func_state.start_dead_code() + } + Operator::Return => { + let depth = (self.func_state.blocks.len() - 1) as u32; + self.check_jump_from_block(depth, 0)?; + self.func_state.start_dead_code() + } + Operator::Call { function_index } => match resources.func_type_id_at(function_index) { + Some(type_index) => { + let ty = resources + .type_at(type_index) + // Note: This was an out-of-bounds memory access before + // the change to return `Option` at `type_at`. So + // I assumed that invalid indices at this point are + // bugs. + .expect("function type index is out of bounds"); + self.check_operands(wasm_func_type_inputs(ty).map(WasmType::to_parser_type))?; + self.func_state.change_frame_with_types( + ty.len_inputs(), + wasm_func_type_outputs(ty).map(WasmType::to_parser_type), + )?; + } + None => return Err("function index out of bounds"), + }, + Operator::CallIndirect { index, table_index } => { + if resources.table_at(table_index).is_none() { + return Err("table index out of bounds"); + } + match resources.type_at(index) { + None => return Err("type index out of bounds"), + Some(ty) => { + let types = { + let mut types = Vec::with_capacity(ty.len_inputs() + 1); + types.extend(wasm_func_type_inputs(ty).map(WasmType::to_parser_type)); + types.push(Type::I32); + types + }; + self.check_operands(types.into_iter())?; + self.func_state.change_frame_with_types( + ty.len_inputs() + 1, + wasm_func_type_outputs(ty).map(WasmType::to_parser_type), + )?; + } + } + } + Operator::Drop => { + self.check_frame_size(1)?; + self.func_state.change_frame(1)?; + } + Operator::Select => { + let ty = self.check_select()?; + self.func_state.change_frame_after_select(ty)?; + } + Operator::TypedSelect { ty } => { + self.check_operands_3(Type::I32, ty, ty)?; + self.func_state.change_frame_after_select(Some(ty))?; + } + Operator::LocalGet { local_index } => { + if local_index as usize >= self.func_state.local_types.len() { + return Err("local index out of bounds"); + } + let local_type = self.func_state.local_types[local_index as usize]; + self.func_state.change_frame_with_type(0, local_type)?; + } + Operator::LocalSet { local_index } => { + if local_index as usize >= self.func_state.local_types.len() { + return Err("local index out of bounds"); + } + let local_type = self.func_state.local_types[local_index as usize]; + self.check_operands_1(local_type)?; + self.func_state.change_frame(1)?; + } + Operator::LocalTee { local_index } => { + if local_index as usize >= self.func_state.local_types.len() { + return Err("local index out of bounds"); + } + let local_type = self.func_state.local_types[local_index as usize]; + self.check_operands_1(local_type)?; + self.func_state.change_frame_with_type(1, local_type)?; + } + Operator::GlobalGet { global_index } => { + if let Some(ty) = resources.global_at(global_index) { + self.func_state + .change_frame_with_type(0, ty.content_type().to_parser_type())?; + } else { + return Err("global index out of bounds"); + }; + } + Operator::GlobalSet { global_index } => { + if let Some(ty) = resources.global_at(global_index) { + if !ty.is_mutable() { + return Err("global expected to be mutable"); + } + self.check_operands_1(ty.content_type().to_parser_type())?; + self.func_state.change_frame(1)?; + } else { + return Err("global index out of bounds"); + }; + } + Operator::I32Load { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64Load { memarg } => { + self.check_memarg(memarg, 3, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::F32Load { memarg } => { + self.check_non_deterministic_enabled()?; + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F64Load { memarg } => { + self.check_non_deterministic_enabled()?; + self.check_memarg(memarg, 3, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::I32Load8S { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Load8U { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Load16S { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Load16U { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64Load8S { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load8U { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load16S { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load16U { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load32S { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Load32U { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I32Store { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame(2)?; + } + Operator::I64Store { memarg } => { + self.check_memarg(memarg, 3, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::F32Store { memarg } => { + self.check_non_deterministic_enabled()?; + self.check_memarg(memarg, 2, resources)?; + self.check_operands_2(Type::I32, Type::F32)?; + self.func_state.change_frame(2)?; + } + Operator::F64Store { memarg } => { + self.check_non_deterministic_enabled()?; + self.check_memarg(memarg, 3, resources)?; + self.check_operands_2(Type::I32, Type::F64)?; + self.func_state.change_frame(2)?; + } + Operator::I32Store8 { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame(2)?; + } + Operator::I32Store16 { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame(2)?; + } + Operator::I64Store8 { memarg } => { + self.check_memarg(memarg, 0, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::I64Store16 { memarg } => { + self.check_memarg(memarg, 1, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::I64Store32 { memarg } => { + self.check_memarg(memarg, 2, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::MemorySize { + reserved: memory_index, + } => { + self.check_memory_index(memory_index, resources)?; + self.func_state.change_frame_with_type(0, Type::I32)?; + } + Operator::MemoryGrow { + reserved: memory_index, + } => { + self.check_memory_index(memory_index, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Const { .. } => self.func_state.change_frame_with_type(0, Type::I32)?, + Operator::I64Const { .. } => self.func_state.change_frame_with_type(0, Type::I64)?, + Operator::F32Const { .. } => { + self.check_non_deterministic_enabled()?; + self.func_state.change_frame_with_type(0, Type::F32)?; + } + Operator::F64Const { .. } => { + self.check_non_deterministic_enabled()?; + self.func_state.change_frame_with_type(0, Type::F64)?; + } + Operator::I32Eqz => { + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Eq + | Operator::I32Ne + | Operator::I32LtS + | Operator::I32LtU + | Operator::I32GtS + | Operator::I32GtU + | Operator::I32LeS + | Operator::I32LeU + | Operator::I32GeS + | Operator::I32GeU => { + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I64Eqz => { + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64Eq + | Operator::I64Ne + | Operator::I64LtS + | Operator::I64LtU + | Operator::I64GtS + | Operator::I64GtU + | Operator::I64LeS + | Operator::I64LeU + | Operator::I64GeS + | Operator::I64GeU => { + self.check_operands_2(Type::I64, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::F32Eq + | Operator::F32Ne + | Operator::F32Lt + | Operator::F32Gt + | Operator::F32Le + | Operator::F32Ge => { + self.check_non_deterministic_enabled()?; + self.check_operands_2(Type::F32, Type::F32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::F64Eq + | Operator::F64Ne + | Operator::F64Lt + | Operator::F64Gt + | Operator::F64Le + | Operator::F64Ge => { + self.check_non_deterministic_enabled()?; + self.check_operands_2(Type::F64, Type::F64)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I32Clz | Operator::I32Ctz | Operator::I32Popcnt => { + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32Add + | Operator::I32Sub + | Operator::I32Mul + | Operator::I32DivS + | Operator::I32DivU + | Operator::I32RemS + | Operator::I32RemU + | Operator::I32And + | Operator::I32Or + | Operator::I32Xor + | Operator::I32Shl + | Operator::I32ShrS + | Operator::I32ShrU + | Operator::I32Rotl + | Operator::I32Rotr => { + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I64Clz | Operator::I64Ctz | Operator::I64Popcnt => { + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64Add + | Operator::I64Sub + | Operator::I64Mul + | Operator::I64DivS + | Operator::I64DivU + | Operator::I64RemS + | Operator::I64RemU + | Operator::I64And + | Operator::I64Or + | Operator::I64Xor + | Operator::I64Shl + | Operator::I64ShrS + | Operator::I64ShrU + | Operator::I64Rotl + | Operator::I64Rotr => { + self.check_operands_2(Type::I64, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::I64)?; + } + Operator::F32Abs + | Operator::F32Neg + | Operator::F32Ceil + | Operator::F32Floor + | Operator::F32Trunc + | Operator::F32Nearest + | Operator::F32Sqrt => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F32Add + | Operator::F32Sub + | Operator::F32Mul + | Operator::F32Div + | Operator::F32Min + | Operator::F32Max + | Operator::F32Copysign => { + self.check_non_deterministic_enabled()?; + self.check_operands_2(Type::F32, Type::F32)?; + self.func_state.change_frame_with_type(2, Type::F32)?; + } + Operator::F64Abs + | Operator::F64Neg + | Operator::F64Ceil + | Operator::F64Floor + | Operator::F64Trunc + | Operator::F64Nearest + | Operator::F64Sqrt => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::F64Add + | Operator::F64Sub + | Operator::F64Mul + | Operator::F64Div + | Operator::F64Min + | Operator::F64Max + | Operator::F64Copysign => { + self.check_non_deterministic_enabled()?; + self.check_operands_2(Type::F64, Type::F64)?; + self.func_state.change_frame_with_type(2, Type::F64)?; + } + Operator::I32WrapI64 => { + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32TruncF32S | Operator::I32TruncF32U => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32TruncF64S | Operator::I32TruncF64U => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64ExtendI32S | Operator::I64ExtendI32U => { + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64TruncF32S | Operator::I64TruncF32U => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64TruncF64S | Operator::I64TruncF64U => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::F32ConvertI32S | Operator::F32ConvertI32U => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F32ConvertI64S | Operator::F32ConvertI64U => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F32DemoteF64 => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F64ConvertI32S | Operator::F64ConvertI32U => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::F64ConvertI64S | Operator::F64ConvertI64U => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::F64PromoteF32 => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::I32ReinterpretF32 => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64ReinterpretF64 => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::F32ReinterpretI32 => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F64ReinterpretI64 => { + self.check_non_deterministic_enabled()?; + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::I32TruncSatF32S | Operator::I32TruncSatF32U => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32TruncSatF64S | Operator::I32TruncSatF64U => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64TruncSatF32S | Operator::I64TruncSatF32U => { + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64TruncSatF64S | Operator::I64TruncSatF64U => { + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I32Extend16S | Operator::I32Extend8S => { + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + + Operator::I64Extend32S | Operator::I64Extend16S | Operator::I64Extend8S => { + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + + Operator::I32AtomicLoad { memarg } + | Operator::I32AtomicLoad16U { memarg } + | Operator::I32AtomicLoad8U { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I64AtomicLoad { memarg } + | Operator::I64AtomicLoad32U { memarg } + | Operator::I64AtomicLoad16U { memarg } + | Operator::I64AtomicLoad8U { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I32AtomicStore { memarg } + | Operator::I32AtomicStore16 { memarg } + | Operator::I32AtomicStore8 { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame(2)?; + } + Operator::I64AtomicStore { memarg } + | Operator::I64AtomicStore32 { memarg } + | Operator::I64AtomicStore16 { memarg } + | Operator::I64AtomicStore8 { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame(2)?; + } + Operator::I32AtomicRmwAdd { memarg } + | Operator::I32AtomicRmwSub { memarg } + | Operator::I32AtomicRmwAnd { memarg } + | Operator::I32AtomicRmwOr { memarg } + | Operator::I32AtomicRmwXor { memarg } + | Operator::I32AtomicRmw16AddU { memarg } + | Operator::I32AtomicRmw16SubU { memarg } + | Operator::I32AtomicRmw16AndU { memarg } + | Operator::I32AtomicRmw16OrU { memarg } + | Operator::I32AtomicRmw16XorU { memarg } + | Operator::I32AtomicRmw8AddU { memarg } + | Operator::I32AtomicRmw8SubU { memarg } + | Operator::I32AtomicRmw8AndU { memarg } + | Operator::I32AtomicRmw8OrU { memarg } + | Operator::I32AtomicRmw8XorU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I64AtomicRmwAdd { memarg } + | Operator::I64AtomicRmwSub { memarg } + | Operator::I64AtomicRmwAnd { memarg } + | Operator::I64AtomicRmwOr { memarg } + | Operator::I64AtomicRmwXor { memarg } + | Operator::I64AtomicRmw32AddU { memarg } + | Operator::I64AtomicRmw32SubU { memarg } + | Operator::I64AtomicRmw32AndU { memarg } + | Operator::I64AtomicRmw32OrU { memarg } + | Operator::I64AtomicRmw32XorU { memarg } + | Operator::I64AtomicRmw16AddU { memarg } + | Operator::I64AtomicRmw16SubU { memarg } + | Operator::I64AtomicRmw16AndU { memarg } + | Operator::I64AtomicRmw16OrU { memarg } + | Operator::I64AtomicRmw16XorU { memarg } + | Operator::I64AtomicRmw8AddU { memarg } + | Operator::I64AtomicRmw8SubU { memarg } + | Operator::I64AtomicRmw8AndU { memarg } + | Operator::I64AtomicRmw8OrU { memarg } + | Operator::I64AtomicRmw8XorU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::I64)?; + } + Operator::I32AtomicRmwXchg { memarg } + | Operator::I32AtomicRmw16XchgU { memarg } + | Operator::I32AtomicRmw8XchgU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I32AtomicRmwCmpxchg { memarg } + | Operator::I32AtomicRmw16CmpxchgU { memarg } + | Operator::I32AtomicRmw8CmpxchgU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(3, Type::I32)?; + } + Operator::I64AtomicRmwXchg { memarg } + | Operator::I64AtomicRmw32XchgU { memarg } + | Operator::I64AtomicRmw16XchgU { memarg } + | Operator::I64AtomicRmw8XchgU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::I64)?; + } + Operator::I64AtomicRmwCmpxchg { memarg } + | Operator::I64AtomicRmw32CmpxchgU { memarg } + | Operator::I64AtomicRmw16CmpxchgU { memarg } + | Operator::I64AtomicRmw8CmpxchgU { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_3(Type::I32, Type::I64, Type::I64)?; + self.func_state.change_frame_with_type(3, Type::I64)?; + } + Operator::AtomicNotify { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_2(Type::I32, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::I32AtomicWait { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_3(Type::I32, Type::I32, Type::I64)?; + self.func_state.change_frame_with_type(3, Type::I32)?; + } + Operator::I64AtomicWait { memarg } => { + self.check_threads_enabled()?; + self.check_shared_memarg_wo_align(memarg, resources)?; + self.check_operands_3(Type::I32, Type::I64, Type::I64)?; + self.func_state.change_frame_with_type(3, Type::I32)?; + } + Operator::AtomicFence { ref flags } => { + self.check_threads_enabled()?; + if *flags != 0 { + return Err("non-zero flags for fence not supported yet"); + } + } + Operator::RefNull => { + self.check_reference_types_enabled()?; + self.func_state.change_frame_with_type(0, Type::NullRef)?; + } + Operator::RefIsNull => { + self.check_reference_types_enabled()?; + self.check_operands_1(Type::AnyRef)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::RefFunc { function_index } => { + self.check_reference_types_enabled()?; + if resources.func_type_id_at(function_index).is_none() { + return Err("function index out of bounds"); + } + self.func_state.change_frame_with_type(0, Type::AnyFunc)?; + } + Operator::V128Load { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 4, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V128Store { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 4, resources)?; + self.check_operands_2(Type::I32, Type::V128)?; + self.func_state.change_frame(2)?; + } + Operator::V128Const { .. } => { + self.check_simd_enabled()?; + self.func_state.change_frame_with_type(0, Type::V128)?; + } + Operator::I8x16Splat | Operator::I16x8Splat | Operator::I32x4Splat => { + self.check_simd_enabled()?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::I64x2Splat => { + self.check_simd_enabled()?; + self.check_operands_1(Type::I64)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::F32x4Splat => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_operands_1(Type::F32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::F64x2Splat => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_operands_1(Type::F64)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::I8x16ExtractLaneS { lane } | Operator::I8x16ExtractLaneU { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 16)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I16x8ExtractLaneS { lane } | Operator::I16x8ExtractLaneU { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 8)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I32x4ExtractLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I8x16ReplaceLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 16)?; + self.check_operands_2(Type::V128, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::I16x8ReplaceLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 8)?; + self.check_operands_2(Type::V128, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::I32x4ReplaceLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.check_operands_2(Type::V128, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::I64x2ExtractLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I64)?; + } + Operator::I64x2ReplaceLane { lane } => { + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.check_operands_2(Type::V128, Type::I64)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::F32x4ExtractLane { lane } => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::F32)?; + } + Operator::F32x4ReplaceLane { lane } => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.check_operands_2(Type::V128, Type::F32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::F64x2ExtractLane { lane } => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::F64)?; + } + Operator::F64x2ReplaceLane { lane } => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.check_operands_2(Type::V128, Type::F64)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::F32x4Eq + | Operator::F32x4Ne + | Operator::F32x4Lt + | Operator::F32x4Gt + | Operator::F32x4Le + | Operator::F32x4Ge + | Operator::F64x2Eq + | Operator::F64x2Ne + | Operator::F64x2Lt + | Operator::F64x2Gt + | Operator::F64x2Le + | Operator::F64x2Ge + | Operator::F32x4Add + | Operator::F32x4Sub + | Operator::F32x4Mul + | Operator::F32x4Div + | Operator::F32x4Min + | Operator::F32x4Max + | Operator::F64x2Add + | Operator::F64x2Sub + | Operator::F64x2Mul + | Operator::F64x2Div + | Operator::F64x2Min + | Operator::F64x2Max => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::V128)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::I8x16Eq + | Operator::I8x16Ne + | Operator::I8x16LtS + | Operator::I8x16LtU + | Operator::I8x16GtS + | Operator::I8x16GtU + | Operator::I8x16LeS + | Operator::I8x16LeU + | Operator::I8x16GeS + | Operator::I8x16GeU + | Operator::I16x8Eq + | Operator::I16x8Ne + | Operator::I16x8LtS + | Operator::I16x8LtU + | Operator::I16x8GtS + | Operator::I16x8GtU + | Operator::I16x8LeS + | Operator::I16x8LeU + | Operator::I16x8GeS + | Operator::I16x8GeU + | Operator::I32x4Eq + | Operator::I32x4Ne + | Operator::I32x4LtS + | Operator::I32x4LtU + | Operator::I32x4GtS + | Operator::I32x4GtU + | Operator::I32x4LeS + | Operator::I32x4LeU + | Operator::I32x4GeS + | Operator::I32x4GeU + | Operator::V128And + | Operator::V128AndNot + | Operator::V128Or + | Operator::V128Xor + | Operator::I8x16Add + | Operator::I8x16AddSaturateS + | Operator::I8x16AddSaturateU + | Operator::I8x16Sub + | Operator::I8x16SubSaturateS + | Operator::I8x16SubSaturateU + | Operator::I8x16Mul + | Operator::I16x8Add + | Operator::I16x8AddSaturateS + | Operator::I16x8AddSaturateU + | Operator::I16x8Sub + | Operator::I16x8SubSaturateS + | Operator::I16x8SubSaturateU + | Operator::I16x8Mul + | Operator::I32x4Add + | Operator::I32x4Sub + | Operator::I32x4Mul + | Operator::I64x2Add + | Operator::I64x2Sub + | Operator::I64x2Mul + | Operator::I8x16RoundingAverageU + | Operator::I16x8RoundingAverageU + | Operator::I8x16NarrowI16x8S + | Operator::I8x16NarrowI16x8U + | Operator::I16x8NarrowI32x4S + | Operator::I16x8NarrowI32x4U => { + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::V128)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::F32x4Abs + | Operator::F32x4Neg + | Operator::F32x4Sqrt + | Operator::F64x2Abs + | Operator::F64x2Neg + | Operator::F64x2Sqrt + | Operator::F32x4ConvertI32x4S + | Operator::F32x4ConvertI32x4U + | Operator::F64x2ConvertI64x2S + | Operator::F64x2ConvertI64x2U => { + self.check_non_deterministic_enabled()?; + self.check_simd_enabled()?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V128Not + | Operator::I8x16Neg + | Operator::I16x8Neg + | Operator::I32x4Neg + | Operator::I64x2Neg + | Operator::I32x4TruncSatF32x4S + | Operator::I32x4TruncSatF32x4U + | Operator::I64x2TruncSatF64x2S + | Operator::I64x2TruncSatF64x2U + | Operator::I16x8WidenLowI8x16S + | Operator::I16x8WidenHighI8x16S + | Operator::I16x8WidenLowI8x16U + | Operator::I16x8WidenHighI8x16U + | Operator::I32x4WidenLowI16x8S + | Operator::I32x4WidenHighI16x8S + | Operator::I32x4WidenLowI16x8U + | Operator::I32x4WidenHighI16x8U => { + self.check_simd_enabled()?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V128Bitselect => { + self.check_simd_enabled()?; + self.check_operands_3(Type::V128, Type::V128, Type::V128)?; + self.func_state.change_frame_with_type(3, Type::V128)?; + } + Operator::I8x16AnyTrue + | Operator::I8x16AllTrue + | Operator::I16x8AnyTrue + | Operator::I16x8AllTrue + | Operator::I32x4AnyTrue + | Operator::I32x4AllTrue + | Operator::I64x2AnyTrue + | Operator::I64x2AllTrue => { + self.check_simd_enabled()?; + self.check_operands_1(Type::V128)?; + self.func_state.change_frame_with_type(1, Type::I32)?; + } + Operator::I8x16Shl + | Operator::I8x16ShrS + | Operator::I8x16ShrU + | Operator::I16x8Shl + | Operator::I16x8ShrS + | Operator::I16x8ShrU + | Operator::I32x4Shl + | Operator::I32x4ShrS + | Operator::I32x4ShrU + | Operator::I64x2Shl + | Operator::I64x2ShrS + | Operator::I64x2ShrU => { + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::V8x16Swizzle => { + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::V128)?; + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::V8x16Shuffle { ref lanes } => { + self.check_simd_enabled()?; + self.check_operands_2(Type::V128, Type::V128)?; + for i in lanes { + self.check_simd_lane_index(*i, 32)?; + } + self.func_state.change_frame_with_type(2, Type::V128)?; + } + Operator::V8x16LoadSplat { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 0, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V16x8LoadSplat { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 1, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V32x4LoadSplat { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 2, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + Operator::V64x2LoadSplat { memarg } + | Operator::I16x8Load8x8S { memarg } + | Operator::I16x8Load8x8U { memarg } + | Operator::I32x4Load16x4S { memarg } + | Operator::I32x4Load16x4U { memarg } + | Operator::I64x2Load32x2S { memarg } + | Operator::I64x2Load32x2U { memarg } => { + self.check_simd_enabled()?; + self.check_memarg(memarg, 3, resources)?; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, Type::V128)?; + } + + Operator::MemoryInit { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.data_count() { + return Err("segment index out of bounds"); + } + self.check_memory_index(0, resources)?; + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame(3)?; + } + Operator::DataDrop { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.data_count() { + return Err("segment index out of bounds"); + } + } + Operator::MemoryCopy | Operator::MemoryFill => { + self.check_bulk_memory_enabled()?; + self.check_memory_index(0, resources)?; + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame(3)?; + } + Operator::TableInit { segment, table } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.element_count() { + return Err("segment index out of bounds"); + } + if table > 0 { + self.check_reference_types_enabled()?; + } + if resources.table_at(table).is_none() { + return Err("table index out of bounds"); + } + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame(3)?; + } + Operator::ElemDrop { segment } => { + self.check_bulk_memory_enabled()?; + if segment >= resources.element_count() { + return Err("segment index out of bounds"); + } + } + Operator::TableCopy { + src_table, + dst_table, + } => { + self.check_bulk_memory_enabled()?; + if src_table > 0 || dst_table > 0 { + self.check_reference_types_enabled()?; + } + if resources.table_at(src_table).is_none() + || resources.table_at(dst_table).is_none() + { + return Err("table index out of bounds"); + } + self.check_operands_3(Type::I32, Type::I32, Type::I32)?; + self.func_state.change_frame(3)?; + } + Operator::TableGet { table } => { + self.check_reference_types_enabled()?; + let ty = match resources.table_at(table) { + Some(ty) => ty.element_type().to_parser_type(), + None => return Err("table index out of bounds"), + }; + self.check_operands_1(Type::I32)?; + self.func_state.change_frame_with_type(1, ty)?; + } + Operator::TableSet { table } => { + self.check_reference_types_enabled()?; + let ty = match resources.table_at(table) { + Some(ty) => ty.element_type().to_parser_type(), + None => return Err("table index out of bounds"), + }; + self.check_operands_2(Type::I32, ty)?; + self.func_state.change_frame(2)?; + } + Operator::TableGrow { table } => { + self.check_reference_types_enabled()?; + let ty = match resources.table_at(table) { + Some(ty) => ty.element_type().to_parser_type(), + None => return Err("table index out of bounds"), + }; + self.check_operands_2(ty, Type::I32)?; + self.func_state.change_frame_with_type(2, Type::I32)?; + } + Operator::TableSize { table } => { + self.check_reference_types_enabled()?; + if resources.table_at(table).is_none() { + return Err("table index out of bounds"); + } + self.func_state.change_frame_with_type(0, Type::I32)?; + } + Operator::TableFill { table } => { + self.check_bulk_memory_enabled()?; + let ty = match resources.table_at(table) { + Some(ty) => ty.element_type().to_parser_type(), + None => return Err("table index out of bounds"), + }; + self.check_operands_3(Type::I32, ty, Type::I32)?; + self.func_state.change_frame(3)?; + } + } + Ok(FunctionEnd::No) + } + + pub(crate) fn process_end_function(&self) -> OperatorValidatorResult<()> { + if !self.func_state.end_function { + return Err("expected end of function"); + } + Ok(()) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/parser.rs b/third_party/rust/wasmparser-0.48.2/src/parser.rs new file mode 100644 index 0000000000..9906c6244c --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/parser.rs @@ -0,0 +1,1185 @@ +/* Copyright 2017 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// See https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md + +use std::boxed::Box; +use std::vec::Vec; + +use crate::limits::{ + MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_STRING_SIZE, MAX_WASM_TABLE_ENTRIES, +}; + +use crate::primitives::{ + BinaryReaderError, CustomSectionKind, ExternalKind, FuncType, GlobalType, + ImportSectionEntryType, LinkingType, MemoryType, Naming, Operator, RelocType, Result, + SectionCode, TableType, Type, +}; + +use crate::readers::{ + CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, + ElementKind, ElementSectionReader, Export, ExportSectionReader, FunctionBody, + FunctionSectionReader, Global, GlobalSectionReader, Import, ImportSectionReader, + LinkingSectionReader, MemorySectionReader, ModuleReader, Name, NameSectionReader, NamingReader, + OperatorsReader, Reloc, RelocSectionReader, Section, SectionReader, TableSectionReader, + TypeSectionReader, +}; + +use crate::binary_reader::{BinaryReader, Range}; + +const MAX_DATA_CHUNK_SIZE: usize = MAX_WASM_STRING_SIZE; + +#[derive(Debug)] +pub struct LocalName<'a> { + pub index: u32, + pub locals: Box<[Naming<'a>]>, +} + +#[derive(Debug)] +pub enum NameEntry<'a> { + Module(&'a str), + Function(Box<[Naming<'a>]>), + Local(Box<[LocalName<'a>]>), +} + +#[derive(Debug)] +pub struct RelocEntry { + pub ty: RelocType, + pub offset: u32, + pub index: u32, + pub addend: Option<u32>, +} + +enum InitExpressionContinuationSection { + Global, + Element, + Data, +} + +#[derive(Debug)] +pub enum ParserState<'a> { + Error(BinaryReaderError), + Initial, + BeginWasm { + version: u32, + }, + EndWasm, + BeginSection { + code: SectionCode<'a>, + range: Range, + }, + EndSection, + SkippingSection, + ReadingCustomSection(CustomSectionKind), + ReadingSectionRawData, + SectionRawData(&'a [u8]), + + TypeSectionEntry(FuncType), + ImportSectionEntry { + module: &'a str, + field: &'a str, + ty: ImportSectionEntryType, + }, + FunctionSectionEntry(u32), + TableSectionEntry(TableType), + MemorySectionEntry(MemoryType), + ExportSectionEntry { + field: &'a str, + kind: ExternalKind, + index: u32, + }, + NameSectionEntry(NameEntry<'a>), + StartSectionEntry(u32), + DataCountSectionEntry(u32), + + BeginInitExpressionBody, + InitExpressionOperator(Operator<'a>), + EndInitExpressionBody, + + BeginFunctionBody { + range: Range, + }, + FunctionBodyLocals { + locals: Box<[(u32, Type)]>, + }, + CodeOperator(Operator<'a>), + EndFunctionBody, + SkippingFunctionBody, + + BeginElementSectionEntry { + /// `None` means this is a passive or defined entry + table: ElemSectionEntryTable, + ty: Type, + }, + ElementSectionEntryBody(Box<[ElementItem]>), + EndElementSectionEntry, + + BeginPassiveDataSectionEntry, + BeginActiveDataSectionEntry(u32), + EndDataSectionEntry, + BeginDataSectionEntryBody(u32), + DataSectionEntryBodyChunk(&'a [u8]), + EndDataSectionEntryBody, + + BeginGlobalSectionEntry(GlobalType), + EndGlobalSectionEntry, + + RelocSectionHeader(SectionCode<'a>), + RelocSectionEntry(RelocEntry), + LinkingSectionEntry(LinkingType), + + SourceMappingURL(&'a str), +} + +#[derive(Debug, Copy, Clone)] +pub enum ElemSectionEntryTable { + Passive, + Declared, + Active(u32), +} + +#[derive(Debug, Copy, Clone)] +pub enum ParserInput { + Default, + SkipSection, + SkipFunctionBody, + ReadCustomSection, + ReadSectionRawData, +} + +pub trait WasmDecoder<'a> { + fn read(&mut self) -> &ParserState<'a>; + fn push_input(&mut self, input: ParserInput); + fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a>; + fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> + where + 'a: 'b; + fn last_state(&self) -> &ParserState<'a>; +} + +enum ParserSectionReader<'a> { + None, + CodeSectionReader(CodeSectionReader<'a>), + DataSectionReader(DataSectionReader<'a>), + ElementSectionReader(ElementSectionReader<'a>), + ExportSectionReader(ExportSectionReader<'a>), + FunctionSectionReader(FunctionSectionReader<'a>), + GlobalSectionReader(GlobalSectionReader<'a>), + ImportSectionReader(ImportSectionReader<'a>), + MemorySectionReader(MemorySectionReader<'a>), + TableSectionReader(TableSectionReader<'a>), + TypeSectionReader(TypeSectionReader<'a>), + NameSectionReader(NameSectionReader<'a>), + LinkingSectionReader(LinkingSectionReader<'a>), + RelocSectionReader(RelocSectionReader<'a>), +} + +macro_rules! section_reader { + ($self:ident, $ty_and_name:ident) => { + if let ParserSectionReader::$ty_and_name(ref mut reader) = $self.section_reader { + reader + } else { + panic!("expected {} reader", stringify!($ty_and_name)); + } + }; +} + +macro_rules! start_section_reader { + ($self:ident, $ty_and_name:ident, $factory:ident) => {{ + let reader = $self + .current_section + .as_ref() + .expect("section") + .$factory()?; + $self.section_entries_left = reader.get_count(); + $self.section_reader = ParserSectionReader::$ty_and_name(reader); + }}; +} + +/// The `Parser` type. A simple event-driven parser of WebAssembly binary +/// format. The `read(&mut self)` is used to iterate through WebAssembly records. +pub struct Parser<'a> { + data: &'a [u8], + state: ParserState<'a>, + module_reader: Option<ModuleReader<'a>>, + current_section: Option<Section<'a>>, + section_reader: ParserSectionReader<'a>, + element_items: Option<ElementItems<'a>>, + current_function_body: Option<FunctionBody<'a>>, + init_expr_continuation: Option<InitExpressionContinuationSection>, + current_data_segment: Option<&'a [u8]>, + binary_reader: Option<BinaryReader<'a>>, + operators_reader: Option<OperatorsReader<'a>>, + section_entries_left: u32, +} + +impl<'a> Parser<'a> { + /// Constructs `Parser` type. + /// + /// # Examples + /// ``` + /// let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// let mut parser = wasmparser::Parser::new(data); + /// ``` + pub fn new(data: &[u8]) -> Parser { + Parser { + data, + state: ParserState::Initial, + module_reader: None, + current_section: None, + section_reader: ParserSectionReader::None, + element_items: None, + current_function_body: None, + init_expr_continuation: None, + current_data_segment: None, + binary_reader: None, + operators_reader: None, + section_entries_left: 0, + } + } + + pub fn eof(&self) -> bool { + match self.state { + ParserState::EndWasm => true, + ParserState::BeginWasm { .. } | ParserState::EndSection => { + self.module_reader.as_ref().expect("module reader").eof() + } + _ => false, // in-process of reading + } + } + + pub fn current_position(&self) -> usize { + if let ParserState::Initial = self.state { + return 0; + } + if self.binary_reader.is_some() { + return self + .binary_reader + .as_ref() + .expect("binary reader") + .original_position(); + } + if self.operators_reader.is_some() { + return self + .operators_reader + .as_ref() + .expect("operators reader") + .original_position(); + } + match self.section_reader { + ParserSectionReader::CodeSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::DataSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::ElementSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::ExportSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::FunctionSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::GlobalSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::ImportSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::MemorySectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::TableSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::TypeSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::NameSectionReader(ref reader) => { + return reader.original_position() + } + ParserSectionReader::LinkingSectionReader(ref reader) => { + return reader.original_position(); + } + ParserSectionReader::RelocSectionReader(ref reader) => { + return reader.original_position(); + } + _ => (), + }; + // TODO might not cover all cases + self.module_reader + .as_ref() + .expect("module reader") + .current_position() + } + + fn read_module(&mut self) -> Result<()> { + let module_reader = ModuleReader::new(self.data)?; + let version = module_reader.get_version(); + self.module_reader = Some(module_reader); + self.state = ParserState::BeginWasm { version }; + Ok(()) + } + + fn read_section_header(&mut self) -> Result<()> { + let section = self.module_reader.as_mut().expect("module reader").read()?; + let code = section.code; + let range = section.range(); + self.current_section = Some(section); + self.state = ParserState::BeginSection { code, range }; + Ok(()) + } + + fn read_type_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let type_entry = section_reader!(self, TypeSectionReader).read()?; + self.state = ParserState::TypeSectionEntry(type_entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_import_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Import { module, field, ty } = section_reader!(self, ImportSectionReader).read()?; + self.state = ParserState::ImportSectionEntry { module, field, ty }; + self.section_entries_left -= 1; + Ok(()) + } + + fn read_function_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let func_type = section_reader!(self, FunctionSectionReader).read()?; + self.state = ParserState::FunctionSectionEntry(func_type); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_memory_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let memory_type = section_reader!(self, MemorySectionReader).read()?; + self.state = ParserState::MemorySectionEntry(memory_type); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_global_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Global { ty, init_expr } = section_reader!(self, GlobalSectionReader).read()?; + self.state = ParserState::BeginGlobalSectionEntry(ty); + self.operators_reader = Some(init_expr.get_operators_reader()); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_init_expression_body(&mut self, cont: InitExpressionContinuationSection) { + self.state = ParserState::BeginInitExpressionBody; + self.init_expr_continuation = Some(cont); + } + + fn read_init_expression_operator(&mut self) -> Result<()> { + let op = self + .operators_reader + .as_mut() + .expect("operator reader") + .read()?; + if let Operator::End = op { + self.operators_reader = None; + self.state = ParserState::EndInitExpressionBody; + return Ok(()); + } + self.state = ParserState::InitExpressionOperator(op); + Ok(()) + } + + fn read_export_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Export { field, kind, index } = section_reader!(self, ExportSectionReader).read()?; + self.state = ParserState::ExportSectionEntry { field, kind, index }; + self.section_entries_left -= 1; + Ok(()) + } + + fn read_element_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Element { kind, items, ty } = section_reader!(self, ElementSectionReader).read()?; + let table = match kind { + ElementKind::Passive => ElemSectionEntryTable::Passive, + ElementKind::Declared => ElemSectionEntryTable::Declared, + ElementKind::Active { + table_index, + init_expr, + } => { + self.operators_reader = Some(init_expr.get_operators_reader()); + ElemSectionEntryTable::Active(table_index) + } + }; + self.state = ParserState::BeginElementSectionEntry { table, ty }; + self.element_items = Some(items); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_element_entry_body(&mut self) -> Result<()> { + let mut reader = self + .element_items + .take() + .expect("element items") + .get_items_reader()?; + let num_elements = reader.get_count() as usize; + if num_elements > MAX_WASM_TABLE_ENTRIES { + return Err(BinaryReaderError { + message: "num_elements is out of bounds", + offset: 0, // reader.position - 1, // TODO offset + }); + } + let mut elements = Vec::with_capacity(num_elements); + for _ in 0..num_elements { + elements.push(reader.read()?); + } + self.state = ParserState::ElementSectionEntryBody(elements.into_boxed_slice()); + Ok(()) + } + + fn read_function_body(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + self.current_function_body = None; + return self.check_section_end(); + } + let function_body = section_reader!(self, CodeSectionReader).read()?; + let range = function_body.range(); + self.state = ParserState::BeginFunctionBody { range }; + self.current_function_body = Some(function_body); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_function_body_locals(&mut self) -> Result<()> { + let function_body = self.current_function_body.as_mut().expect("function body"); + let mut reader = function_body.get_locals_reader()?; + let local_count = reader.get_count() as usize; + if local_count > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "local_count is out of bounds", + offset: reader.original_position() - 1, + }); + } + let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count); + let mut locals_total: usize = 0; + for _ in 0..local_count { + let (count, ty) = reader.read()?; + locals_total = + locals_total + .checked_add(count as usize) + .ok_or_else(|| BinaryReaderError { + message: "locals_total is out of bounds", + offset: reader.original_position() - 1, + })?; + if locals_total > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals_total is out of bounds", + offset: reader.original_position() - 1, + }); + } + locals.push((count, ty)); + } + self.operators_reader = Some(function_body.get_operators_reader()?); + self.state = ParserState::FunctionBodyLocals { + locals: locals.into_boxed_slice(), + }; + Ok(()) + } + + fn read_code_operator(&mut self) -> Result<()> { + if self + .operators_reader + .as_ref() + .expect("operator reader") + .eof() + { + if let ParserState::CodeOperator(Operator::End) = self.state { + self.state = ParserState::EndFunctionBody; + self.operators_reader = None; + self.current_function_body = None; + return Ok(()); + } + let reader = self.operators_reader.as_ref().expect("operator reader"); + return Err(BinaryReaderError { + message: "Expected end of function marker", + offset: reader.original_position(), + }); + } + let reader = self.operators_reader.as_mut().expect("operator reader"); + let op = reader.read()?; + self.state = ParserState::CodeOperator(op); + Ok(()) + } + + fn read_table_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let table_entry = section_reader!(self, TableSectionReader).read()?; + self.state = ParserState::TableSectionEntry(table_entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_data_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Data { kind, data } = section_reader!(self, DataSectionReader).read()?; + match kind { + DataKind::Passive => { + self.state = ParserState::BeginPassiveDataSectionEntry; + } + DataKind::Active { + memory_index, + init_expr, + } => { + self.state = ParserState::BeginActiveDataSectionEntry(memory_index); + self.operators_reader = Some(init_expr.get_operators_reader()); + } + } + self.current_data_segment = Some(data); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_data_entry_body(&mut self) -> Result<()> { + let size = self.current_data_segment.expect("data entry").len(); + self.state = ParserState::BeginDataSectionEntryBody(size as u32); + Ok(()) + } + + fn read_naming<'b>( + mut naming_reader: NamingReader<'a>, + limit: usize, + ) -> Result<Box<[Naming<'b>]>> + where + 'a: 'b, + { + let count = naming_reader.get_count() as usize; + if count > limit { + return Err(BinaryReaderError { + message: "name map size is out of bound", + offset: naming_reader.original_position() - 1, + }); + } + let mut result = Vec::with_capacity(count); + for _ in 0..count { + result.push(naming_reader.read()?); + } + Ok(result.into_boxed_slice()) + } + + fn read_name_entry(&mut self) -> Result<()> { + if section_reader!(self, NameSectionReader).eof() { + return self.position_to_section_end(); + } + let entry = match section_reader!(self, NameSectionReader).read()? { + Name::Module(name) => NameEntry::Module(name.get_name()?), + Name::Function(func) => { + NameEntry::Function(Self::read_naming(func.get_map()?, MAX_WASM_FUNCTIONS)?) + } + Name::Local(locals) => { + let mut reader = locals.get_function_local_reader()?; + let funcs_len = reader.get_count() as usize; + if funcs_len > MAX_WASM_FUNCTIONS { + return Err(BinaryReaderError { + message: "function count is out of bounds", + offset: reader.original_position() - 1, + }); + } + let mut funcs: Vec<LocalName<'a>> = Vec::with_capacity(funcs_len); + for _ in 0..funcs_len { + let func = reader.read()?; + funcs.push(LocalName { + index: func.func_index, + locals: Self::read_naming(func.get_map()?, MAX_WASM_FUNCTION_LOCALS)?, + }); + } + NameEntry::Local(funcs.into_boxed_slice()) + } + }; + self.state = ParserState::NameSectionEntry(entry); + Ok(()) + } + + fn read_source_mapping(&mut self) -> Result<()> { + let url = self + .current_section + .as_ref() + .expect("section") + .get_sourcemappingurl_section_content()?; + self.state = ParserState::SourceMappingURL(url); + Ok(()) + } + + // See https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md + fn read_reloc_header(&mut self) -> Result<()> { + let section_code = section_reader!(self, RelocSectionReader).get_section_code(); + self.state = ParserState::RelocSectionHeader(section_code); + Ok(()) + } + + fn read_reloc_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let Reloc { + ty, + offset, + index, + addend, + } = section_reader!(self, RelocSectionReader).read()?; + self.state = ParserState::RelocSectionEntry(RelocEntry { + ty, + offset, + index, + addend, + }); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_linking_entry(&mut self) -> Result<()> { + if self.section_entries_left == 0 { + return self.check_section_end(); + } + let entry = section_reader!(self, LinkingSectionReader).read()?; + self.state = ParserState::LinkingSectionEntry(entry); + self.section_entries_left -= 1; + Ok(()) + } + + fn read_section_body(&mut self) -> Result<()> { + match self.state { + ParserState::BeginSection { + code: SectionCode::Type, + .. + } => { + start_section_reader!(self, TypeSectionReader, get_type_section_reader); + self.read_type_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Import, + .. + } => { + start_section_reader!(self, ImportSectionReader, get_import_section_reader); + self.read_import_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Function, + .. + } => { + start_section_reader!(self, FunctionSectionReader, get_function_section_reader); + self.read_function_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Memory, + .. + } => { + start_section_reader!(self, MemorySectionReader, get_memory_section_reader); + self.read_memory_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Global, + .. + } => { + start_section_reader!(self, GlobalSectionReader, get_global_section_reader); + self.read_global_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Export, + .. + } => { + start_section_reader!(self, ExportSectionReader, get_export_section_reader); + self.read_export_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Element, + .. + } => { + start_section_reader!(self, ElementSectionReader, get_element_section_reader); + self.read_element_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Code, + .. + } => { + start_section_reader!(self, CodeSectionReader, get_code_section_reader); + self.read_function_body()?; + } + ParserState::BeginSection { + code: SectionCode::Table, + .. + } => { + start_section_reader!(self, TableSectionReader, get_table_section_reader); + self.read_table_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Data, + .. + } => { + start_section_reader!(self, DataSectionReader, get_data_section_reader); + self.read_data_entry()?; + } + ParserState::BeginSection { + code: SectionCode::Start, + .. + } => { + let func_index = self + .current_section + .as_ref() + .expect("section") + .get_start_section_content()?; + self.state = ParserState::StartSectionEntry(func_index); + } + ParserState::BeginSection { + code: SectionCode::DataCount, + .. + } => { + let func_index = self + .current_section + .as_ref() + .expect("section") + .get_data_count_section_content()?; + self.state = ParserState::DataCountSectionEntry(func_index); + } + ParserState::BeginSection { + code: SectionCode::Custom { .. }, + .. + } => { + self.create_custom_section_binary_reader(); + self.read_section_body_bytes()?; + } + _ => unreachable!(), + } + Ok(()) + } + + fn create_custom_section_binary_reader(&mut self) { + let reader = self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(); + self.binary_reader = Some(reader); + } + + fn read_custom_section_body(&mut self) -> Result<()> { + match self.state { + ParserState::ReadingCustomSection(CustomSectionKind::Name) => { + let reader = self + .current_section + .as_ref() + .expect("section") + .get_name_section_reader()?; + self.section_reader = ParserSectionReader::NameSectionReader(reader); + self.read_name_entry()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::SourceMappingURL) => { + self.read_source_mapping()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Reloc) => { + start_section_reader!(self, RelocSectionReader, get_reloc_section_reader); + self.read_reloc_header()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Linking) => { + start_section_reader!(self, LinkingSectionReader, get_linking_section_reader); + self.read_linking_entry()?; + } + ParserState::ReadingCustomSection(CustomSectionKind::Producers) + | ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => { + self.create_custom_section_binary_reader(); + self.read_section_body_bytes()?; + } + _ => unreachable!(), + } + Ok(()) + } + + fn position_to_section_end(&mut self) -> Result<()> { + self.current_section = None; + self.binary_reader = None; + self.state = ParserState::EndSection; + Ok(()) + } + + fn check_section_end(&mut self) -> Result<()> { + match self.section_reader { + ParserSectionReader::CodeSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::DataSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ElementSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ExportSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::FunctionSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::GlobalSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::ImportSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::MemorySectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::TableSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::TypeSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::LinkingSectionReader(ref reader) => reader.ensure_end()?, + ParserSectionReader::RelocSectionReader(ref reader) => reader.ensure_end()?, + _ => unreachable!(), + } + self.position_to_section_end() + } + + fn read_section_body_bytes(&mut self) -> Result<()> { + if self.binary_reader.as_ref().expect("binary reader").eof() { + self.state = ParserState::EndSection; + self.binary_reader = None; + return Ok(()); + } + let binary_reader = self.binary_reader.as_mut().expect("binary reader"); + let to_read = if binary_reader.buffer.len() - binary_reader.position < MAX_DATA_CHUNK_SIZE { + binary_reader.buffer.len() - binary_reader.position + } else { + MAX_DATA_CHUNK_SIZE + }; + let bytes = binary_reader.read_bytes(to_read)?; + self.state = ParserState::SectionRawData(bytes); + Ok(()) + } + + fn read_data_chunk(&mut self) -> Result<()> { + let data = self.current_data_segment.expect("data"); + if data.is_empty() { + self.state = ParserState::EndDataSectionEntryBody; + self.current_data_segment = None; + return Ok(()); + } + let to_read = if data.len() > MAX_DATA_CHUNK_SIZE { + MAX_DATA_CHUNK_SIZE + } else { + data.len() + }; + let (head, tail) = data.split_at(to_read); + self.current_data_segment = Some(tail); + self.state = ParserState::DataSectionEntryBodyChunk(head); + Ok(()) + } + + fn read_next_section(&mut self) -> Result<()> { + if self.module_reader.as_ref().expect("module_reader").eof() { + self.current_section = None; + self.state = ParserState::EndWasm; + } else { + self.read_section_header()?; + } + Ok(()) + } + + fn read_wrapped(&mut self) -> Result<()> { + match self.state { + ParserState::EndWasm => panic!("Parser in end state"), + ParserState::Error(_) => panic!("Parser in error state"), + ParserState::Initial => self.read_module()?, + ParserState::BeginWasm { .. } | ParserState::EndSection => self.read_next_section()?, + ParserState::BeginSection { .. } => self.read_section_body()?, + ParserState::SkippingSection => { + self.position_to_section_end()?; + self.read_next_section()?; + } + ParserState::TypeSectionEntry(_) => self.read_type_entry()?, + ParserState::ImportSectionEntry { .. } => self.read_import_entry()?, + ParserState::FunctionSectionEntry(_) => self.read_function_entry()?, + ParserState::MemorySectionEntry(_) => self.read_memory_entry()?, + ParserState::TableSectionEntry(_) => self.read_table_entry()?, + ParserState::ExportSectionEntry { .. } => self.read_export_entry()?, + ParserState::BeginGlobalSectionEntry(_) => { + self.read_init_expression_body(InitExpressionContinuationSection::Global) + } + ParserState::EndGlobalSectionEntry => self.read_global_entry()?, + ParserState::BeginElementSectionEntry { + table: ElemSectionEntryTable::Active(_), + .. + } => self.read_init_expression_body(InitExpressionContinuationSection::Element), + ParserState::BeginElementSectionEntry { .. } => self.read_element_entry_body()?, + ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => { + self.read_init_expression_operator()? + } + ParserState::BeginPassiveDataSectionEntry => self.read_data_entry_body()?, + ParserState::BeginActiveDataSectionEntry(_) => { + self.read_init_expression_body(InitExpressionContinuationSection::Data) + } + ParserState::EndInitExpressionBody => { + match self.init_expr_continuation { + Some(InitExpressionContinuationSection::Global) => { + self.state = ParserState::EndGlobalSectionEntry + } + Some(InitExpressionContinuationSection::Element) => { + self.read_element_entry_body()? + } + Some(InitExpressionContinuationSection::Data) => self.read_data_entry_body()?, + None => unreachable!(), + } + self.init_expr_continuation = None; + } + ParserState::BeginFunctionBody { .. } => self.read_function_body_locals()?, + ParserState::FunctionBodyLocals { .. } | ParserState::CodeOperator(_) => { + self.read_code_operator()? + } + ParserState::EndFunctionBody => self.read_function_body()?, + ParserState::SkippingFunctionBody => { + self.current_function_body = None; + self.read_function_body()?; + } + ParserState::EndDataSectionEntry => self.read_data_entry()?, + ParserState::BeginDataSectionEntryBody(_) + | ParserState::DataSectionEntryBodyChunk(_) => self.read_data_chunk()?, + ParserState::EndDataSectionEntryBody => { + self.state = ParserState::EndDataSectionEntry; + } + ParserState::ElementSectionEntryBody(_) => { + self.state = ParserState::EndElementSectionEntry; + } + ParserState::EndElementSectionEntry => self.read_element_entry()?, + ParserState::StartSectionEntry(_) => self.position_to_section_end()?, + ParserState::DataCountSectionEntry(_) => self.position_to_section_end()?, + ParserState::NameSectionEntry(_) => self.read_name_entry()?, + ParserState::SourceMappingURL(_) => self.position_to_section_end()?, + ParserState::RelocSectionHeader(_) => { + let mut reader = self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(); + self.section_entries_left = reader.read_var_u32()?; + self.binary_reader = Some(reader); + self.read_reloc_entry()?; + } + ParserState::RelocSectionEntry(_) => self.read_reloc_entry()?, + ParserState::LinkingSectionEntry(_) => self.read_linking_entry()?, + ParserState::ReadingCustomSection(_) => self.read_custom_section_body()?, + ParserState::ReadingSectionRawData | ParserState::SectionRawData(_) => { + self.read_section_body_bytes()? + } + } + Ok(()) + } + + fn skip_section(&mut self) { + match self.state { + ParserState::Initial + | ParserState::EndWasm + | ParserState::Error(_) + | ParserState::BeginWasm { .. } + | ParserState::EndSection => panic!("Invalid reader state during skip section"), + _ => self.state = ParserState::SkippingSection, + } + } + + fn skip_function_body(&mut self) { + match self.state { + ParserState::BeginFunctionBody { .. } + | ParserState::FunctionBodyLocals { .. } + | ParserState::CodeOperator(_) => self.state = ParserState::SkippingFunctionBody, + _ => panic!("Invalid reader state during skip function body"), + } + } + + fn read_custom_section(&mut self) { + match self.state { + ParserState::BeginSection { + code: SectionCode::Custom { kind, .. }, + .. + } => { + self.state = ParserState::ReadingCustomSection(kind); + } + _ => panic!("Invalid reader state during reading custom section"), + } + } + + fn read_raw_section_data(&mut self) { + match self.state { + ParserState::BeginSection { .. } => { + self.binary_reader = Some( + self.current_section + .as_ref() + .expect("section") + .get_binary_reader(), + ); + self.state = ParserState::ReadingSectionRawData; + } + _ => panic!("Invalid reader state during reading raw section data"), + } + } +} + +impl<'a> WasmDecoder<'a> for Parser<'a> { + /// Reads next record from the WebAssembly binary data. The methods returns + /// reference to current state of the parser. See `ParserState` num. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::WasmDecoder; + /// let mut parser = wasmparser::Parser::new(data); + /// { + /// let state = parser.read(); + /// println!("First state {:?}", state); + /// } + /// { + /// let state = parser.read(); + /// println!("Second state {:?}", state); + /// } + /// ``` + fn read(&mut self) -> &ParserState<'a> { + let result = self.read_wrapped(); + if result.is_err() { + self.state = ParserState::Error(result.err().unwrap()); + } + &self.state + } + + fn push_input(&mut self, input: ParserInput) { + match input { + ParserInput::Default => (), + ParserInput::SkipSection => self.skip_section(), + ParserInput::SkipFunctionBody => self.skip_function_body(), + ParserInput::ReadCustomSection => self.read_custom_section(), + ParserInput::ReadSectionRawData => self.read_raw_section_data(), + } + } + + /// Creates a BinaryReader when current state is ParserState::BeginSection + /// or ParserState::BeginFunctionBody. + /// + /// # Examples + /// ``` + /// # let data = &[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x84, + /// # 0x80, 0x80, 0x80, 0x0, 0x1, 0x60, 0x0, 0x0, 0x3, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x2, 0x0, 0x0, 0x6, 0x81, 0x80, + /// # 0x80, 0x80, 0x0, 0x0, 0xa, 0x91, 0x80, 0x80, 0x80, 0x0, + /// # 0x2, 0x83, 0x80, 0x80, 0x80, 0x0, 0x0, 0x1, 0xb, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb]; + /// use wasmparser::{WasmDecoder, Parser, ParserState}; + /// let mut parser = Parser::new(data); + /// let mut types = Vec::new(); + /// let mut function_types = Vec::new(); + /// let mut function_readers = Vec::new(); + /// loop { + /// match parser.read() { + /// ParserState::Error(_) | + /// ParserState::EndWasm => break, + /// ParserState::TypeSectionEntry(ty) => { + /// types.push(ty.clone()); + /// } + /// ParserState::FunctionSectionEntry(id) => { + /// function_types.push(id.clone()); + /// } + /// ParserState::BeginFunctionBody {..} => { + /// let reader = parser.create_binary_reader(); + /// function_readers.push(reader); + /// } + /// _ => continue + /// } + /// } + /// for (i, reader) in function_readers.iter_mut().enumerate() { + /// // Access the function type through the types table. + /// let ty = &types[function_types[i] as usize]; + /// println!("\nFunction {} of type {:?}", i, ty); + /// // Read the local declarations required by the function body. + /// let local_decls_len = reader.read_local_count().unwrap(); + /// let mut local_decls = Vec::with_capacity(local_decls_len); + /// let mut local_count = ty.params.len(); + /// for _ in 0..local_decls_len { + /// let local_decl = reader.read_local_decl(&mut local_count).unwrap(); + /// local_decls.push(local_decl); + /// } + /// println!("Function locals: vars {:?}; total {} ", local_decls, local_count); + /// // Read the operations of the function body. + /// while let Ok(ref op) = reader.read_operator() { + /// println!(" {:?}", op); + /// } + /// } + /// ``` + fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> + where + 'a: 'b, + { + match self.state { + ParserState::BeginSection { .. } => self + .current_section + .as_ref() + .expect("section") + .get_binary_reader(), + ParserState::BeginFunctionBody { .. } | ParserState::FunctionBodyLocals { .. } => self + .current_function_body + .as_ref() + .expect("function body") + .get_binary_reader(), + _ => panic!("Invalid reader state during get binary reader operation"), + } + } + + /// Reads next record from the WebAssembly binary data. It also allows to + /// control how parser will treat the next record(s). The method accepts the + /// `ParserInput` parameter that allows e.g. to skip section or function + /// operators. The methods returns reference to current state of the parser. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::WasmDecoder; + /// let mut parser = wasmparser::Parser::new(data); + /// let mut next_input = wasmparser::ParserInput::Default; + /// loop { + /// let state = parser.read_with_input(next_input); + /// match *state { + /// wasmparser::ParserState::EndWasm => break, + /// wasmparser::ParserState::BeginWasm { .. } | + /// wasmparser::ParserState::EndSection => + /// next_input = wasmparser::ParserInput::Default, + /// wasmparser::ParserState::BeginSection { ref code, .. } => { + /// println!("Found section: {:?}", code); + /// next_input = wasmparser::ParserInput::SkipSection; + /// }, + /// _ => unreachable!() + /// } + /// } + /// ``` + fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> { + self.push_input(input); + self.read() + } + + fn last_state(&self) -> &ParserState<'a> { + &self.state + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/primitives.rs b/third_party/rust/wasmparser-0.48.2/src/primitives.rs new file mode 100644 index 0000000000..d7d2218aa4 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/primitives.rs @@ -0,0 +1,690 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::error::Error; +use std::fmt; +use std::result; + +#[derive(Debug, Copy, Clone)] +pub struct BinaryReaderError { + pub message: &'static str, + pub offset: usize, +} + +pub type Result<T> = result::Result<T, BinaryReaderError>; + +impl Error for BinaryReaderError {} + +impl fmt::Display for BinaryReaderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} (at offset {})", self.message, self.offset) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum CustomSectionKind { + Unknown, + Name, + Producers, + SourceMappingURL, + Reloc, + Linking, +} + +/// Section code as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/binary/modules.html#sections +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum SectionCode<'a> { + Custom { + name: &'a str, + kind: CustomSectionKind, + }, + Type, // Function signature declarations + Import, // Import declarations + Function, // Function declarations + Table, // Indirect function table and other tables + Memory, // Memory attributes + Global, // Global declarations + Export, // Exports + Start, // Start function declaration + Element, // Elements section + Code, // Function bodies (code) + Data, // Data segments + DataCount, // Count of passive data segments +} + +/// Types as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#types +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Type { + I32, + I64, + F32, + F64, + V128, + AnyFunc, + AnyRef, + NullRef, + Func, + EmptyBlockType, +} + +impl Type { + pub(crate) fn is_valid_for_old_select(self) -> bool { + match self { + Type::I32 | Type::I64 | Type::F32 | Type::F64 => true, + _ => false, + } + } +} + +/// Either a value type or a function type. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum TypeOrFuncType { + /// A value type. + /// + /// When used as the type for a block, this type is the optional result + /// type: `[] -> [t?]`. + Type(Type), + + /// A function type (referenced as an index into the types section). + FuncType(u32), +} + +/// External types as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/syntax/types.html#external-types +#[derive(Debug, Copy, Clone)] +pub enum ExternalKind { + Function, + Table, + Memory, + Global, +} + +#[derive(Debug, Clone)] +pub struct FuncType { + pub form: Type, + pub params: Box<[Type]>, + pub returns: Box<[Type]>, +} + +#[derive(Debug, Copy, Clone)] +pub struct ResizableLimits { + pub initial: u32, + pub maximum: Option<u32>, +} + +#[derive(Debug, Copy, Clone)] +pub struct TableType { + pub element_type: Type, + pub limits: ResizableLimits, +} + +#[derive(Debug, Copy, Clone)] +pub struct MemoryType { + pub limits: ResizableLimits, + pub shared: bool, +} + +#[derive(Debug, Copy, Clone)] +pub struct GlobalType { + pub content_type: Type, + pub mutable: bool, +} + +#[derive(Debug, Copy, Clone)] +pub enum ImportSectionEntryType { + Function(u32), + Table(TableType), + Memory(MemoryType), + Global(GlobalType), +} + +#[derive(Debug, Copy, Clone)] +pub struct MemoryImmediate { + pub flags: u32, + pub offset: u32, +} + +#[derive(Debug, Copy, Clone)] +pub struct Naming<'a> { + pub index: u32, + pub name: &'a str, +} + +#[derive(Debug, Copy, Clone)] +pub enum NameType { + Module, + Function, + Local, +} + +#[derive(Debug, Copy, Clone)] +pub enum LinkingType { + StackPointer(u32), +} + +#[derive(Debug, Copy, Clone)] +pub enum RelocType { + FunctionIndexLEB, + TableIndexSLEB, + TableIndexI32, + GlobalAddrLEB, + GlobalAddrSLEB, + GlobalAddrI32, + TypeIndexLEB, + GlobalIndexLEB, +} + +/// A br_table entries representation. +#[derive(Debug, Clone)] +pub struct BrTable<'a> { + pub(crate) buffer: &'a [u8], + pub(crate) cnt: usize, +} + +/// An IEEE binary32 immediate floating point value, represented as a u32 +/// containing the bitpattern. +/// +/// All bit patterns are allowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Ieee32(pub(crate) u32); + +impl Ieee32 { + pub fn bits(self) -> u32 { + self.0 + } +} + +/// An IEEE binary64 immediate floating point value, represented as a u64 +/// containing the bitpattern. +/// +/// All bit patterns are allowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Ieee64(pub(crate) u64); + +impl Ieee64 { + pub fn bits(self) -> u64 { + self.0 + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct V128(pub(crate) [u8; 16]); + +impl V128 { + pub fn bytes(&self) -> &[u8; 16] { + &self.0 + } +} + +pub type SIMDLaneIndex = u8; + +/// Instructions as defined [here]. +/// +/// [here]: https://webassembly.github.io/spec/core/binary/instructions.html +#[derive(Debug, Clone)] +pub enum Operator<'a> { + Unreachable, + Nop, + Block { ty: TypeOrFuncType }, + Loop { ty: TypeOrFuncType }, + If { ty: TypeOrFuncType }, + Else, + End, + Br { relative_depth: u32 }, + BrIf { relative_depth: u32 }, + BrTable { table: BrTable<'a> }, + Return, + Call { function_index: u32 }, + CallIndirect { index: u32, table_index: u32 }, + Drop, + Select, + TypedSelect { ty: Type }, + LocalGet { local_index: u32 }, + LocalSet { local_index: u32 }, + LocalTee { local_index: u32 }, + GlobalGet { global_index: u32 }, + GlobalSet { global_index: u32 }, + I32Load { memarg: MemoryImmediate }, + I64Load { memarg: MemoryImmediate }, + F32Load { memarg: MemoryImmediate }, + F64Load { memarg: MemoryImmediate }, + I32Load8S { memarg: MemoryImmediate }, + I32Load8U { memarg: MemoryImmediate }, + I32Load16S { memarg: MemoryImmediate }, + I32Load16U { memarg: MemoryImmediate }, + I64Load8S { memarg: MemoryImmediate }, + I64Load8U { memarg: MemoryImmediate }, + I64Load16S { memarg: MemoryImmediate }, + I64Load16U { memarg: MemoryImmediate }, + I64Load32S { memarg: MemoryImmediate }, + I64Load32U { memarg: MemoryImmediate }, + I32Store { memarg: MemoryImmediate }, + I64Store { memarg: MemoryImmediate }, + F32Store { memarg: MemoryImmediate }, + F64Store { memarg: MemoryImmediate }, + I32Store8 { memarg: MemoryImmediate }, + I32Store16 { memarg: MemoryImmediate }, + I64Store8 { memarg: MemoryImmediate }, + I64Store16 { memarg: MemoryImmediate }, + I64Store32 { memarg: MemoryImmediate }, + MemorySize { reserved: u32 }, + MemoryGrow { reserved: u32 }, + I32Const { value: i32 }, + I64Const { value: i64 }, + F32Const { value: Ieee32 }, + F64Const { value: Ieee64 }, + RefNull, + RefIsNull, + RefFunc { function_index: u32 }, + I32Eqz, + I32Eq, + I32Ne, + I32LtS, + I32LtU, + I32GtS, + I32GtU, + I32LeS, + I32LeU, + I32GeS, + I32GeU, + I64Eqz, + I64Eq, + I64Ne, + I64LtS, + I64LtU, + I64GtS, + I64GtU, + I64LeS, + I64LeU, + I64GeS, + I64GeU, + F32Eq, + F32Ne, + F32Lt, + F32Gt, + F32Le, + F32Ge, + F64Eq, + F64Ne, + F64Lt, + F64Gt, + F64Le, + F64Ge, + I32Clz, + I32Ctz, + I32Popcnt, + I32Add, + I32Sub, + I32Mul, + I32DivS, + I32DivU, + I32RemS, + I32RemU, + I32And, + I32Or, + I32Xor, + I32Shl, + I32ShrS, + I32ShrU, + I32Rotl, + I32Rotr, + I64Clz, + I64Ctz, + I64Popcnt, + I64Add, + I64Sub, + I64Mul, + I64DivS, + I64DivU, + I64RemS, + I64RemU, + I64And, + I64Or, + I64Xor, + I64Shl, + I64ShrS, + I64ShrU, + I64Rotl, + I64Rotr, + F32Abs, + F32Neg, + F32Ceil, + F32Floor, + F32Trunc, + F32Nearest, + F32Sqrt, + F32Add, + F32Sub, + F32Mul, + F32Div, + F32Min, + F32Max, + F32Copysign, + F64Abs, + F64Neg, + F64Ceil, + F64Floor, + F64Trunc, + F64Nearest, + F64Sqrt, + F64Add, + F64Sub, + F64Mul, + F64Div, + F64Min, + F64Max, + F64Copysign, + I32WrapI64, + I32TruncF32S, + I32TruncF32U, + I32TruncF64S, + I32TruncF64U, + I64ExtendI32S, + I64ExtendI32U, + I64TruncF32S, + I64TruncF32U, + I64TruncF64S, + I64TruncF64U, + F32ConvertI32S, + F32ConvertI32U, + F32ConvertI64S, + F32ConvertI64U, + F32DemoteF64, + F64ConvertI32S, + F64ConvertI32U, + F64ConvertI64S, + F64ConvertI64U, + F64PromoteF32, + I32ReinterpretF32, + I64ReinterpretF64, + F32ReinterpretI32, + F64ReinterpretI64, + I32Extend8S, + I32Extend16S, + I64Extend8S, + I64Extend16S, + I64Extend32S, + + // 0xFC operators + // Non-trapping Float-to-int Conversions + I32TruncSatF32S, + I32TruncSatF32U, + I32TruncSatF64S, + I32TruncSatF64U, + I64TruncSatF32S, + I64TruncSatF32U, + I64TruncSatF64S, + I64TruncSatF64U, + + // 0xFC operators + // bulk memory https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md + MemoryInit { segment: u32 }, + DataDrop { segment: u32 }, + MemoryCopy, + MemoryFill, + TableInit { segment: u32, table: u32 }, + ElemDrop { segment: u32 }, + TableCopy { dst_table: u32, src_table: u32 }, + TableFill { table: u32 }, + TableGet { table: u32 }, + TableSet { table: u32 }, + TableGrow { table: u32 }, + TableSize { table: u32 }, + + // 0xFE operators + // https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md + AtomicNotify { memarg: MemoryImmediate }, + I32AtomicWait { memarg: MemoryImmediate }, + I64AtomicWait { memarg: MemoryImmediate }, + AtomicFence { flags: u8 }, + I32AtomicLoad { memarg: MemoryImmediate }, + I64AtomicLoad { memarg: MemoryImmediate }, + I32AtomicLoad8U { memarg: MemoryImmediate }, + I32AtomicLoad16U { memarg: MemoryImmediate }, + I64AtomicLoad8U { memarg: MemoryImmediate }, + I64AtomicLoad16U { memarg: MemoryImmediate }, + I64AtomicLoad32U { memarg: MemoryImmediate }, + I32AtomicStore { memarg: MemoryImmediate }, + I64AtomicStore { memarg: MemoryImmediate }, + I32AtomicStore8 { memarg: MemoryImmediate }, + I32AtomicStore16 { memarg: MemoryImmediate }, + I64AtomicStore8 { memarg: MemoryImmediate }, + I64AtomicStore16 { memarg: MemoryImmediate }, + I64AtomicStore32 { memarg: MemoryImmediate }, + I32AtomicRmwAdd { memarg: MemoryImmediate }, + I64AtomicRmwAdd { memarg: MemoryImmediate }, + I32AtomicRmw8AddU { memarg: MemoryImmediate }, + I32AtomicRmw16AddU { memarg: MemoryImmediate }, + I64AtomicRmw8AddU { memarg: MemoryImmediate }, + I64AtomicRmw16AddU { memarg: MemoryImmediate }, + I64AtomicRmw32AddU { memarg: MemoryImmediate }, + I32AtomicRmwSub { memarg: MemoryImmediate }, + I64AtomicRmwSub { memarg: MemoryImmediate }, + I32AtomicRmw8SubU { memarg: MemoryImmediate }, + I32AtomicRmw16SubU { memarg: MemoryImmediate }, + I64AtomicRmw8SubU { memarg: MemoryImmediate }, + I64AtomicRmw16SubU { memarg: MemoryImmediate }, + I64AtomicRmw32SubU { memarg: MemoryImmediate }, + I32AtomicRmwAnd { memarg: MemoryImmediate }, + I64AtomicRmwAnd { memarg: MemoryImmediate }, + I32AtomicRmw8AndU { memarg: MemoryImmediate }, + I32AtomicRmw16AndU { memarg: MemoryImmediate }, + I64AtomicRmw8AndU { memarg: MemoryImmediate }, + I64AtomicRmw16AndU { memarg: MemoryImmediate }, + I64AtomicRmw32AndU { memarg: MemoryImmediate }, + I32AtomicRmwOr { memarg: MemoryImmediate }, + I64AtomicRmwOr { memarg: MemoryImmediate }, + I32AtomicRmw8OrU { memarg: MemoryImmediate }, + I32AtomicRmw16OrU { memarg: MemoryImmediate }, + I64AtomicRmw8OrU { memarg: MemoryImmediate }, + I64AtomicRmw16OrU { memarg: MemoryImmediate }, + I64AtomicRmw32OrU { memarg: MemoryImmediate }, + I32AtomicRmwXor { memarg: MemoryImmediate }, + I64AtomicRmwXor { memarg: MemoryImmediate }, + I32AtomicRmw8XorU { memarg: MemoryImmediate }, + I32AtomicRmw16XorU { memarg: MemoryImmediate }, + I64AtomicRmw8XorU { memarg: MemoryImmediate }, + I64AtomicRmw16XorU { memarg: MemoryImmediate }, + I64AtomicRmw32XorU { memarg: MemoryImmediate }, + I32AtomicRmwXchg { memarg: MemoryImmediate }, + I64AtomicRmwXchg { memarg: MemoryImmediate }, + I32AtomicRmw8XchgU { memarg: MemoryImmediate }, + I32AtomicRmw16XchgU { memarg: MemoryImmediate }, + I64AtomicRmw8XchgU { memarg: MemoryImmediate }, + I64AtomicRmw16XchgU { memarg: MemoryImmediate }, + I64AtomicRmw32XchgU { memarg: MemoryImmediate }, + I32AtomicRmwCmpxchg { memarg: MemoryImmediate }, + I64AtomicRmwCmpxchg { memarg: MemoryImmediate }, + I32AtomicRmw8CmpxchgU { memarg: MemoryImmediate }, + I32AtomicRmw16CmpxchgU { memarg: MemoryImmediate }, + I64AtomicRmw8CmpxchgU { memarg: MemoryImmediate }, + I64AtomicRmw16CmpxchgU { memarg: MemoryImmediate }, + I64AtomicRmw32CmpxchgU { memarg: MemoryImmediate }, + + // 0xFD operators + // SIMD https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md + V128Load { memarg: MemoryImmediate }, + V128Store { memarg: MemoryImmediate }, + V128Const { value: V128 }, + I8x16Splat, + I8x16ExtractLaneS { lane: SIMDLaneIndex }, + I8x16ExtractLaneU { lane: SIMDLaneIndex }, + I8x16ReplaceLane { lane: SIMDLaneIndex }, + I16x8Splat, + I16x8ExtractLaneS { lane: SIMDLaneIndex }, + I16x8ExtractLaneU { lane: SIMDLaneIndex }, + I16x8ReplaceLane { lane: SIMDLaneIndex }, + I32x4Splat, + I32x4ExtractLane { lane: SIMDLaneIndex }, + I32x4ReplaceLane { lane: SIMDLaneIndex }, + I64x2Splat, + I64x2ExtractLane { lane: SIMDLaneIndex }, + I64x2ReplaceLane { lane: SIMDLaneIndex }, + F32x4Splat, + F32x4ExtractLane { lane: SIMDLaneIndex }, + F32x4ReplaceLane { lane: SIMDLaneIndex }, + F64x2Splat, + F64x2ExtractLane { lane: SIMDLaneIndex }, + F64x2ReplaceLane { lane: SIMDLaneIndex }, + I8x16Eq, + I8x16Ne, + I8x16LtS, + I8x16LtU, + I8x16GtS, + I8x16GtU, + I8x16LeS, + I8x16LeU, + I8x16GeS, + I8x16GeU, + I16x8Eq, + I16x8Ne, + I16x8LtS, + I16x8LtU, + I16x8GtS, + I16x8GtU, + I16x8LeS, + I16x8LeU, + I16x8GeS, + I16x8GeU, + I32x4Eq, + I32x4Ne, + I32x4LtS, + I32x4LtU, + I32x4GtS, + I32x4GtU, + I32x4LeS, + I32x4LeU, + I32x4GeS, + I32x4GeU, + F32x4Eq, + F32x4Ne, + F32x4Lt, + F32x4Gt, + F32x4Le, + F32x4Ge, + F64x2Eq, + F64x2Ne, + F64x2Lt, + F64x2Gt, + F64x2Le, + F64x2Ge, + V128Not, + V128And, + V128AndNot, + V128Or, + V128Xor, + V128Bitselect, + I8x16Neg, + I8x16AnyTrue, + I8x16AllTrue, + I8x16Shl, + I8x16ShrS, + I8x16ShrU, + I8x16Add, + I8x16AddSaturateS, + I8x16AddSaturateU, + I8x16Sub, + I8x16SubSaturateS, + I8x16SubSaturateU, + I8x16Mul, + I16x8Neg, + I16x8AnyTrue, + I16x8AllTrue, + I16x8Shl, + I16x8ShrS, + I16x8ShrU, + I16x8Add, + I16x8AddSaturateS, + I16x8AddSaturateU, + I16x8Sub, + I16x8SubSaturateS, + I16x8SubSaturateU, + I16x8Mul, + I32x4Neg, + I32x4AnyTrue, + I32x4AllTrue, + I32x4Shl, + I32x4ShrS, + I32x4ShrU, + I32x4Add, + I32x4Sub, + I32x4Mul, + I64x2Neg, + I64x2AnyTrue, + I64x2AllTrue, + I64x2Shl, + I64x2ShrS, + I64x2ShrU, + I64x2Add, + I64x2Sub, + I64x2Mul, + F32x4Abs, + F32x4Neg, + F32x4Sqrt, + F32x4Add, + F32x4Sub, + F32x4Mul, + F32x4Div, + F32x4Min, + F32x4Max, + F64x2Abs, + F64x2Neg, + F64x2Sqrt, + F64x2Add, + F64x2Sub, + F64x2Mul, + F64x2Div, + F64x2Min, + F64x2Max, + I32x4TruncSatF32x4S, + I32x4TruncSatF32x4U, + I64x2TruncSatF64x2S, + I64x2TruncSatF64x2U, + F32x4ConvertI32x4S, + F32x4ConvertI32x4U, + F64x2ConvertI64x2S, + F64x2ConvertI64x2U, + V8x16Swizzle, + V8x16Shuffle { lanes: [SIMDLaneIndex; 16] }, + V8x16LoadSplat { memarg: MemoryImmediate }, + V16x8LoadSplat { memarg: MemoryImmediate }, + V32x4LoadSplat { memarg: MemoryImmediate }, + V64x2LoadSplat { memarg: MemoryImmediate }, + I8x16NarrowI16x8S, + I8x16NarrowI16x8U, + I16x8NarrowI32x4S, + I16x8NarrowI32x4U, + I16x8WidenLowI8x16S, + I16x8WidenHighI8x16S, + I16x8WidenLowI8x16U, + I16x8WidenHighI8x16U, + I32x4WidenLowI16x8S, + I32x4WidenHighI16x8S, + I32x4WidenLowI16x8U, + I32x4WidenHighI16x8U, + I16x8Load8x8S { memarg: MemoryImmediate }, + I16x8Load8x8U { memarg: MemoryImmediate }, + I32x4Load16x4S { memarg: MemoryImmediate }, + I32x4Load16x4U { memarg: MemoryImmediate }, + I64x2Load32x2S { memarg: MemoryImmediate }, + I64x2Load32x2U { memarg: MemoryImmediate }, + I8x16RoundingAverageU, + I16x8RoundingAverageU, +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs new file mode 100644 index 0000000000..fac9c6e229 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/code_section.rs @@ -0,0 +1,245 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, BinaryReaderError, OperatorsReader, Range, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, Type, +}; + +#[derive(Debug)] +pub struct FunctionBody<'a> { + offset: usize, + data: &'a [u8], +} + +impl<'a> FunctionBody<'a> { + pub fn new(offset: usize, data: &'a [u8]) -> Self { + Self { offset, data } + } + + pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> + where + 'a: 'b, + { + BinaryReader::new_with_offset(self.data, self.offset) + } + + fn skip_locals(reader: &mut BinaryReader) -> Result<()> { + let count = reader.read_var_u32()?; + for _ in 0..count { + reader.skip_var_32()?; + reader.skip_type()?; + } + Ok(()) + } + + pub fn get_locals_reader<'b>(&self) -> Result<LocalsReader<'b>> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + let count = reader.read_var_u32()?; + Ok(LocalsReader { reader, count }) + } + + pub fn get_operators_reader<'b>(&self) -> Result<OperatorsReader<'b>> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + Self::skip_locals(&mut reader)?; + let pos = reader.position; + Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos)) + } + + pub fn range(&self) -> Range { + Range { + start: self.offset, + end: self.offset + self.data.len(), + } + } +} + +pub struct LocalsReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> LocalsReader<'a> { + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read(&mut self) -> Result<(u32, Type)> { + let count = self.reader.read_var_u32()?; + let value_type = self.reader.read_type()?; + Ok((count, value_type)) + } +} + +pub struct CodeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> IntoIterator for LocalsReader<'a> { + type Item = Result<(u32, Type)>; + type IntoIter = LocalsIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + LocalsIterator { + reader: self, + left: count, + err: false, + } + } +} + +pub struct LocalsIterator<'a> { + reader: LocalsReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for LocalsIterator<'a> { + type Item = Result<(u32, Type)>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +impl<'a> CodeSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<CodeSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(CodeSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + fn verify_body_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError { + message: "Function body extends past end of the code section", + offset: self.reader.original_offset + self.reader.buffer.len(), + }); + } + Ok(()) + } + + /// Reads content of the code section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("code section"); + /// let mut code_reader = section.get_code_section_reader().expect("code section reader"); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut binary_reader = body.get_binary_reader(); + /// assert!(binary_reader.read_local_count().expect("local count") == 0); + /// let op = binary_reader.read_operator().expect("first operator"); + /// println!("First operator: {:?}", op); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<FunctionBody<'b>> + where + 'a: 'b, + { + let size = self.reader.read_var_u32()? as usize; + let body_start = self.reader.position; + let body_end = body_start + size; + self.verify_body_end(body_end)?; + self.reader.skip_to(body_end); + Ok(FunctionBody { + offset: self.reader.original_offset + body_start, + data: &self.reader.buffer[body_start..body_end], + }) + } +} + +impl<'a> SectionReader for CodeSectionReader<'a> { + type Item = FunctionBody<'a>; + fn read(&mut self) -> Result<Self::Item> { + CodeSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + CodeSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for CodeSectionReader<'a> { + fn get_count(&self) -> u32 { + CodeSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for CodeSectionReader<'a> { + type Item = Result<FunctionBody<'a>>; + type IntoIter = SectionIteratorLimited<CodeSectionReader<'a>>; + + /// Implements iterator over the code section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("code section"); + /// let mut code_reader = section.get_code_section_reader().expect("code section reader"); + /// for body in code_reader { + /// let mut binary_reader = body.expect("b").get_binary_reader(); + /// assert!(binary_reader.read_local_count().expect("local count") == 0); + /// let op = binary_reader.read_operator().expect("first operator"); + /// println!("First operator: {:?}", op); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs new file mode 100644 index 0000000000..ac0f9db0f7 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/data_count_section.rs @@ -0,0 +1,28 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, BinaryReaderError, Result}; + +pub(crate) fn read_data_count_section_content(data: &[u8], offset: usize) -> Result<u32> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + if !reader.eof() { + return Err(BinaryReaderError { + message: "Unexpected content in the data count section", + offset: offset + reader.position, + }); + } + Ok(count) +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs new file mode 100644 index 0000000000..29b7d8284e --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/data_section.rs @@ -0,0 +1,157 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Data<'a> { + pub kind: DataKind<'a>, + pub data: &'a [u8], +} + +#[derive(Debug, Copy, Clone)] +pub enum DataKind<'a> { + Passive, + Active { + memory_index: u32, + init_expr: InitExpr<'a>, + }, +} + +pub struct DataSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> DataSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<DataSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(DataSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + fn verify_data_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError { + message: "Data segment extends past end of the data section", + offset: self.reader.original_offset + self.reader.buffer.len(), + }); + } + Ok(()) + } + + /// Reads content of the data section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x05, 0x03, 0x01, 0x00, 0x02, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b, + /// # 0x0b, 0x0b, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00]; + /// use wasmparser::{ModuleReader, DataKind}; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("memory section"); + /// let section = reader.read().expect("code section"); + /// let section = reader.read().expect("data section"); + /// let mut data_reader = section.get_data_section_reader().expect("data section reader"); + /// for _ in 0..data_reader.get_count() { + /// let data = data_reader.read().expect("data"); + /// println!("Data: {:?}", data); + /// if let DataKind::Active { init_expr, .. } = data.kind { + /// let mut init_expr_reader = init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Data<'b>> + where + 'a: 'b, + { + let flags = self.reader.read_var_u32()?; + let kind = if flags == 1 { + DataKind::Passive + } else { + let memory_index = match flags { + 0 => 0, + 2 => self.reader.read_var_u32()?, + _ => { + return Err(BinaryReaderError { + message: "invalid flags byte in data segment", + offset: self.reader.original_position() - 1, + }); + } + }; + let init_expr = { + let expr_offset = self.reader.position; + self.reader.skip_init_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + InitExpr::new(data, self.reader.original_offset + expr_offset) + }; + DataKind::Active { + memory_index, + init_expr, + } + }; + let data_len = self.reader.read_var_u32()? as usize; + let data_end = self.reader.position + data_len; + self.verify_data_end(data_end)?; + let data = &self.reader.buffer[self.reader.position..data_end]; + self.reader.skip_to(data_end); + Ok(Data { kind, data }) + } +} + +impl<'a> SectionReader for DataSectionReader<'a> { + type Item = Data<'a>; + fn read(&mut self) -> Result<Self::Item> { + DataSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + DataSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for DataSectionReader<'a> { + fn get_count(&self) -> u32 { + DataSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for DataSectionReader<'a> { + type Item = Result<Data<'a>>; + type IntoIter = SectionIteratorLimited<DataSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs new file mode 100644 index 0000000000..ef45113a3f --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/element_section.rs @@ -0,0 +1,301 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, Type, +}; +use crate::{ExternalKind, Operator}; + +#[derive(Clone)] +pub struct Element<'a> { + pub kind: ElementKind<'a>, + pub items: ElementItems<'a>, + pub ty: Type, +} + +#[derive(Clone)] +pub enum ElementKind<'a> { + Passive, + Active { + table_index: u32, + init_expr: InitExpr<'a>, + }, + Declared, +} + +#[derive(Debug, Copy, Clone)] +pub struct ElementItems<'a> { + exprs: bool, + offset: usize, + data: &'a [u8], +} + +#[derive(Debug)] +pub enum ElementItem { + Null, + Func(u32), +} + +impl<'a> ElementItems<'a> { + pub fn get_items_reader<'b>(&self) -> Result<ElementItemsReader<'b>> + where + 'a: 'b, + { + ElementItemsReader::new(self.data, self.offset, self.exprs) + } +} + +pub struct ElementItemsReader<'a> { + reader: BinaryReader<'a>, + count: u32, + exprs: bool, +} + +impl<'a> ElementItemsReader<'a> { + pub fn new(data: &[u8], offset: usize, exprs: bool) -> Result<ElementItemsReader> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ElementItemsReader { + reader, + count, + exprs, + }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn uses_exprs(&self) -> bool { + self.exprs + } + + pub fn read(&mut self) -> Result<ElementItem> { + if self.exprs { + let offset = self.reader.original_position(); + let ret = match self.reader.read_operator()? { + Operator::RefNull => ElementItem::Null, + Operator::RefFunc { function_index } => ElementItem::Func(function_index), + _ => { + return Err(BinaryReaderError { + message: "invalid passive segment", + offset, + }) + } + }; + match self.reader.read_operator()? { + Operator::End => {} + _ => { + return Err(BinaryReaderError { + message: "invalid passive segment", + offset, + }) + } + } + Ok(ret) + } else { + self.reader.read_var_u32().map(ElementItem::Func) + } + } +} + +impl<'a> IntoIterator for ElementItemsReader<'a> { + type Item = Result<ElementItem>; + type IntoIter = ElementItemsIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + ElementItemsIterator { + reader: self, + left: count, + err: false, + } + } +} + +pub struct ElementItemsIterator<'a> { + reader: ElementItemsReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for ElementItemsIterator<'a> { + type Item = Result<ElementItem>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +pub struct ElementSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ElementSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<ElementSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ElementSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the element section. + /// + /// # Examples + /// ```no-run + /// # let data: &[u8] = &[]; + /// use wasmparser::{ModuleReader, ElementKind}; + ///use wasmparser::Result; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("table section"); + /// let section = reader.read().expect("element section"); + /// let mut element_reader = section.get_element_section_reader().expect("element section reader"); + /// for _ in 0..element_reader.get_count() { + /// let element = element_reader.read().expect("element"); + /// if let ElementKind::Active { init_expr, .. } = element.kind { + /// let mut init_expr_reader = init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } + /// let mut items_reader = element.items.get_items_reader().expect("items reader"); + /// for _ in 0..items_reader.get_count() { + /// let item = items_reader.read().expect("item"); + /// println!(" Item: {:?}", item); + /// } + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Element<'b>> + where + 'a: 'b, + { + let flags = self.reader.read_var_u32()?; + if (flags & !0b111) != 0 { + return Err(BinaryReaderError { + message: "invalid flags byte in element segment", + offset: self.reader.original_position() - 1, + }); + } + let kind = if flags & 0b001 != 0 { + if flags & 0b010 != 0 { + ElementKind::Declared + } else { + ElementKind::Passive + } + } else { + let table_index = if flags & 0b010 == 0 { + 0 + } else { + self.reader.read_var_u32()? + }; + let init_expr = { + let expr_offset = self.reader.position; + self.reader.skip_init_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + InitExpr::new(data, self.reader.original_offset + expr_offset) + }; + ElementKind::Active { + table_index, + init_expr, + } + }; + let exprs = flags & 0b100 != 0; + let ty = if flags & 0b011 != 0 { + if exprs { + self.reader.read_type()? + } else { + match self.reader.read_external_kind()? { + ExternalKind::Function => Type::AnyFunc, + _ => { + return Err(BinaryReaderError { + message: "only the function external type is supported in elem segment", + offset: self.reader.original_position() - 1, + }); + } + } + } + } else { + Type::AnyFunc + }; + let data_start = self.reader.position; + let items_count = self.reader.read_var_u32()?; + if exprs { + for _ in 0..items_count { + self.reader.skip_init_expr()?; + } + } else { + for _ in 0..items_count { + self.reader.skip_var_32()?; + } + } + let data_end = self.reader.position; + let items = ElementItems { + offset: self.reader.original_offset + data_start, + data: &self.reader.buffer[data_start..data_end], + exprs, + }; + Ok(Element { kind, items, ty }) + } +} + +impl<'a> SectionReader for ElementSectionReader<'a> { + type Item = Element<'a>; + fn read(&mut self) -> Result<Self::Item> { + ElementSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ElementSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ElementSectionReader<'a> { + fn get_count(&self) -> u32 { + ElementSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ElementSectionReader<'a> { + type Item = Result<Element<'a>>; + type IntoIter = SectionIteratorLimited<ElementSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs new file mode 100644 index 0000000000..636ac2bcf3 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/export_section.rs @@ -0,0 +1,104 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, ExternalKind, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Export<'a> { + pub field: &'a str, + pub kind: ExternalKind, + pub index: u32, +} + +pub struct ExportSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ExportSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<ExportSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ExportSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the export section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x07, 0x5, 0x01, 0x01, 0x65, 0x00, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("export section"); + /// let mut export_reader = section.get_export_section_reader().expect("export section reader"); + /// for _ in 0..export_reader.get_count() { + /// let export = export_reader.read().expect("export"); + /// println!("Export: {:?}", export); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Export<'b>> + where + 'a: 'b, + { + let field = self.reader.read_string()?; + let kind = self.reader.read_external_kind()?; + let index = self.reader.read_var_u32()?; + Ok(Export { field, kind, index }) + } +} + +impl<'a> SectionReader for ExportSectionReader<'a> { + type Item = Export<'a>; + fn read(&mut self) -> Result<Self::Item> { + ExportSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ExportSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ExportSectionReader<'a> { + fn get_count(&self) -> u32 { + ExportSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ExportSectionReader<'a> { + type Item = Result<Export<'a>>; + type IntoIter = SectionIteratorLimited<ExportSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs new file mode 100644 index 0000000000..c81bb4d9ed --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/function_section.rs @@ -0,0 +1,86 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; + +pub struct FunctionSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> FunctionSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<FunctionSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(FunctionSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads function type index from the function section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let mut function_reader = section.get_function_section_reader().expect("function section reader"); + /// for _ in 0..function_reader.get_count() { + /// let ty = function_reader.read().expect("function type index"); + /// println!("Function type index: {}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<u32> { + self.reader.read_var_u32() + } +} + +impl<'a> SectionReader for FunctionSectionReader<'a> { + type Item = u32; + fn read(&mut self) -> Result<Self::Item> { + FunctionSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + FunctionSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for FunctionSectionReader<'a> { + fn get_count(&self) -> u32 { + FunctionSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for FunctionSectionReader<'a> { + type Item = Result<u32>; + type IntoIter = SectionIteratorLimited<FunctionSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs new file mode 100644 index 0000000000..15a85a7c36 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/global_section.rs @@ -0,0 +1,108 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, GlobalType, InitExpr, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Global<'a> { + pub ty: GlobalType, + pub init_expr: InitExpr<'a>, +} + +pub struct GlobalSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> GlobalSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<GlobalSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(GlobalSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the global section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x06, 0x8, 0x01, 0x7F, 0x01, 0x41, 0x90, 0x88, 0x04, 0x0B, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("global section"); + /// let mut global_reader = section.get_global_section_reader().expect("global section reader"); + /// for _ in 0..global_reader.get_count() { + /// let global = global_reader.read().expect("global"); + /// println!("Global: {:?}", global); + /// let mut init_expr_reader = global.init_expr.get_binary_reader(); + /// let op = init_expr_reader.read_operator().expect("op"); + /// println!("Init const: {:?}", op); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Global<'b>> + where + 'a: 'b, + { + let ty = self.reader.read_global_type()?; + let expr_offset = self.reader.position; + self.reader.skip_init_expr()?; + let data = &self.reader.buffer[expr_offset..self.reader.position]; + let init_expr = InitExpr::new(data, self.reader.original_offset + expr_offset); + Ok(Global { ty, init_expr }) + } +} + +impl<'a> SectionReader for GlobalSectionReader<'a> { + type Item = Global<'a>; + fn read(&mut self) -> Result<Self::Item> { + GlobalSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + GlobalSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for GlobalSectionReader<'a> { + fn get_count(&self) -> u32 { + GlobalSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for GlobalSectionReader<'a> { + type Item = Result<Global<'a>>; + type IntoIter = SectionIteratorLimited<GlobalSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs new file mode 100644 index 0000000000..92fd5f5e99 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/import_section.rs @@ -0,0 +1,109 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, ExternalKind, ImportSectionEntryType, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Import<'a> { + pub module: &'a str, + pub field: &'a str, + pub ty: ImportSectionEntryType, +} + +pub struct ImportSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ImportSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<ImportSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ImportSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the import section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, + /// # 0x02, 0x07, 0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00, + /// # 0x03, 0x02, 0x01, 0x00, 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("import section"); + /// let mut import_reader = section.get_import_section_reader().expect("import section reader"); + /// for _ in 0..import_reader.get_count() { + /// let import = import_reader.read().expect("import"); + /// println!("Import: {:?}", import); + /// } + /// ``` + pub fn read<'b>(&mut self) -> Result<Import<'b>> + where + 'a: 'b, + { + let module = self.reader.read_string()?; + let field = self.reader.read_string()?; + let kind = self.reader.read_external_kind()?; + let ty = match kind { + ExternalKind::Function => ImportSectionEntryType::Function(self.reader.read_var_u32()?), + ExternalKind::Table => ImportSectionEntryType::Table(self.reader.read_table_type()?), + ExternalKind::Memory => ImportSectionEntryType::Memory(self.reader.read_memory_type()?), + ExternalKind::Global => ImportSectionEntryType::Global(self.reader.read_global_type()?), + }; + Ok(Import { module, field, ty }) + } +} + +impl<'a> SectionReader for ImportSectionReader<'a> { + type Item = Import<'a>; + fn read(&mut self) -> Result<Self::Item> { + ImportSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ImportSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ImportSectionReader<'a> { + fn get_count(&self) -> u32 { + ImportSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ImportSectionReader<'a> { + type Item = Result<Import<'a>>; + type IntoIter = SectionIteratorLimited<ImportSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs b/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs new file mode 100644 index 0000000000..98c301d350 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/init_expr.rs @@ -0,0 +1,42 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, OperatorsReader}; + +#[derive(Debug, Copy, Clone)] +pub struct InitExpr<'a> { + offset: usize, + data: &'a [u8], +} + +impl<'a> InitExpr<'a> { + pub fn new(data: &[u8], offset: usize) -> InitExpr { + InitExpr { offset, data } + } + + pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> + where + 'a: 'b, + { + BinaryReader::new_with_offset(self.data, self.offset) + } + + pub fn get_operators_reader<'b>(&self) -> OperatorsReader<'b> + where + 'a: 'b, + { + OperatorsReader::new(self.data, self.offset) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs new file mode 100644 index 0000000000..4181cde2dd --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/linking_section.rs @@ -0,0 +1,75 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, LinkingType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +pub struct LinkingSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> LinkingSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<LinkingSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(LinkingSectionReader { reader, count }) + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read<'b>(&mut self) -> Result<LinkingType> + where + 'a: 'b, + { + Ok(self.reader.read_linking_type()?) + } +} + +impl<'a> SectionReader for LinkingSectionReader<'a> { + type Item = LinkingType; + fn read(&mut self) -> Result<Self::Item> { + LinkingSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + LinkingSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for LinkingSectionReader<'a> { + fn get_count(&self) -> u32 { + LinkingSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for LinkingSectionReader<'a> { + type Item = Result<LinkingType>; + type IntoIter = SectionIteratorLimited<LinkingSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs new file mode 100644 index 0000000000..6e9dcb9dd0 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/memory_section.rs @@ -0,0 +1,91 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, MemoryType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +pub struct MemorySectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> MemorySectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<MemorySectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(MemorySectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the memory section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x05, 0x03, 0x01, 0x00, 0x02, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("memory section"); + /// let mut memory_reader = section.get_memory_section_reader().expect("memory section reader"); + /// for _ in 0..memory_reader.get_count() { + /// let memory = memory_reader.read().expect("memory"); + /// println!("Memory: {:?}", memory); + /// } + /// ``` + pub fn read(&mut self) -> Result<MemoryType> { + self.reader.read_memory_type() + } +} + +impl<'a> SectionReader for MemorySectionReader<'a> { + type Item = MemoryType; + fn read(&mut self) -> Result<Self::Item> { + MemorySectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + MemorySectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for MemorySectionReader<'a> { + fn get_count(&self) -> u32 { + MemorySectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for MemorySectionReader<'a> { + type Item = Result<MemoryType>; + type IntoIter = SectionIteratorLimited<MemorySectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs b/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs new file mode 100644 index 0000000000..6eca50d9ff --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/mod.rs @@ -0,0 +1,100 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, BinaryReaderError, CustomSectionKind, ExternalKind, FuncType, GlobalType, + ImportSectionEntryType, LinkingType, MemoryType, NameType, Naming, Operator, Range, RelocType, + Result, SectionCode, TableType, Type, +}; + +use super::SectionHeader; + +pub use self::code_section::CodeSectionReader; +pub use self::code_section::FunctionBody; +pub use self::code_section::LocalsReader; +use self::data_count_section::read_data_count_section_content; +pub use self::data_section::Data; +pub use self::data_section::DataKind; +pub use self::data_section::DataSectionReader; +pub use self::element_section::Element; +pub use self::element_section::ElementItem; +pub use self::element_section::ElementItems; +pub use self::element_section::ElementItemsReader; +pub use self::element_section::ElementKind; +pub use self::element_section::ElementSectionReader; +pub use self::export_section::Export; +pub use self::export_section::ExportSectionReader; +pub use self::function_section::FunctionSectionReader; +pub use self::global_section::Global; +pub use self::global_section::GlobalSectionReader; +pub use self::import_section::Import; +pub use self::import_section::ImportSectionReader; +pub use self::init_expr::InitExpr; +pub use self::memory_section::MemorySectionReader; +pub use self::module::CustomSectionContent; +pub use self::module::ModuleReader; +pub use self::module::Section; +pub use self::module::SectionContent; +use self::start_section::read_start_section_content; +pub use self::table_section::TableSectionReader; +pub use self::type_section::TypeSectionReader; + +pub use self::section_reader::SectionIterator; +pub use self::section_reader::SectionIteratorLimited; +pub use self::section_reader::SectionReader; +pub use self::section_reader::SectionWithLimitedItems; + +pub use self::name_section::FunctionName; +pub use self::name_section::LocalName; +pub use self::name_section::ModuleName; +pub use self::name_section::Name; +pub use self::name_section::NameSectionReader; +pub use self::name_section::NamingReader; + +pub use self::producers_section::ProducersField; +pub use self::producers_section::ProducersFieldValue; +pub use self::producers_section::ProducersFieldValuesReader; +pub use self::producers_section::ProducersSectionReader; + +pub use self::linking_section::LinkingSectionReader; + +pub use self::reloc_section::Reloc; +pub use self::reloc_section::RelocSectionReader; + +use self::sourcemappingurl_section::read_sourcemappingurl_section_content; + +pub use self::operators::OperatorsReader; + +mod code_section; +mod data_count_section; +mod data_section; +mod element_section; +mod export_section; +mod function_section; +mod global_section; +mod import_section; +mod init_expr; +mod linking_section; +mod memory_section; +mod module; +mod name_section; +mod operators; +mod producers_section; +mod reloc_section; +mod section_reader; +mod sourcemappingurl_section; +mod start_section; +mod table_section; +mod type_section; diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/module.rs b/third_party/rust/wasmparser-0.48.2/src/readers/module.rs new file mode 100644 index 0000000000..2eb63d61e5 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/module.rs @@ -0,0 +1,512 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, BinaryReaderError, CustomSectionKind, Range, Result, SectionCode, SectionHeader, +}; + +use super::{ + read_data_count_section_content, read_sourcemappingurl_section_content, + read_start_section_content, CodeSectionReader, DataSectionReader, ElementSectionReader, + ExportSectionReader, FunctionSectionReader, GlobalSectionReader, ImportSectionReader, + LinkingSectionReader, MemorySectionReader, NameSectionReader, ProducersSectionReader, + RelocSectionReader, TableSectionReader, TypeSectionReader, +}; + +#[derive(Debug)] +pub struct Section<'a> { + pub code: SectionCode<'a>, + offset: usize, + data: &'a [u8], +} + +impl<'a> Section<'a> { + /// Creates reader for the type section. Available when the reader just read + /// the type section. + pub fn get_type_section_reader<'b>(&self) -> Result<TypeSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Type => TypeSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_type_section_reader"), + } + } + + /// Creates reader for the function section. Available when the reader just read + /// the function section. + pub fn get_function_section_reader<'b>(&self) -> Result<FunctionSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Function => FunctionSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_function_section_reader"), + } + } + + /// Creates reader for the code section. Available when the reader just read + /// the code section. + pub fn get_code_section_reader<'b>(&self) -> Result<CodeSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Code => CodeSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_function_section_reader"), + } + } + + /// Creates reader for the export section. Available when the reader just read + /// the export section. + pub fn get_export_section_reader<'b>(&self) -> Result<ExportSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Export => ExportSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_export_section_reader"), + } + } + + /// Creates reader for the import section. Available when the reader just read + /// the import section. + pub fn get_import_section_reader<'b>(&self) -> Result<ImportSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Import => ImportSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_import_section_reader"), + } + } + + /// Creates reader for the global section. Available when the reader just read + /// the global section. + pub fn get_global_section_reader<'b>(&self) -> Result<GlobalSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Global => GlobalSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_global_section_reader"), + } + } + + /// Creates reader for the memory section. Available when the reader just read + /// the memory section. + pub fn get_memory_section_reader<'b>(&self) -> Result<MemorySectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Memory => MemorySectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_memory_section_reader"), + } + } + + /// Creates reader for the data section. Available when the reader just read + /// the data section. + pub fn get_data_section_reader<'b>(&self) -> Result<DataSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Data => DataSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_data_section_reader"), + } + } + + /// Creates reader for the table section. Available when the reader just read + /// the table section. + pub fn get_table_section_reader<'b>(&self) -> Result<TableSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Table => TableSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_table_section_reader"), + } + } + + /// Creates reader for the element section. Available when the reader just read + /// the element section. + pub fn get_element_section_reader<'b>(&self) -> Result<ElementSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Element => ElementSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_element_section_reader"), + } + } + + pub fn get_name_section_reader<'b>(&self) -> Result<NameSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Name, + .. + } => NameSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_name_section_reader"), + } + } + + pub fn get_producers_section_reader<'b>(&self) -> Result<ProducersSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Producers, + .. + } => ProducersSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_producers_section_reader"), + } + } + + pub fn get_linking_section_reader<'b>(&self) -> Result<LinkingSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Linking, + .. + } => LinkingSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_linking_section_reader"), + } + } + + pub fn get_reloc_section_reader<'b>(&self) -> Result<RelocSectionReader<'b>> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::Reloc, + .. + } => RelocSectionReader::new(self.data, self.offset), + _ => panic!("Invalid state for get_reloc_section_reader"), + } + } + + pub fn get_start_section_content(&self) -> Result<u32> { + match self.code { + SectionCode::Start => read_start_section_content(self.data, self.offset), + _ => panic!("Invalid state for get_start_section_content"), + } + } + + pub fn get_data_count_section_content(&self) -> Result<u32> { + match self.code { + SectionCode::DataCount => read_data_count_section_content(self.data, self.offset), + _ => panic!("Invalid state for get_data_count_section_content"), + } + } + + pub fn get_sourcemappingurl_section_content<'b>(&self) -> Result<&'b str> + where + 'a: 'b, + { + match self.code { + SectionCode::Custom { + kind: CustomSectionKind::SourceMappingURL, + .. + } => read_sourcemappingurl_section_content(self.data, self.offset), + _ => panic!("Invalid state for get_start_section_content"), + } + } + + pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> + where + 'a: 'b, + { + BinaryReader::new_with_offset(self.data, self.offset) + } + + pub fn range(&self) -> Range { + Range { + start: self.offset, + end: self.offset + self.data.len(), + } + } + + pub fn content<'b>(&self) -> Result<SectionContent<'b>> + where + 'a: 'b, + { + let c = match self.code { + SectionCode::Type => SectionContent::Type(self.get_type_section_reader()?), + SectionCode::Function => SectionContent::Function(self.get_function_section_reader()?), + SectionCode::Code => SectionContent::Code(self.get_code_section_reader()?), + SectionCode::Export => SectionContent::Export(self.get_export_section_reader()?), + SectionCode::Import => SectionContent::Import(self.get_import_section_reader()?), + SectionCode::Global => SectionContent::Global(self.get_global_section_reader()?), + SectionCode::Memory => SectionContent::Memory(self.get_memory_section_reader()?), + SectionCode::Data => SectionContent::Data(self.get_data_section_reader()?), + SectionCode::Table => SectionContent::Table(self.get_table_section_reader()?), + SectionCode::Element => SectionContent::Element(self.get_element_section_reader()?), + SectionCode::Start => SectionContent::Start(self.get_start_section_content()?), + SectionCode::DataCount => { + SectionContent::DataCount(self.get_data_count_section_content()?) + } + SectionCode::Custom { kind, name } => { + // The invalid custom section may cause trouble during + // content() call. The spec recommends to ignore erroneous + // content in custom section. + // Return None in the content field if invalid. + let binary = self.get_binary_reader(); + let content = match kind { + CustomSectionKind::Name => self + .get_name_section_reader() + .ok() + .map(CustomSectionContent::Name), + CustomSectionKind::Producers => self + .get_producers_section_reader() + .ok() + .map(CustomSectionContent::Producers), + CustomSectionKind::Linking => self + .get_linking_section_reader() + .ok() + .map(CustomSectionContent::Linking), + CustomSectionKind::Reloc => self + .get_reloc_section_reader() + .ok() + .map(CustomSectionContent::Reloc), + CustomSectionKind::SourceMappingURL => self + .get_sourcemappingurl_section_content() + .ok() + .map(CustomSectionContent::SourceMappingURL), + _ => None, + }; + SectionContent::Custom { + name, + binary, + content, + } + } + }; + Ok(c) + } +} + +pub enum SectionContent<'a> { + Type(TypeSectionReader<'a>), + Function(FunctionSectionReader<'a>), + Code(CodeSectionReader<'a>), + Export(ExportSectionReader<'a>), + Import(ImportSectionReader<'a>), + Global(GlobalSectionReader<'a>), + Memory(MemorySectionReader<'a>), + Data(DataSectionReader<'a>), + Table(TableSectionReader<'a>), + Element(ElementSectionReader<'a>), + Start(u32), + DataCount(u32), + Custom { + name: &'a str, + binary: BinaryReader<'a>, + content: Option<CustomSectionContent<'a>>, + }, +} + +pub enum CustomSectionContent<'a> { + Name(NameSectionReader<'a>), + Producers(ProducersSectionReader<'a>), + Linking(LinkingSectionReader<'a>), + Reloc(RelocSectionReader<'a>), + SourceMappingURL(&'a str), +} + +/// Reads top-level WebAssembly file structure: header and sections. +pub struct ModuleReader<'a> { + reader: BinaryReader<'a>, + version: u32, + read_ahead: Option<(usize, SectionHeader<'a>)>, +} + +impl<'a> ModuleReader<'a> { + pub fn new(data: &[u8]) -> Result<ModuleReader> { + let mut reader = BinaryReader::new(data); + let version = reader.read_file_header()?; + Ok(ModuleReader { + reader, + version, + read_ahead: None, + }) + } + + pub fn get_version(&self) -> u32 { + self.version + } + + pub fn current_position(&self) -> usize { + match self.read_ahead { + Some((position, _)) => position, + _ => self.reader.current_position(), + } + } + + pub fn eof(&self) -> bool { + self.read_ahead.is_none() && self.reader.eof() + } + + fn verify_section_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError { + message: "Section body extends past end of file", + offset: self.reader.buffer.len(), + }); + } + if self.reader.position > end { + return Err(BinaryReaderError { + message: "Section header is too big to fit into section body", + offset: end, + }); + } + Ok(()) + } + + /// Reads next top-level record from the WebAssembly binary data. + /// The methods returns reference to current state of the reader. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("reader"); + /// let section = reader.read().expect("section #1"); + /// println!("First section {:?}", section); + /// let section = reader.read().expect("section #2"); + /// println!("Second section {:?}", section); + /// assert!(!reader.eof(), "there are more sections"); + /// ``` + pub fn read<'b>(&mut self) -> Result<Section<'b>> + where + 'a: 'b, + { + let SectionHeader { + code, + payload_start, + payload_len, + } = match self.read_ahead.take() { + Some((_, section_header)) => section_header, + None => self.reader.read_section_header()?, + }; + let payload_end = payload_start + payload_len; + self.verify_section_end(payload_end)?; + let body_start = self.reader.position; + self.reader.skip_to(payload_end); + Ok(Section { + code, + offset: body_start, + data: &self.reader.buffer[body_start..payload_end], + }) + } + + fn ensure_read_ahead(&mut self) -> Result<()> { + if self.read_ahead.is_none() && !self.eof() { + let position = self.reader.current_position(); + self.read_ahead = Some((position, self.reader.read_section_header()?)); + } + Ok(()) + } + + /// Skips custom sections. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x00, 0x8, 0x03, 0x63, 0x61, 0x74, 0x01, 0x02, 0x03, 0x04, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// use wasmparser::SectionCode; + /// let mut reader = ModuleReader::new(data).expect("reader"); + /// while { reader.skip_custom_sections(); !reader.eof() } { + /// let section = reader.read().expect("section"); + /// if let SectionCode::Custom {..} = section.code { panic!("no custom"); } + /// println!("Section {:?}", section); + /// } + /// ``` + pub fn skip_custom_sections(&mut self) -> Result<()> { + loop { + self.ensure_read_ahead()?; + match self.read_ahead { + Some(( + _, + SectionHeader { + code: SectionCode::Custom { .. }, + payload_start, + payload_len, + }, + )) => { + self.verify_section_end(payload_start + payload_len)?; + // Skip section + self.read_ahead = None; + self.reader.skip_to(payload_start + payload_len); + } + _ => break, + }; + } + Ok(()) + } +} + +impl<'a> IntoIterator for ModuleReader<'a> { + type Item = Result<Section<'a>>; + type IntoIter = ModuleIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + ModuleIterator { + reader: self, + err: false, + } + } +} + +pub struct ModuleIterator<'a> { + reader: ModuleReader<'a>, + err: bool, +} + +impl<'a> Iterator for ModuleIterator<'a> { + type Item = Result<Section<'a>>; + + /// Iterates sections from the WebAssembly binary data. Stops at first error. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// for section in ModuleReader::new(data).expect("reader") { + /// println!("Section {:?}", section); + /// } + /// ``` + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + Some(result) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs new file mode 100644 index 0000000000..f657c69fc7 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/name_section.rs @@ -0,0 +1,233 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, BinaryReaderError, NameType, Naming, Result, SectionIterator, SectionReader, +}; + +#[derive(Debug, Copy, Clone)] +pub struct ModuleName<'a> { + data: &'a [u8], + offset: usize, +} + +impl<'a> ModuleName<'a> { + pub fn get_name<'b>(&self) -> Result<&'b str> + where + 'a: 'b, + { + let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + reader.read_string() + } +} + +pub struct NamingReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> NamingReader<'a> { + fn new(data: &'a [u8], offset: usize) -> Result<NamingReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(NamingReader { reader, count }) + } + + fn skip(reader: &mut BinaryReader) -> Result<()> { + let count = reader.read_var_u32()?; + for _ in 0..count { + reader.skip_var_32()?; + reader.skip_string()?; + } + Ok(()) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn read<'b>(&mut self) -> Result<Naming<'b>> + where + 'a: 'b, + { + let index = self.reader.read_var_u32()?; + let name = self.reader.read_string()?; + Ok(Naming { index, name }) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct FunctionName<'a> { + data: &'a [u8], + offset: usize, +} + +impl<'a> FunctionName<'a> { + pub fn get_map<'b>(&self) -> Result<NamingReader<'b>> + where + 'a: 'b, + { + NamingReader::new(self.data, self.offset) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct FunctionLocalName<'a> { + pub func_index: u32, + data: &'a [u8], + offset: usize, +} + +impl<'a> FunctionLocalName<'a> { + pub fn get_map<'b>(&self) -> Result<NamingReader<'b>> + where + 'a: 'b, + { + NamingReader::new(self.data, self.offset) + } +} + +pub struct FunctionLocalReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> FunctionLocalReader<'a> { + fn new(data: &'a [u8], offset: usize) -> Result<FunctionLocalReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(FunctionLocalReader { reader, count }) + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read<'b>(&mut self) -> Result<FunctionLocalName<'b>> + where + 'a: 'b, + { + let func_index = self.reader.read_var_u32()?; + let start = self.reader.position; + NamingReader::skip(&mut self.reader)?; + let end = self.reader.position; + Ok(FunctionLocalName { + func_index, + data: &self.reader.buffer[start..end], + offset: self.reader.original_offset + start, + }) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct LocalName<'a> { + data: &'a [u8], + offset: usize, +} + +impl<'a> LocalName<'a> { + pub fn get_function_local_reader<'b>(&self) -> Result<FunctionLocalReader<'b>> + where + 'a: 'b, + { + FunctionLocalReader::new(self.data, self.offset) + } +} + +#[derive(Debug, Copy, Clone)] +pub enum Name<'a> { + Module(ModuleName<'a>), + Function(FunctionName<'a>), + Local(LocalName<'a>), +} + +pub struct NameSectionReader<'a> { + reader: BinaryReader<'a>, +} + +impl<'a> NameSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<NameSectionReader<'a>> { + Ok(NameSectionReader { + reader: BinaryReader::new_with_offset(data, offset), + }) + } + + fn verify_section_end(&self, end: usize) -> Result<()> { + if self.reader.buffer.len() < end { + return Err(BinaryReaderError { + message: "Name entry extends past end of the code section", + offset: self.reader.original_offset + self.reader.buffer.len(), + }); + } + Ok(()) + } + + pub fn eof(&self) -> bool { + self.reader.eof() + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read<'b>(&mut self) -> Result<Name<'b>> + where + 'a: 'b, + { + let ty = self.reader.read_name_type()?; + let payload_len = self.reader.read_var_u32()? as usize; + let payload_start = self.reader.position; + let payload_end = payload_start + payload_len; + self.verify_section_end(payload_end)?; + let offset = self.reader.original_offset + payload_start; + let data = &self.reader.buffer[payload_start..payload_end]; + self.reader.skip_to(payload_end); + Ok(match ty { + NameType::Module => Name::Module(ModuleName { data, offset }), + NameType::Function => Name::Function(FunctionName { data, offset }), + NameType::Local => Name::Local(LocalName { data, offset }), + }) + } +} + +impl<'a> SectionReader for NameSectionReader<'a> { + type Item = Name<'a>; + fn read(&mut self) -> Result<Self::Item> { + NameSectionReader::read(self) + } + fn eof(&self) -> bool { + NameSectionReader::eof(self) + } + fn original_position(&self) -> usize { + NameSectionReader::original_position(self) + } +} + +impl<'a> IntoIterator for NameSectionReader<'a> { + type Item = Result<Name<'a>>; + type IntoIter = SectionIterator<NameSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIterator::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs b/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs new file mode 100644 index 0000000000..0ecac8d5fb --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/operators.rs @@ -0,0 +1,171 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, BinaryReaderError, Operator, Result}; + +#[derive(Clone)] +pub struct OperatorsReader<'a> { + pub(crate) reader: BinaryReader<'a>, +} + +impl<'a> OperatorsReader<'a> { + pub(crate) fn new<'b>(data: &'a [u8], offset: usize) -> OperatorsReader<'b> + where + 'a: 'b, + { + OperatorsReader { + reader: BinaryReader::new_with_offset(data, offset), + } + } + + pub fn eof(&self) -> bool { + self.reader.eof() + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn ensure_end(&self) -> Result<()> { + if self.eof() { + return Ok(()); + } + Err(BinaryReaderError { + message: "Unexpected data at the end of operators", + offset: self.reader.original_position(), + }) + } + + pub fn read<'b>(&mut self) -> Result<Operator<'b>> + where + 'a: 'b, + { + self.reader.read_operator() + } + + pub fn into_iter_with_offsets<'b>(self) -> OperatorsIteratorWithOffsets<'b> + where + 'a: 'b, + { + OperatorsIteratorWithOffsets { + reader: self, + err: false, + } + } + + pub fn read_with_offset<'b>(&mut self) -> Result<(Operator<'b>, usize)> + where + 'a: 'b, + { + let pos = self.reader.original_position(); + Ok((self.read()?, pos)) + } +} + +impl<'a> IntoIterator for OperatorsReader<'a> { + type Item = Result<Operator<'a>>; + type IntoIter = OperatorsIterator<'a>; + + /// Reads content of the code section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::{ModuleReader, Result, Operator}; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("code section"); + /// let mut code_reader = section.get_code_section_reader().expect("code section reader"); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut op_reader = body.get_operators_reader().expect("op reader"); + /// let ops = op_reader.into_iter().collect::<Result<Vec<Operator>>>().expect("ops"); + /// assert!( + /// if let [Operator::Nop, Operator::End] = ops.as_slice() { true } else { false }, + /// "found {:?}", + /// ops + /// ); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + OperatorsIterator { + reader: self, + err: false, + } + } +} + +pub struct OperatorsIterator<'a> { + reader: OperatorsReader<'a>, + err: bool, +} + +impl<'a> Iterator for OperatorsIterator<'a> { + type Item = Result<Operator<'a>>; + + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + Some(result) + } +} + +pub struct OperatorsIteratorWithOffsets<'a> { + reader: OperatorsReader<'a>, + err: bool, +} + +impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { + type Item = Result<(Operator<'a>, usize)>; + + /// Reads content of the code section with offsets. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, /* offset = 23 */ 0x01, 0x0b]; + /// use wasmparser::{ModuleReader, Result, Operator}; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("code section"); + /// let mut code_reader = section.get_code_section_reader().expect("code section reader"); + /// for _ in 0..code_reader.get_count() { + /// let body = code_reader.read().expect("function body"); + /// let mut op_reader = body.get_operators_reader().expect("op reader"); + /// let ops = op_reader.into_iter_with_offsets().collect::<Result<Vec<(Operator, usize)>>>().expect("ops"); + /// assert!( + /// if let [(Operator::Nop, 23), (Operator::End, 24)] = ops.as_slice() { true } else { false }, + /// "found {:?}", + /// ops + /// ); + /// } + /// ``` + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read_with_offset(); + self.err = result.is_err(); + Some(result) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs new file mode 100644 index 0000000000..a65769c1d9 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/producers_section.rs @@ -0,0 +1,192 @@ +/* Copyright 2019 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; + +#[derive(Debug, Copy, Clone)] +pub struct ProducersFieldValue<'a> { + pub name: &'a str, + pub version: &'a str, +} + +pub struct ProducersFieldValuesReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ProducersFieldValuesReader<'a> { + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + fn skip(reader: &mut BinaryReader, values_count: u32) -> Result<()> { + for _ in 0..values_count { + reader.skip_string()?; + reader.skip_string()?; + } + Ok(()) + } + + pub fn read<'b>(&mut self) -> Result<ProducersFieldValue<'b>> + where + 'a: 'b, + { + let name = self.reader.read_string()?; + let version = self.reader.read_string()?; + Ok(ProducersFieldValue { name, version }) + } +} + +impl<'a> IntoIterator for ProducersFieldValuesReader<'a> { + type Item = Result<ProducersFieldValue<'a>>; + type IntoIter = ProducersFieldValuesIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + let count = self.count; + ProducersFieldValuesIterator { + reader: self, + left: count, + err: false, + } + } +} + +pub struct ProducersFieldValuesIterator<'a> { + reader: ProducersFieldValuesReader<'a>, + left: u32, + err: bool, +} + +impl<'a> Iterator for ProducersFieldValuesIterator<'a> { + type Item = Result<ProducersFieldValue<'a>>; + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.left == 0 { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + self.left -= 1; + Some(result) + } + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct ProducersField<'a> { + pub name: &'a str, + values_count: u32, + values_data: &'a [u8], + values_offset: usize, +} + +impl<'a> ProducersField<'a> { + pub fn get_producer_field_values_reader<'b>(&self) -> Result<ProducersFieldValuesReader<'b>> + where + 'a: 'b, + { + Ok(ProducersFieldValuesReader { + reader: BinaryReader::new_with_offset(self.values_data, self.values_offset), + count: self.values_count, + }) + } +} + +pub struct ProducersSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ProducersSectionReader<'a> { + /// Creates reader for the producers section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x01, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + /// # 0x02, 0x03, 0x77, 0x61, 0x74, 0x01, 0x31, 0x01, 0x43, 0x03, 0x39, 0x2e, 0x30]; + /// use wasmparser::{ProducersSectionReader, ProducersFieldValue, Result}; + /// let mut reader = ProducersSectionReader::new(data, 0).expect("producers reader"); + /// let field = reader.read().expect("producers field"); + /// assert!(field.name == "language"); + /// let mut values_reader = field.get_producer_field_values_reader().expect("values reader"); + /// let value = values_reader.into_iter().collect::<Result<Vec<ProducersFieldValue>>>().expect("values"); + /// assert!(value.len() == 2); + /// assert!(value[0].name == "wat" && value[0].version == "1"); + /// assert!(value[1].name == "C" && value[1].version == "9.0"); + /// ``` + pub fn new(data: &'a [u8], offset: usize) -> Result<ProducersSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(ProducersSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn read<'b>(&mut self) -> Result<ProducersField<'b>> + where + 'a: 'b, + { + let name = self.reader.read_string()?; + let values_count = self.reader.read_var_u32()?; + let values_start = self.reader.position; + ProducersFieldValuesReader::skip(&mut self.reader, values_count)?; + let values_end = self.reader.position; + Ok(ProducersField { + name, + values_count, + values_data: &self.reader.buffer[values_start..values_end], + values_offset: self.reader.original_offset + values_start, + }) + } +} + +impl<'a> SectionReader for ProducersSectionReader<'a> { + type Item = ProducersField<'a>; + fn read(&mut self) -> Result<Self::Item> { + ProducersSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + ProducersSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for ProducersSectionReader<'a> { + fn get_count(&self) -> u32 { + ProducersSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for ProducersSectionReader<'a> { + type Item = Result<ProducersField<'a>>; + type IntoIter = SectionIteratorLimited<ProducersSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs new file mode 100644 index 0000000000..2758294cb0 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/reloc_section.rs @@ -0,0 +1,115 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, RelocType, Result, SectionCode, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Reloc { + pub ty: RelocType, + pub offset: u32, + pub index: u32, + pub addend: Option<u32>, +} + +pub struct RelocSectionReader<'a> { + reader: BinaryReader<'a>, + section_code: SectionCode<'a>, + count: u32, +} + +impl<'a> RelocSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<RelocSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + + let section_id_position = reader.position; + let section_id = reader.read_var_u7()?; + let section_code = reader.read_section_code(section_id, section_id_position)?; + + let count = reader.read_var_u32()?; + Ok(RelocSectionReader { + reader, + section_code, + count, + }) + } + + pub fn get_count(&self) -> u32 { + self.count + } + + pub fn get_section_code<'b>(&self) -> SectionCode<'b> + where + 'a: 'b, + { + self.section_code + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn read(&mut self) -> Result<Reloc> { + let ty = self.reader.read_reloc_type()?; + let offset = self.reader.read_var_u32()?; + let index = self.reader.read_var_u32()?; + let addend = match ty { + RelocType::FunctionIndexLEB + | RelocType::TableIndexSLEB + | RelocType::TableIndexI32 + | RelocType::TypeIndexLEB + | RelocType::GlobalIndexLEB => None, + RelocType::GlobalAddrLEB | RelocType::GlobalAddrSLEB | RelocType::GlobalAddrI32 => { + Some(self.reader.read_var_u32()?) + } + }; + Ok(Reloc { + ty, + offset, + index, + addend, + }) + } +} + +impl<'a> SectionReader for RelocSectionReader<'a> { + type Item = Reloc; + fn read(&mut self) -> Result<Self::Item> { + RelocSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + RelocSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for RelocSectionReader<'a> { + fn get_count(&self) -> u32 { + RelocSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for RelocSectionReader<'a> { + type Item = Result<Reloc>; + type IntoIter = SectionIteratorLimited<RelocSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs b/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs new file mode 100644 index 0000000000..6ec9cd791d --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/section_reader.rs @@ -0,0 +1,123 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReaderError, Result}; + +pub trait SectionReader { + type Item; + fn read(&mut self) -> Result<Self::Item>; + fn eof(&self) -> bool; + fn original_position(&self) -> usize; + fn ensure_end(&self) -> Result<()> { + if self.eof() { + return Ok(()); + } + Err(BinaryReaderError { + message: "Unexpected data at the end of the section", + offset: self.original_position(), + }) + } +} + +pub trait SectionWithLimitedItems { + fn get_count(&self) -> u32; +} + +pub struct SectionIterator<R> +where + R: SectionReader, +{ + reader: R, + err: bool, +} + +impl<R> SectionIterator<R> +where + R: SectionReader, +{ + pub fn new(reader: R) -> SectionIterator<R> { + SectionIterator { reader, err: false } + } +} + +impl<R> Iterator for SectionIterator<R> +where + R: SectionReader, +{ + type Item = Result<R::Item>; + + fn next(&mut self) -> Option<Self::Item> { + if self.err || self.reader.eof() { + return None; + } + let result = self.reader.read(); + self.err = result.is_err(); + Some(result) + } +} + +pub struct SectionIteratorLimited<R> +where + R: SectionReader + SectionWithLimitedItems, +{ + reader: R, + left: u32, + end: bool, +} + +impl<R> SectionIteratorLimited<R> +where + R: SectionReader + SectionWithLimitedItems, +{ + pub fn new(reader: R) -> SectionIteratorLimited<R> { + let left = reader.get_count(); + SectionIteratorLimited { + reader, + left, + end: false, + } + } +} + +impl<R> Iterator for SectionIteratorLimited<R> +where + R: SectionReader + SectionWithLimitedItems, +{ + type Item = Result<R::Item>; + + fn next(&mut self) -> Option<Self::Item> { + if self.end { + return None; + } + if self.left == 0 { + return match self.reader.ensure_end() { + Ok(()) => None, + Err(err) => { + self.end = true; + Some(Err(err)) + } + }; + } + let result = self.reader.read(); + self.end = result.is_err(); + self.left -= 1; + Some(result) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let count = self.reader.get_count() as usize; + (count, Some(count)) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs new file mode 100644 index 0000000000..6f6e5eef21 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/sourcemappingurl_section.rs @@ -0,0 +1,31 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, BinaryReaderError, Result}; + +pub(crate) fn read_sourcemappingurl_section_content<'a>( + data: &'a [u8], + offset: usize, +) -> Result<&'a str> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let url = reader.read_string()?; + if !reader.eof() { + return Err(BinaryReaderError { + message: "Unexpected content in the sourceMappingURL section", + offset: offset + reader.position, + }); + } + Ok(url) +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs new file mode 100644 index 0000000000..81da40b58f --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/start_section.rs @@ -0,0 +1,28 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{BinaryReader, BinaryReaderError, Result}; + +pub(crate) fn read_start_section_content(data: &[u8], offset: usize) -> Result<u32> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let start_index = reader.read_var_u32()?; + if !reader.eof() { + return Err(BinaryReaderError { + message: "Unexpected content in the start section", + offset: offset + reader.position, + }); + } + Ok(start_index) +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs new file mode 100644 index 0000000000..322e23656f --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/table_section.rs @@ -0,0 +1,90 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TableType, +}; + +pub struct TableSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> TableSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<TableSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(TableSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the table section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("type section"); + /// let section = reader.read().expect("function section"); + /// let section = reader.read().expect("table section"); + /// let mut table_reader = section.get_table_section_reader().expect("table section reader"); + /// for _ in 0..table_reader.get_count() { + /// let table = table_reader.read().expect("table"); + /// println!("Table: {:?}", table); + /// } + /// ``` + pub fn read(&mut self) -> Result<TableType> { + self.reader.read_table_type() + } +} + +impl<'a> SectionReader for TableSectionReader<'a> { + type Item = TableType; + fn read(&mut self) -> Result<Self::Item> { + TableSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + TableSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for TableSectionReader<'a> { + fn get_count(&self) -> u32 { + TableSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for TableSectionReader<'a> { + type Item = Result<TableType>; + type IntoIter = SectionIteratorLimited<TableSectionReader<'a>>; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs b/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs new file mode 100644 index 0000000000..51fd6eea36 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/readers/type_section.rs @@ -0,0 +1,103 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + BinaryReader, FuncType, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, +}; + +pub struct TypeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> TypeSectionReader<'a> { + pub fn new(data: &'a [u8], offset: usize) -> Result<TypeSectionReader<'a>> { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(TypeSectionReader { reader, count }) + } + + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the type section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("section"); + /// let mut type_reader = section.get_type_section_reader().expect("type section reader"); + /// for _ in 0..type_reader.get_count() { + /// let ty = type_reader.read().expect("type"); + /// println!("Type {:?}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result<FuncType> { + self.reader.read_func_type() + } +} + +impl<'a> SectionReader for TypeSectionReader<'a> { + type Item = FuncType; + fn read(&mut self) -> Result<Self::Item> { + TypeSectionReader::read(self) + } + fn eof(&self) -> bool { + self.reader.eof() + } + fn original_position(&self) -> usize { + TypeSectionReader::original_position(self) + } +} + +impl<'a> SectionWithLimitedItems for TypeSectionReader<'a> { + fn get_count(&self) -> u32 { + TypeSectionReader::get_count(self) + } +} + +impl<'a> IntoIterator for TypeSectionReader<'a> { + type Item = Result<FuncType>; + type IntoIter = SectionIteratorLimited<TypeSectionReader<'a>>; + + /// Implements iterator over the type section. + /// + /// # Examples + /// ``` + /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + /// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + /// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b]; + /// use wasmparser::ModuleReader; + /// use wasmparser::{Result, FuncType}; + /// let mut reader = ModuleReader::new(data).expect("module reader"); + /// let section = reader.read().expect("section"); + /// let mut type_reader = section.get_type_section_reader().expect("type section reader"); + /// for ty in type_reader { + /// println!("Type {:?}", ty); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/tests.rs b/third_party/rust/wasmparser-0.48.2/src/tests.rs new file mode 100644 index 0000000000..527ace1993 --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/tests.rs @@ -0,0 +1,529 @@ +/* Copyright 2017 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#[cfg(test)] +mod simple_tests { + use crate::operators_validator::OperatorValidatorConfig; + use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder}; + use crate::primitives::{Operator, SectionCode}; + use crate::validator::{ValidatingParser, ValidatingParserConfig}; + use std::fs::{read_dir, File}; + use std::io::prelude::*; + use std::path::PathBuf; + + const VALIDATOR_CONFIG: Option<ValidatingParserConfig> = Some(ValidatingParserConfig { + operator_config: OperatorValidatorConfig { + enable_threads: true, + enable_reference_types: true, + enable_simd: true, + enable_bulk_memory: true, + enable_multi_value: true, + + #[cfg(feature = "deterministic")] + deterministic_only: true, + }, + }); + + fn read_file_data(path: &PathBuf) -> Vec<u8> { + println!("Parsing {:?}", path); + let mut data = Vec::new(); + let mut f = File::open(path).ok().unwrap(); + f.read_to_end(&mut data).unwrap(); + data + } + + #[allow(dead_code)] + fn scan_tests_files(prefix: &str) -> Vec<PathBuf> { + let mut files = Vec::new(); + + for entry in read_dir("tests/").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + + let path = dir.path(); + let file = path.to_str().unwrap(); + + if file.starts_with(prefix) { + files.push(path); + } + } + + return files; + } + + #[test] + fn it_works() { + for entry in read_dir("tests").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + let data = read_file_data(&dir.path()); + let mut parser = Parser::new(data.as_slice()); + let mut max_iteration = 100000000; + loop { + let state = parser.read(); + match *state { + ParserState::EndWasm => break, + ParserState::Error(err) => panic!("Error: {:?}", err), + _ => (), + } + max_iteration -= 1; + if max_iteration == 0 { + panic!("Max iterations exceeded"); + } + } + } + } + + #[test] + fn validator_not_fails() { + for entry in read_dir("tests").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + let data = read_file_data(&dir.path()); + let mut parser = ValidatingParser::new(data.as_slice(), VALIDATOR_CONFIG); + let mut max_iteration = 100000000; + loop { + let state = parser.read(); + match *state { + ParserState::EndWasm => break, + ParserState::Error(err) => panic!("Error: {:?}", err), + _ => (), + } + max_iteration -= 1; + if max_iteration == 0 { + panic!("Max iterations exceeded"); + } + } + } + } + + #[test] + fn validator_fails() { + for entry in read_dir("tests/invalid").unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() { + continue; + } + let data = read_file_data(&dir.path()); + let mut parser = ValidatingParser::new(data.as_slice(), VALIDATOR_CONFIG); + let mut max_iteration = 100000000; + let mut error = false; + loop { + let state = parser.read(); + if let ParserState::Error(_) = *state { + error = true; + break; + } + if let ParserState::EndWasm = *state { + break; + } + max_iteration -= 1; + if max_iteration == 0 { + panic!("Max iterations exceeded"); + } + } + if !error { + panic!("fail is expected"); + } + } + } + + macro_rules! expect_state { + ($state:expr, $expected:pat) => {{ + { + let state: &ParserState = $state; + match *state { + $expected => (), + _ => panic!("Unexpected state during testing: {:?}", state), + } + } + }}; + } + + #[test] + fn default_read() { + let data = read_file_data(&PathBuf::from("tests/simple.wasm")); + let mut parser = Parser::new(data.as_slice()); + + expect_state!(parser.read(), ParserState::BeginWasm { .. }); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Type, .. }); + expect_state!(parser.read(), ParserState::TypeSectionEntry(_)); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Function, .. }); + expect_state!(parser.read(), ParserState::FunctionSectionEntry(_)); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Code, .. }); + expect_state!(parser.read(), ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read(), ParserState::FunctionBodyLocals { .. }); + expect_state!(parser.read(), ParserState::CodeOperator(_)); + expect_state!(parser.read(), ParserState::CodeOperator(Operator::End)); + expect_state!(parser.read(), ParserState::EndFunctionBody); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::EndWasm); + } + + #[test] + fn default_read_with_input() { + let data = read_file_data(&PathBuf::from("tests/simple.wasm")); + let mut parser = Parser::new(data.as_slice()); + + expect_state!(parser.read(), ParserState::BeginWasm { .. }); + expect_state!(parser.read_with_input(ParserInput::Default), + ParserState::BeginSection { code: SectionCode::Type, .. }); + expect_state!(parser.read(), ParserState::TypeSectionEntry(_)); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Function, ..}); + expect_state!( + parser.read_with_input(ParserInput::ReadSectionRawData), + ParserState::SectionRawData(_) + ); + expect_state!(parser.read(), ParserState::EndSection); + expect_state!(parser.read(), ParserState::BeginSection { code: SectionCode::Code, .. }); + expect_state!(parser.read(), ParserState::BeginFunctionBody { .. }); + expect_state!( + parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::EndSection + ); + expect_state!(parser.read(), ParserState::EndWasm); + } + + #[test] + fn skipping() { + let data = read_file_data(&PathBuf::from("tests/naming.wasm")); + let mut parser = Parser::new(data.as_slice()); + + expect_state!(parser.read(), + ParserState::BeginWasm { .. }); + expect_state!(parser.read_with_input(ParserInput::Default), + ParserState::BeginSection { code: SectionCode::Type, .. }); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Import, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Function, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Global, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Export, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Element, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Code, .. }); + expect_state!(parser.read(), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!(parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::BeginFunctionBody { .. }); + expect_state!( + parser.read_with_input(ParserInput::SkipFunctionBody), + ParserState::EndSection + ); + expect_state!(parser.read(), + ParserState::BeginSection { code: SectionCode::Custom { .. }, ..}); + expect_state!(parser.read_with_input(ParserInput::SkipSection), + ParserState::BeginSection { code: SectionCode::Custom { .. }, .. }); + expect_state!( + parser.read_with_input(ParserInput::SkipSection), + ParserState::EndWasm + ); + } + + #[cfg(feature = "deterministic")] + fn run_deterministic_enabled_test(path: &PathBuf) { + let data = read_file_data(path); + + let config = Some(ValidatingParserConfig { + operator_config: OperatorValidatorConfig { + deterministic_only: false, + enable_threads: true, + enable_reference_types: true, + enable_simd: true, + enable_bulk_memory: true, + enable_multi_value: true, + }, + }); + + let mut parser = ValidatingParser::new(data.as_slice(), config); + let mut error = false; + + loop { + let state = parser.read(); + if let ParserState::Error(_) = *state { + error = true; + break; + } + if let ParserState::EndWasm = *state { + break; + } + } + + assert!(error); + } + + #[cfg(feature = "deterministic")] + #[test] + fn deterministic_enabled() { + // `float_exprs.*.wasm` + let mut tests_count = 0; + for path in scan_tests_files("tests/float_exprs.") { + run_deterministic_enabled_test(&path); + tests_count += 1; + } + assert_eq!(96, tests_count); + + // `float_memory.*.wasm` + let mut tests_count = 0; + for path in scan_tests_files("tests/float_memory.") { + run_deterministic_enabled_test(&path); + tests_count += 1; + } + assert_eq!(6, tests_count); + + // `float_misc.*.wasm` + let mut tests_count = 0; + for path in scan_tests_files("tests/float_misc.") { + run_deterministic_enabled_test(&path); + tests_count += 1; + } + assert_eq!(1, tests_count); + } +} + +#[cfg(test)] +mod wast_tests { + use crate::operators_validator::OperatorValidatorConfig; + use crate::parser::{ParserState, WasmDecoder}; + use crate::validator::{ValidatingParser, ValidatingParserConfig}; + use crate::BinaryReaderError; + use std::fs::{read, read_dir}; + use std::str; + + const SPEC_TESTS_PATH: &str = "testsuite"; + + fn default_config() -> ValidatingParserConfig { + ValidatingParserConfig { + operator_config: OperatorValidatorConfig { + enable_threads: false, + enable_reference_types: false, + enable_simd: false, + enable_bulk_memory: false, + enable_multi_value: false, + + #[cfg(feature = "deterministic")] + deterministic_only: true, + }, + } + } + + fn validate_module( + mut module: wast::Module, + config: ValidatingParserConfig, + ) -> Result<(), BinaryReaderError> { + let data = module.encode().unwrap(); + let mut parser = ValidatingParser::new(data.as_slice(), Some(config)); + let mut max_iteration = 100000000; + loop { + let state = parser.read(); + match *state { + ParserState::EndWasm => break, + ParserState::Error(err) => return Err(err), + _ => (), + } + max_iteration -= 1; + if max_iteration == 0 { + panic!("Max iterations exceeded"); + } + } + Ok(()) + } + + fn run_wabt_scripts<F>( + filename: &str, + wast: &[u8], + config: ValidatingParserConfig, + skip_test: F, + ) where + F: Fn(&str, u64) -> bool, + { + println!("Parsing {:?}", filename); + // Check if we need to skip entire wast file test/parsing. + if skip_test(filename, /* line = */ 0) { + println!("{}: skipping", filename); + return; + } + + let contents = str::from_utf8(wast).unwrap(); + let buf = wast::parser::ParseBuffer::new(&contents) + .map_err(|mut e| { + e.set_path(filename.as_ref()); + e + }) + .unwrap(); + let wast = wast::parser::parse::<wast::Wast>(&buf) + .map_err(|mut e| { + e.set_path(filename.as_ref()); + e + }) + .unwrap(); + + for directive in wast.directives { + use wast::WastDirective::*; + let (line, _col) = directive.span().linecol_in(&contents); + let line = line + 1; + if skip_test(filename, line as u64) { + println!("{}:{}: skipping", filename, line); + continue; + } + match directive { + Module(module) | AssertUnlinkable { module, .. } => { + if let Err(err) = validate_module(module, config.clone()) { + panic!("{}:{}: invalid module: {}", filename, line, err.message); + } + } + AssertInvalid { module, .. } + | AssertMalformed { + module: wast::QuoteModule::Module(module), + .. + } => { + // TODO diffentiate between assert_invalid and assert_malformed + if let Ok(_) = validate_module(module, config.clone()) { + panic!( + "{}:{}: invalid module was successfully parsed", + filename, line + ); + } + // TODO: Check the assert_invalid or assert_malformed message + } + + AssertMalformed { + module: wast::QuoteModule::Quote(_), + .. + } + | Register { .. } + | Invoke { .. } + | AssertTrap { .. } + | AssertReturn { .. } + | AssertReturnFunc { .. } + | AssertExhaustion { .. } => {} + } + } + } + + fn run_proposal_tests<F>(name: &str, config: ValidatingParserConfig, skip_test: F) + where + F: Fn(&str, u64) -> bool, + { + let proposal_dir = format!("{}/proposals/{}", SPEC_TESTS_PATH, name); + for entry in read_dir(&proposal_dir).unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() + || dir.path().extension().map(|s| s.to_str().unwrap()) != Some("wast") + { + continue; + } + + let data = read(&dir.path()).expect("wast data"); + run_wabt_scripts( + dir.file_name().to_str().expect("name"), + &data, + config, + |name, line| skip_test(name, line), + ); + } + } + + #[test] + fn run_proposals_tests() { + run_proposal_tests( + "simd", + { + let mut config: ValidatingParserConfig = default_config(); + config.operator_config.enable_simd = true; + config + }, + |name, line| match (name, line) { + // FIXME(WebAssembly/simd#140) needs a few updates to the + // `*.wast` file to successfully parse it (or so I think) + ("simd_lane.wast", _) => true, + ("simd_load_extend.wast", _) => true, + ("simd_f32x4_arith.wast", _) => true, + ("simd_f64x2_arith.wast", _) => true, + ("simd_f32x4.wast", _) => true, + ("simd_f64x2.wast", _) => true, + ("simd_const.wast", _) => true, + ("simd_load_splat.wast", _) => true, + _ => false, + }, + ); + + run_proposal_tests( + "multi-value", + { + let mut config: ValidatingParserConfig = default_config(); + config.operator_config.enable_multi_value = true; + config + }, + |_name, _line| false, + ); + + run_proposal_tests( + "reference-types", + { + let mut config: ValidatingParserConfig = default_config(); + config.operator_config.enable_reference_types = true; + config.operator_config.enable_bulk_memory = true; + config + }, + |name, line| match (name, line) { + ("br_table.wast", _) | ("select.wast", _) => true, + _ => false, + }, + ); + } + + #[test] + fn run_spec_tests() { + for entry in read_dir(SPEC_TESTS_PATH).unwrap() { + let dir = entry.unwrap(); + if !dir.file_type().unwrap().is_file() + || dir.path().extension().map(|s| s.to_str().unwrap()) != Some("wast") + { + continue; + } + + let data = read(&dir.path()).expect("wast data"); + run_wabt_scripts( + dir.file_name().to_str().expect("name"), + &data, + default_config(), + |_, _| false, + ); + } + } +} diff --git a/third_party/rust/wasmparser-0.48.2/src/validator.rs b/third_party/rust/wasmparser-0.48.2/src/validator.rs new file mode 100644 index 0000000000..2fae3112bd --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/src/validator.rs @@ -0,0 +1,946 @@ +/* Copyright 2018 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::collections::HashSet; +use std::result; +use std::str; + +use crate::limits::{ + MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_GLOBALS, MAX_WASM_MEMORIES, + MAX_WASM_MEMORY_PAGES, MAX_WASM_TABLES, MAX_WASM_TYPES, +}; + +use crate::binary_reader::BinaryReader; + +use crate::primitives::{ + BinaryReaderError, ExternalKind, FuncType, GlobalType, ImportSectionEntryType, MemoryType, + Operator, ResizableLimits, Result, SectionCode, TableType, Type, +}; + +use crate::operators_validator::{ + is_subtype_supertype, FunctionEnd, OperatorValidator, OperatorValidatorConfig, + DEFAULT_OPERATOR_VALIDATOR_CONFIG, +}; +use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder}; +use crate::{ElemSectionEntryTable, ElementItem}; +use crate::{WasmFuncType, WasmGlobalType, WasmMemoryType, WasmModuleResources, WasmTableType}; + +use crate::readers::FunctionBody; + +type ValidatorResult<'a, T> = result::Result<T, ParserState<'a>>; + +struct InitExpressionState { + ty: Type, + global_count: usize, + function_count: usize, + validated: bool, +} + +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] +enum SectionOrderState { + Initial, + Type, + Import, + Function, + Table, + Memory, + Global, + Export, + Start, + Element, + DataCount, + Code, + Data, +} + +impl SectionOrderState { + pub fn from_section_code(code: &SectionCode) -> Option<SectionOrderState> { + match *code { + SectionCode::Type => Some(SectionOrderState::Type), + SectionCode::Import => Some(SectionOrderState::Import), + SectionCode::Function => Some(SectionOrderState::Function), + SectionCode::Table => Some(SectionOrderState::Table), + SectionCode::Memory => Some(SectionOrderState::Memory), + SectionCode::Global => Some(SectionOrderState::Global), + SectionCode::Export => Some(SectionOrderState::Export), + SectionCode::Start => Some(SectionOrderState::Start), + SectionCode::Element => Some(SectionOrderState::Element), + SectionCode::Code => Some(SectionOrderState::Code), + SectionCode::Data => Some(SectionOrderState::Data), + SectionCode::DataCount => Some(SectionOrderState::DataCount), + _ => None, + } + } +} + +#[derive(Copy, Clone)] +pub struct ValidatingParserConfig { + pub operator_config: OperatorValidatorConfig, +} + +const DEFAULT_VALIDATING_PARSER_CONFIG: ValidatingParserConfig = ValidatingParserConfig { + operator_config: DEFAULT_OPERATOR_VALIDATOR_CONFIG, +}; + +struct ValidatingParserResources { + types: Vec<FuncType>, + tables: Vec<TableType>, + memories: Vec<MemoryType>, + globals: Vec<GlobalType>, + element_count: u32, + data_count: Option<u32>, + func_type_indices: Vec<u32>, +} + +impl<'a> WasmModuleResources for ValidatingParserResources { + type FuncType = crate::FuncType; + type TableType = crate::TableType; + type MemoryType = crate::MemoryType; + type GlobalType = crate::GlobalType; + + fn type_at(&self, at: u32) -> Option<&Self::FuncType> { + self.types.get(at as usize) + } + + fn table_at(&self, at: u32) -> Option<&Self::TableType> { + self.tables.get(at as usize) + } + + fn memory_at(&self, at: u32) -> Option<&Self::MemoryType> { + self.memories.get(at as usize) + } + + fn global_at(&self, at: u32) -> Option<&Self::GlobalType> { + self.globals.get(at as usize) + } + + fn func_type_id_at(&self, at: u32) -> Option<u32> { + self.func_type_indices.get(at as usize).copied() + } + + fn element_count(&self) -> u32 { + self.element_count + } + + fn data_count(&self) -> u32 { + self.data_count.unwrap_or(0) + } +} + +pub struct ValidatingParser<'a> { + parser: Parser<'a>, + validation_error: Option<ParserState<'a>>, + read_position: Option<usize>, + section_order_state: SectionOrderState, + resources: ValidatingParserResources, + current_func_index: u32, + func_imports_count: u32, + init_expression_state: Option<InitExpressionState>, + data_found: u32, + exported_names: HashSet<String>, + current_operator_validator: Option<OperatorValidator>, + config: ValidatingParserConfig, +} + +impl<'a> ValidatingParser<'a> { + pub fn new(bytes: &[u8], config: Option<ValidatingParserConfig>) -> ValidatingParser { + ValidatingParser { + parser: Parser::new(bytes), + validation_error: None, + read_position: None, + section_order_state: SectionOrderState::Initial, + resources: ValidatingParserResources { + types: Vec::new(), + tables: Vec::new(), + memories: Vec::new(), + globals: Vec::new(), + element_count: 0, + data_count: None, + func_type_indices: Vec::new(), + }, + current_func_index: 0, + func_imports_count: 0, + current_operator_validator: None, + init_expression_state: None, + data_found: 0, + exported_names: HashSet::new(), + config: config.unwrap_or(DEFAULT_VALIDATING_PARSER_CONFIG), + } + } + + pub fn get_resources( + &self, + ) -> &dyn WasmModuleResources< + FuncType = crate::FuncType, + TableType = crate::TableType, + MemoryType = crate::MemoryType, + GlobalType = crate::GlobalType, + > { + &self.resources + } + + fn set_validation_error(&mut self, message: &'static str) { + self.validation_error = Some(ParserState::Error(BinaryReaderError { + message, + offset: self.read_position.unwrap(), + })) + } + + fn create_error<T>(&self, message: &'static str) -> ValidatorResult<'a, T> { + Err(ParserState::Error(BinaryReaderError { + message, + offset: self.read_position.unwrap(), + })) + } + + fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> { + match ty { + Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()), + Type::NullRef | Type::AnyFunc | Type::AnyRef => { + if !self.config.operator_config.enable_reference_types { + return self.create_error("reference types support is not enabled"); + } + Ok(()) + } + Type::V128 => { + if !self.config.operator_config.enable_simd { + return self.create_error("SIMD support is not enabled"); + } + Ok(()) + } + _ => self.create_error("invalid value type"), + } + } + + fn check_value_types(&self, types: &[Type]) -> ValidatorResult<'a, ()> { + for ty in types { + self.check_value_type(*ty)?; + } + Ok(()) + } + + fn check_limits(&self, limits: &ResizableLimits) -> ValidatorResult<'a, ()> { + if limits.maximum.is_some() && limits.initial > limits.maximum.unwrap() { + return self.create_error("maximum limits less than initial"); + } + Ok(()) + } + + fn check_func_type(&self, func_type: &FuncType) -> ValidatorResult<'a, ()> { + if let Type::Func = func_type.form { + self.check_value_types(&*func_type.params)?; + self.check_value_types(&*func_type.returns)?; + if !self.config.operator_config.enable_multi_value && func_type.returns.len() > 1 { + self.create_error("func type returns multiple values") + } else { + Ok(()) + } + } else { + self.create_error("type signature is not a func") + } + } + + fn check_table_type(&self, table_type: &TableType) -> ValidatorResult<'a, ()> { + match table_type.element_type { + Type::AnyFunc => {} + _ => { + if !self.config.operator_config.enable_reference_types { + return self.create_error("element is not anyfunc"); + } + } + } + self.check_limits(&table_type.limits) + } + + fn check_memory_type(&self, memory_type: &MemoryType) -> ValidatorResult<'a, ()> { + self.check_limits(&memory_type.limits)?; + let initial = memory_type.limits.initial; + if initial as usize > MAX_WASM_MEMORY_PAGES { + return self.create_error("memory initial value exceeds limit"); + } + let maximum = memory_type.limits.maximum; + if maximum.is_some() && maximum.unwrap() as usize > MAX_WASM_MEMORY_PAGES { + return self.create_error("memory maximum value exceeds limit"); + } + Ok(()) + } + + fn check_global_type(&self, global_type: GlobalType) -> ValidatorResult<'a, ()> { + self.check_value_type(global_type.content_type) + } + + fn check_import_entry(&self, import_type: &ImportSectionEntryType) -> ValidatorResult<'a, ()> { + match *import_type { + ImportSectionEntryType::Function(type_index) => { + if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS { + return self.create_error("functions count out of bounds"); + } + if type_index as usize >= self.resources.types.len() { + return self.create_error("type index out of bounds"); + } + Ok(()) + } + ImportSectionEntryType::Table(ref table_type) => { + if !self.config.operator_config.enable_reference_types + && self.resources.tables.len() >= MAX_WASM_TABLES + { + return self.create_error("tables count must be at most 1"); + } + self.check_table_type(table_type) + } + ImportSectionEntryType::Memory(ref memory_type) => { + if self.resources.memories.len() >= MAX_WASM_MEMORIES { + return self.create_error("memory count must be at most 1"); + } + self.check_memory_type(memory_type) + } + ImportSectionEntryType::Global(global_type) => { + if self.resources.globals.len() >= MAX_WASM_GLOBALS { + return self.create_error("functions count out of bounds"); + } + self.check_global_type(global_type) + } + } + } + + fn check_init_expression_operator(&self, operator: &Operator) -> ValidatorResult<'a, ()> { + let state = self.init_expression_state.as_ref().unwrap(); + if state.validated { + return self.create_error("only one init_expr operator is expected"); + } + let ty = match *operator { + Operator::I32Const { .. } => Type::I32, + Operator::I64Const { .. } => Type::I64, + Operator::F32Const { .. } => Type::F32, + Operator::F64Const { .. } => Type::F64, + Operator::RefNull => { + if !self.config.operator_config.enable_reference_types { + return self.create_error("reference types support is not enabled"); + } + Type::NullRef + } + Operator::V128Const { .. } => { + if !self.config.operator_config.enable_simd { + return self.create_error("SIMD support is not enabled"); + } + Type::V128 + } + Operator::GlobalGet { global_index } => { + if global_index as usize >= state.global_count { + return self.create_error("init_expr global index out of bounds"); + } + self.resources.globals[global_index as usize].content_type + } + Operator::RefFunc { function_index } => { + if function_index as usize >= state.function_count { + return self.create_error("init_expr function index out of bounds"); + } + Type::AnyFunc + } + _ => return self.create_error("invalid init_expr operator"), + }; + if !is_subtype_supertype(ty, state.ty) { + return self.create_error("invalid init_expr type"); + } + Ok(()) + } + + fn check_export_entry( + &self, + field: &str, + kind: ExternalKind, + index: u32, + ) -> ValidatorResult<'a, ()> { + if self.exported_names.contains(field) { + return self.create_error("non-unique export name"); + } + match kind { + ExternalKind::Function => { + if index as usize >= self.resources.func_type_indices.len() { + return self.create_error("exported function index out of bounds"); + } + } + ExternalKind::Table => { + if index as usize >= self.resources.tables.len() { + return self.create_error("exported table index out of bounds"); + } + } + ExternalKind::Memory => { + if index as usize >= self.resources.memories.len() { + return self.create_error("exported memory index out of bounds"); + } + } + ExternalKind::Global => { + if index as usize >= self.resources.globals.len() { + return self.create_error("exported global index out of bounds"); + } + } + }; + Ok(()) + } + + fn check_start(&self, func_index: u32) -> ValidatorResult<'a, ()> { + if func_index as usize >= self.resources.func_type_indices.len() { + return self.create_error("start function index out of bounds"); + } + let type_index = self.resources.func_type_indices[func_index as usize]; + let ty = &self.resources.types[type_index as usize]; + if !ty.params.is_empty() || !ty.returns.is_empty() { + return self.create_error("invlid start function type"); + } + Ok(()) + } + + fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> { + let order_state = SectionOrderState::from_section_code(code); + Ok(match self.section_order_state { + SectionOrderState::Initial => match order_state { + Some(section) => section, + _ => SectionOrderState::Initial, + }, + previous => { + if let Some(order_state_unwraped) = order_state { + if previous >= order_state_unwraped { + return self.create_error("section out of order"); + } + order_state_unwraped + } else { + previous + } + } + }) + } + + fn process_state(&mut self) { + match *self.parser.last_state() { + ParserState::BeginWasm { version } => { + if version != 1 { + self.set_validation_error("bad wasm file version"); + } + } + ParserState::BeginSection { ref code, .. } => { + let check = self.process_begin_section(code); + if check.is_err() { + self.validation_error = check.err(); + } else { + self.section_order_state = check.ok().unwrap(); + } + } + ParserState::TypeSectionEntry(ref func_type) => { + let check = self.check_func_type(func_type); + if check.is_err() { + self.validation_error = check.err(); + } else if self.resources.types.len() > MAX_WASM_TYPES { + self.set_validation_error("types count is out of bounds"); + } else { + self.resources.types.push(func_type.clone()); + } + } + ParserState::ImportSectionEntry { ref ty, .. } => { + let check = self.check_import_entry(ty); + if check.is_err() { + self.validation_error = check.err(); + } else { + match *ty { + ImportSectionEntryType::Function(type_index) => { + self.func_imports_count += 1; + self.resources.func_type_indices.push(type_index); + } + ImportSectionEntryType::Table(ref table_type) => { + self.resources.tables.push(table_type.clone()); + } + ImportSectionEntryType::Memory(ref memory_type) => { + self.resources.memories.push(memory_type.clone()); + } + ImportSectionEntryType::Global(ref global_type) => { + self.resources.globals.push(global_type.clone()); + } + } + } + } + ParserState::FunctionSectionEntry(type_index) => { + if type_index as usize >= self.resources.types.len() { + self.set_validation_error("func type index out of bounds"); + } else if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS { + self.set_validation_error("functions count out of bounds"); + } else { + self.resources.func_type_indices.push(type_index); + } + } + ParserState::TableSectionEntry(ref table_type) => { + if !self.config.operator_config.enable_reference_types + && self.resources.tables.len() >= MAX_WASM_TABLES + { + self.set_validation_error("tables count must be at most 1"); + } else { + self.validation_error = self.check_table_type(table_type).err(); + self.resources.tables.push(table_type.clone()); + } + } + ParserState::MemorySectionEntry(ref memory_type) => { + if self.resources.memories.len() >= MAX_WASM_MEMORIES { + self.set_validation_error("memories count must be at most 1"); + } else { + self.validation_error = self.check_memory_type(memory_type).err(); + self.resources.memories.push(memory_type.clone()); + } + } + ParserState::BeginGlobalSectionEntry(global_type) => { + if self.resources.globals.len() >= MAX_WASM_GLOBALS { + self.set_validation_error("globals count out of bounds"); + } else { + self.validation_error = self.check_global_type(global_type).err(); + self.init_expression_state = Some(InitExpressionState { + ty: global_type.content_type, + global_count: self.resources.globals.len(), + function_count: self.resources.func_type_indices.len(), + validated: false, + }); + self.resources.globals.push(global_type); + } + } + ParserState::BeginInitExpressionBody => { + assert!(self.init_expression_state.is_some()); + } + ParserState::InitExpressionOperator(ref operator) => { + self.validation_error = self.check_init_expression_operator(operator).err(); + self.init_expression_state.as_mut().unwrap().validated = true; + } + ParserState::EndInitExpressionBody => { + if !self.init_expression_state.as_ref().unwrap().validated { + self.set_validation_error("init_expr is empty"); + } + self.init_expression_state = None; + } + ParserState::ExportSectionEntry { field, kind, index } => { + self.validation_error = self.check_export_entry(field, kind, index).err(); + self.exported_names.insert(String::from(field)); + } + ParserState::StartSectionEntry(func_index) => { + self.validation_error = self.check_start(func_index).err(); + } + ParserState::DataCountSectionEntry(count) => { + self.resources.data_count = Some(count); + } + ParserState::BeginElementSectionEntry { table, ty } => { + self.resources.element_count += 1; + if let ElemSectionEntryTable::Active(table_index) = table { + let table = match self.resources.tables.get(table_index as usize) { + Some(t) => t, + None => { + self.set_validation_error("element section table index out of bounds"); + return; + } + }; + if !is_subtype_supertype(ty, table.element_type) { + self.set_validation_error("element_type != table type"); + return; + } + if !self.config.operator_config.enable_reference_types && ty != Type::AnyFunc { + self.set_validation_error("element_type != anyfunc is not supported yet"); + return; + } + self.init_expression_state = Some(InitExpressionState { + ty: Type::I32, + global_count: self.resources.globals.len(), + function_count: self.resources.func_type_indices.len(), + validated: false, + }); + } + } + ParserState::ElementSectionEntryBody(ref indices) => { + for item in &**indices { + if let ElementItem::Func(func_index) = item { + if *func_index as usize >= self.resources.func_type_indices.len() { + self.set_validation_error("element func index out of bounds"); + break; + } + } + } + } + ParserState::BeginFunctionBody { .. } => { + let index = (self.current_func_index + self.func_imports_count) as usize; + if index as usize >= self.resources.func_type_indices.len() { + self.set_validation_error("func type is not defined"); + } + } + ParserState::FunctionBodyLocals { ref locals } => { + let index = (self.current_func_index + self.func_imports_count) as usize; + let func_type = + &self.resources.types[self.resources.func_type_indices[index] as usize]; + let operator_config = self.config.operator_config; + self.current_operator_validator = + Some(OperatorValidator::new(func_type, locals, operator_config)); + } + ParserState::CodeOperator(ref operator) => { + let check = self + .current_operator_validator + .as_mut() + .unwrap() + .process_operator(operator, &self.resources); + + if let Err(err) = check { + self.set_validation_error(err); + } + } + ParserState::EndFunctionBody => { + let check = self + .current_operator_validator + .as_ref() + .unwrap() + .process_end_function(); + if let Err(err) = check { + self.set_validation_error(err); + } + self.current_func_index += 1; + self.current_operator_validator = None; + } + ParserState::BeginDataSectionEntryBody(_) => { + self.data_found += 1; + } + ParserState::BeginActiveDataSectionEntry(memory_index) => { + if memory_index as usize >= self.resources.memories.len() { + self.set_validation_error("data section memory index out of bounds"); + } else { + self.init_expression_state = Some(InitExpressionState { + ty: Type::I32, + global_count: self.resources.globals.len(), + function_count: self.resources.func_type_indices.len(), + validated: false, + }); + } + } + ParserState::EndWasm => { + if self.resources.func_type_indices.len() + != self.current_func_index as usize + self.func_imports_count as usize + { + self.set_validation_error( + "function and code section have inconsistent lengths", + ); + } + if let Some(data_count) = self.resources.data_count { + if data_count != self.data_found { + self.set_validation_error("data count section and passive data mismatch"); + } + } + } + _ => (), + }; + } + + pub fn create_validating_operator_parser<'b>(&mut self) -> ValidatingOperatorParser<'b> + where + 'a: 'b, + { + let func_body_offset = match *self.last_state() { + ParserState::BeginFunctionBody { .. } => self.parser.current_position(), + _ => panic!("Invalid reader state"), + }; + self.read(); + let operator_validator = match *self.last_state() { + ParserState::FunctionBodyLocals { ref locals } => { + let index = (self.current_func_index + self.func_imports_count) as usize; + let func_type = + &self.resources.types[self.resources.func_type_indices[index] as usize]; + let operator_config = self.config.operator_config; + OperatorValidator::new(func_type, locals, operator_config) + } + _ => panic!("Invalid reader state"), + }; + let reader = self.create_binary_reader(); + ValidatingOperatorParser::new(operator_validator, reader, func_body_offset) + } +} + +impl<'a> WasmDecoder<'a> for ValidatingParser<'a> { + fn read(&mut self) -> &ParserState<'a> { + if self.validation_error.is_some() { + panic!("Parser in error state: validation"); + } + self.read_position = Some(self.parser.current_position()); + self.parser.read(); + self.process_state(); + self.last_state() + } + + fn push_input(&mut self, input: ParserInput) { + match input { + ParserInput::SkipSection => panic!("Not supported"), + ParserInput::ReadSectionRawData => panic!("Not supported"), + ParserInput::SkipFunctionBody => { + self.current_func_index += 1; + self.parser.push_input(input); + } + _ => self.parser.push_input(input), + } + } + + fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> { + self.push_input(input); + self.read() + } + + fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b> + where + 'a: 'b, + { + if let ParserState::BeginSection { .. } = *self.parser.last_state() { + panic!("Not supported"); + } + self.parser.create_binary_reader() + } + + fn last_state(&self) -> &ParserState<'a> { + if self.validation_error.is_some() { + self.validation_error.as_ref().unwrap() + } else { + self.parser.last_state() + } + } +} + +pub struct ValidatingOperatorParser<'b> { + operator_validator: OperatorValidator, + reader: BinaryReader<'b>, + func_body_offset: usize, + end_function: bool, +} + +impl<'b> ValidatingOperatorParser<'b> { + pub(crate) fn new<'c>( + operator_validator: OperatorValidator, + reader: BinaryReader<'c>, + func_body_offset: usize, + ) -> ValidatingOperatorParser<'c> + where + 'b: 'c, + { + ValidatingOperatorParser { + operator_validator, + reader, + func_body_offset, + end_function: false, + } + } + + pub fn eof(&self) -> bool { + self.end_function + } + + pub fn current_position(&self) -> usize { + self.reader.current_position() + } + + pub fn is_dead_code(&self) -> bool { + self.operator_validator.is_dead_code() + } + + /// Creates a BinaryReader when current state is ParserState::BeginSection + /// or ParserState::BeginFunctionBody. + /// + /// # Examples + /// ``` + /// # let data = &[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x84, + /// # 0x80, 0x80, 0x80, 0x0, 0x1, 0x60, 0x0, 0x0, 0x3, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x2, 0x0, 0x0, 0x6, 0x81, 0x80, + /// # 0x80, 0x80, 0x0, 0x0, 0xa, 0x91, 0x80, 0x80, 0x80, 0x0, + /// # 0x2, 0x83, 0x80, 0x80, 0x80, 0x0, 0x0, 0x1, 0xb, 0x83, + /// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb]; + /// use wasmparser::{WasmDecoder, ParserState, ValidatingParser}; + /// let mut parser = ValidatingParser::new(data, None); + /// let mut i = 0; + /// loop { + /// { + /// match *parser.read() { + /// ParserState::Error(_) | + /// ParserState::EndWasm => break, + /// ParserState::BeginFunctionBody {..} => (), + /// _ => continue + /// } + /// } + /// let mut reader = parser.create_validating_operator_parser(); + /// println!("Function {}", i); + /// i += 1; + /// while !reader.eof() { + /// let read = reader.next(parser.get_resources()); + /// if let Ok(ref op) = read { + /// println!(" {:?}", op); + /// } else { + /// panic!(" Bad wasm code {:?}", read.err()); + /// } + /// } + /// } + /// ``` + pub fn next<'c, F: WasmFuncType, T: WasmTableType, M: WasmMemoryType, G: WasmGlobalType>( + &mut self, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + ) -> Result<Operator<'c>> + where + 'b: 'c, + { + let op = self.reader.read_operator()?; + match self.operator_validator.process_operator(&op, resources) { + Err(err) => { + return Err(BinaryReaderError { + message: err, + offset: self.func_body_offset + self.reader.current_position(), + }); + } + Ok(FunctionEnd::Yes) => { + self.end_function = true; + if !self.reader.eof() { + return Err(BinaryReaderError { + message: "unexpected end of function", + offset: self.func_body_offset + self.reader.current_position(), + }); + } + } + _ => (), + }; + Ok(op) + } +} + +/// Test whether the given buffer contains a valid WebAssembly function. +/// The resources parameter contains all needed data to validate the operators. +pub fn validate_function_body< + F: WasmFuncType, + T: WasmTableType, + M: WasmMemoryType, + G: WasmGlobalType, +>( + bytes: &[u8], + offset: usize, + func_index: u32, + resources: &dyn WasmModuleResources< + FuncType = F, + TableType = T, + MemoryType = M, + GlobalType = G, + >, + operator_config: Option<OperatorValidatorConfig>, +) -> Result<()> { + let operator_config = operator_config.unwrap_or(DEFAULT_OPERATOR_VALIDATOR_CONFIG); + let function_body = FunctionBody::new(offset, bytes); + let mut locals_reader = function_body.get_locals_reader()?; + let local_count = locals_reader.get_count() as usize; + if local_count > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals exceed maximum", + offset: locals_reader.original_position(), + }); + } + let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count); + let mut locals_total: usize = 0; + for _ in 0..local_count { + let (count, ty) = locals_reader.read()?; + locals_total = + locals_total + .checked_add(count as usize) + .ok_or_else(|| BinaryReaderError { + message: "locals overflow", + offset: locals_reader.original_position(), + })?; + if locals_total > MAX_WASM_FUNCTION_LOCALS { + return Err(BinaryReaderError { + message: "locals exceed maximum", + offset: locals_reader.original_position(), + }); + } + locals.push((count, ty)); + } + let operators_reader = function_body.get_operators_reader()?; + let func_type_index = resources + .func_type_id_at(func_index) + // Note: This was an out-of-bounds access before the change to return `Option` + // so I assumed it is considered a bug to access a non-existing function + // id here and went with panicking instead of returning a proper error. + .expect("the function index of the validated function itself is out of bounds"); + let func_type = resources + .type_at(func_type_index) + // Note: This was an out-of-bounds access before the change to return `Option` + // so I assumed it is considered a bug to access a non-existing function + // id here and went with panicking instead of returning a proper error. + .expect("the function type indexof the validated function itself is out of bounds"); + let mut operator_validator = OperatorValidator::new(func_type, &locals, operator_config); + let mut eof_found = false; + let mut last_op = 0; + for item in operators_reader.into_iter_with_offsets() { + let (ref op, offset) = item?; + match operator_validator + .process_operator(op, resources) + .map_err(|message| BinaryReaderError { message, offset })? + { + FunctionEnd::Yes => { + eof_found = true; + } + FunctionEnd::No => { + last_op = offset; + } + } + } + if !eof_found { + return Err(BinaryReaderError { + message: "end of function not found", + offset: last_op, + }); + } + Ok(()) +} + +/// Test whether the given buffer contains a valid WebAssembly module, +/// analogous to WebAssembly.validate in the JS API. +pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> Result<()> { + let mut parser = ValidatingParser::new(bytes, config); + let mut parser_input = None; + let mut func_ranges = Vec::new(); + loop { + let next_input = parser_input.take().unwrap_or(ParserInput::Default); + let state = parser.read_with_input(next_input); + match *state { + ParserState::EndWasm => break, + ParserState::Error(e) => return Err(e), + ParserState::BeginFunctionBody { range } => { + parser_input = Some(ParserInput::SkipFunctionBody); + func_ranges.push(range); + } + _ => (), + } + } + let operator_config = config.map(|c| c.operator_config); + for (i, range) in func_ranges.into_iter().enumerate() { + let function_body = range.slice(bytes); + let function_index = i as u32 + parser.func_imports_count; + validate_function_body( + function_body, + range.start, + function_index, + &parser.resources, + operator_config, + )?; + } + Ok(()) +} + +#[test] +fn test_validate() { + assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0], None).is_ok()); + assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0], None).is_err()); +} diff --git a/third_party/rust/wasmparser-0.48.2/test-all.sh b/third_party/rust/wasmparser-0.48.2/test-all.sh new file mode 100755 index 0000000000..cf0b4c137c --- /dev/null +++ b/third_party/rust/wasmparser-0.48.2/test-all.sh @@ -0,0 +1,57 @@ +#!/bin/bash +set -euo pipefail + +# This is the top-level test script: +# +# - Check code formatting. +# - Make a debug build. +# - Make a release build. +# - Run unit tests for all Rust crates. +# - Build API documentation. +# +# All tests run by this script should be passing at all times. + +# Repository top-level directory. +topdir=$(dirname "$0") +cd "$topdir" + +function banner { + echo "====== $* ======" +} + +# Run rustfmt if we have it. +banner "Rust formatting" +if type rustfmt > /dev/null; then + if ! "$topdir/format-all.sh" --check ; then + echo "Formatting diffs detected! Run \"cargo fmt --all\" to correct." + exit 1 + fi +else + echo "rustfmt not available; formatting not checked!" + echo + echo "If you are using rustup, rustfmt can be installed via" + echo "\"rustup component add --toolchain=stable rustfmt-preview\", or see" + echo "https://github.com/rust-lang-nursery/rustfmt for more information." +fi + +# Make sure the code builds in release mode. +banner "Rust release build" +cargo build --release + +# Make sure the code builds in debug mode. +banner "Rust debug build" +cargo build + +# Run the tests. We run these in debug mode so that assertions are enabled. +banner "Rust unit tests" +cargo test --all + +# Run only tests with "deterministic" feature. +banner "Rust deterministic unit tests" +cargo test --features "deterministic" + +# Make sure the documentation builds. +banner "Rust documentation: $topdir/target/doc/wasmparser/index.html" +cargo doc + +banner "OK" |