├── .gitmodules ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── section-2-background-and-related-work ├── Figure-1 │ ├── README.md │ ├── data_rust_history.tab │ ├── plot_Figure_1.sh │ └── plot_rust_histories.pl └── Figure-2 │ ├── README.md │ ├── data_bugs_date.tab │ ├── plot_Figure_2.sh │ ├── plot_bugs_date.pl │ └── raw_data │ ├── data_ethereum_bugs_date.tab │ ├── data_libs_bugs_date.tab │ ├── data_redox_bugs_date.tab │ ├── data_servo_bugs_date.tab │ ├── data_tikv_bugs_date.tab │ └── data_tock_bugs_date.tab ├── section-4-unsafe-usages ├── section-4-1-reasons-of-usage │ ├── README.md │ ├── array-access │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── array-offset │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── mem-copy │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── run_all.sh └── unsafe-statisitcs │ ├── README.md │ └── src_parser │ ├── comment_remover │ ├── README.md │ ├── comment_remover │ ├── comment_remover.cpp │ └── tests │ │ ├── comment.rs │ │ └── no-comment.rs │ ├── run_all.sh │ ├── sum.py │ ├── tests │ └── unsafe_block.rs │ ├── unsafe_block_extractor │ ├── tests │ │ └── unsafe_block.rs │ └── unsafe_block_extractor.py │ └── unsafe_fn_extractor │ ├── tests │ └── unsafe_fn.rs │ └── unsafe_fn_extractor.py ├── section-5-memory-safety-issues ├── memory-bugs │ ├── CVE-RUSTSEC │ │ ├── CVE-2018-1000657 │ │ ├── CVE-2018-1000810 │ │ ├── CVE-2019-15553_RUSTSEC-2019-0011 │ │ ├── CVE-2019-15554_RUSTSEC-2019-0012 │ │ ├── CVE-2019-16138_RUSTSEC-2019-0014 │ │ ├── CVE-2019-16140_RUSTSEC-2019-0016 │ │ ├── CVE-2019-16144_RUSTSEC-2019-0020 │ │ ├── CVE-2019-16880_RUSTSEC-2019-0021 │ │ ├── CVE-2019-16881_RUSTSEC-2019-0022 │ │ ├── CVE-2019-16882_RUSTSEC-2019-0023 │ │ ├── RUSTSEC-2017-0004 │ │ ├── RUSTSEC-2018-0003 │ │ ├── RUSTSEC-2018-0004 │ │ ├── RUSTSEC-2018-0008 │ │ ├── RUSTSEC-2018-0009 │ │ ├── RUSTSEC-2018-0010 │ │ ├── RUSTSEC-2018-0011 │ │ ├── RUSTSEC-2018-0013 │ │ ├── RUSTSEC-2019-0008 │ │ ├── RUSTSEC-2019-0009 │ │ └── RUSTSEC-2019-0010 │ ├── crossbeam │ │ ├── 0ad4443d063351e86bcf8dec5c0ccfbdaaa442a7 │ │ ├── 17bce41cc3f5e3f8c657700705b6a75bdac91bc8 │ │ ├── 392e1425cec0fd57fdaa7b47ced3cf013b45bea1 │ │ ├── 424807f92ee938793094b5f3d440f13097c49597 │ │ ├── b6868f7fd1799ffac6257e05389803fde89102b5 │ │ └── c2010348b9b2be419065384189d3051e6e60416c │ ├── parity-ethereum │ │ ├── 0cd1de769b8ffe5f517f07b0d74ebdca2238ec79 │ │ └── 46fe32bc2d8badfac97e2057a38d07dc58c2a2ab │ ├── rand │ │ └── f35d51a2c82e684bd25f4c34e9a85e946af54933 │ ├── redox │ │ ├── 0b15e8bdfcda359501763d77eb0eb76d32f30a3b │ │ ├── 1ebd8a3d723291e7f120b3c95b2e5141c9ef93b3 │ │ ├── 442a7bbedc37c589be490cfe21a74be5ea9de65b │ │ ├── 49259d3f018284370c883ae54e2bbe7783d040ea │ │ ├── 52acce0d346256f1ad3d0562a9a3a85531a9da75 │ │ ├── 629c20f097ed158233d65ca5ffc62e1c887709e6 │ │ ├── 6bd5bd5614effaa4016394d24ad2881aab8d4e51 │ │ ├── 921303f83451dca1954447dcdf50f6aff81e812b │ │ ├── 925d9f6bbfeb8c764d0ea32911bb1edbf2716953 │ │ ├── bfa132473f4fc286cbd1ec3d4a052a3699e34bd6 │ │ ├── dcb49be48133cf811dcd870e8af5f7ffaffc2ab0 │ │ ├── de429a8df69b5b588ba7527f20d21548c797d14a │ │ ├── f661d5d1c099e78ff26f0fb4754d40302bd00e19 │ │ ├── redox-kernel-issues#81 │ │ ├── redox-pull#680 │ │ ├── redox-pull#691 │ │ ├── redox-ralloc-issues#20 │ │ ├── redox-ralloc-issues#22 │ │ ├── redox-ralloc-pull#61 │ │ └── redox-relibc-pull#188 │ ├── servo │ │ ├── 1292fa29658e24d96cc146ebc4fc05a26de6b88e │ │ ├── 275d4561187bf2c4cc940c4a7ae3b6215e06e39b │ │ ├── 2fb6cc6f4d2e6ea662c781b65bcafff3221461e1 │ │ ├── 4d76e7570ed410c5630699f55ac3e8de858cb052 │ │ ├── 4eb78753a6004ef84a41a20ce377bdbc00fccc5f │ │ ├── 593e89086fd1bd7a1cb9c496ad5837a3c7ba594e │ │ ├── 6c6d070dab43d96ba5724d3e5007025c56ff290e │ │ ├── 79ef14e84427ae2c871360da0666c20c8473ed3a │ │ ├── 865e81749a6530a02f608dddae154b7b0bef827e │ │ ├── 9b92d0bc3a590697b2f17ef16b2dfeee057a57f2 │ │ ├── afafb0b71cc9f8721ea31b027570254aa7f6b012 │ │ ├── ea8f115b8cb30513d077e42884d062d6d10ccee4 │ │ ├── ecab3cd7961d122f122f4dd97d251ead00cea924 │ │ └── f298089f0216f50b64d1197b36075f606566e609 │ ├── tikv │ │ └── a928d39a5b85055186bb81bbba20dcad1117b1ce │ └── tock │ │ ├── 43760ae9137db07ea2a79cd6b551bda53e6fd7d6 │ │ ├── 5089adc1c8cfef7de31ef0d036e16e64c8c140bd │ │ ├── 87ef34b31890ee8c3d405b45924492d76376f3fa │ │ ├── bb5c6f6410a16a404778d12d21d4e0f78ef50943 │ │ └── ff90e26500212e92fa3693205218a9627657a116 └── reproduced-bugs │ ├── README.md │ ├── cve │ ├── CVE-2018-1000657 │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── CVE-2018-1000810 │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── RUSTSEC-2017-0004 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── RUSTSEC-2018-0003 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── RUSTSEC-2018-0008 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── RUSTSEC-2018-0009 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── RUSTSEC-2018-0010 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs │ ├── servo │ ├── 1 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── 4 │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs │ └── tock │ └── 1 │ ├── .gitignore │ ├── Cargo.toml │ └── src │ └── main.rs ├── section-6-thread-safety-issues ├── reproduced_concurrency_bugs │ ├── README.md │ ├── blocking-bugs │ │ ├── deadlock-test │ │ │ ├── README.md │ │ │ ├── deadlock1.rs │ │ │ ├── deadlock2.rs │ │ │ ├── non-deadlock1.rs │ │ │ ├── non-deadlock2.rs │ │ │ └── non-deadlock3.rs │ │ ├── ethereum-blocking-3 │ │ │ ├── Cargo.toml │ │ │ ├── README.md │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── ethereum-blocking-4 │ │ │ ├── Cargo.toml │ │ │ ├── README.md │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── lazy-static-blocking-1 │ │ │ ├── Cargo.toml │ │ │ ├── README.md │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── rayon-blocking-1 │ │ │ ├── Cargo.toml │ │ │ ├── README.md │ │ │ ├── install.sh │ │ │ ├── rayon │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── Cargo.toml │ │ │ │ ├── LICENSE-APACHE │ │ │ │ ├── LICENSE-MIT │ │ │ │ ├── README.md │ │ │ │ ├── RELEASES.md │ │ │ │ ├── appveyor.yml │ │ │ │ ├── ci │ │ │ │ │ ├── alt-core │ │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ │ ├── build.rs │ │ │ │ │ │ └── src │ │ │ │ │ │ │ └── lib.rs │ │ │ │ │ ├── highlander.sh │ │ │ │ │ └── highlander │ │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ │ └── src │ │ │ │ │ │ └── main.rs │ │ │ │ ├── examples │ │ │ │ │ ├── README.md │ │ │ │ │ └── cpu_monitor.rs │ │ │ │ ├── rayon-core │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── LICENSE-APACHE │ │ │ │ │ ├── LICENSE-MIT │ │ │ │ │ ├── build.rs │ │ │ │ │ └── src │ │ │ │ │ │ ├── internal │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ ├── task.rs │ │ │ │ │ │ └── worker.rs │ │ │ │ │ │ ├── job.rs │ │ │ │ │ │ ├── join │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ └── test.rs │ │ │ │ │ │ ├── latch.rs │ │ │ │ │ │ ├── lib.rs │ │ │ │ │ │ ├── log.rs │ │ │ │ │ │ ├── registry.rs │ │ │ │ │ │ ├── scope │ │ │ │ │ │ ├── internal.rs │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ └── test.rs │ │ │ │ │ │ ├── sleep │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── spawn │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ └── test.rs │ │ │ │ │ │ ├── test.rs │ │ │ │ │ │ ├── thread_pool │ │ │ │ │ │ ├── internal.rs │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ └── test.rs │ │ │ │ │ │ ├── unwind.rs │ │ │ │ │ │ └── util.rs │ │ │ │ ├── rayon-demo │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── data │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ └── tsp │ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ │ ├── dj10.tsp │ │ │ │ │ │ │ ├── dj15.tsp │ │ │ │ │ │ │ └── dj38.tsp │ │ │ │ │ └── src │ │ │ │ │ │ ├── factorial │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── fibonacci │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── find │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── join_microbench.rs │ │ │ │ │ │ ├── life │ │ │ │ │ │ ├── bench.rs │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── main.rs │ │ │ │ │ │ ├── map_collect.rs │ │ │ │ │ │ ├── matmul │ │ │ │ │ │ ├── bench.rs │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── mergesort │ │ │ │ │ │ ├── bench.rs │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── nbody │ │ │ │ │ │ ├── bench.rs │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ ├── nbody.rs │ │ │ │ │ │ └── visualize.rs │ │ │ │ │ │ ├── pythagoras │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── quicksort │ │ │ │ │ │ ├── bench.rs │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── sieve │ │ │ │ │ │ ├── bench.rs │ │ │ │ │ │ └── mod.rs │ │ │ │ │ │ ├── sort.rs │ │ │ │ │ │ ├── str_split.rs │ │ │ │ │ │ ├── tsp │ │ │ │ │ │ ├── bench.rs │ │ │ │ │ │ ├── graph.rs │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ ├── parser.rs │ │ │ │ │ │ ├── solver.rs │ │ │ │ │ │ ├── step.rs │ │ │ │ │ │ ├── tour.rs │ │ │ │ │ │ └── weight.rs │ │ │ │ │ │ └── vec_collect.rs │ │ │ │ ├── rayon-futures │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── LICENSE-APACHE │ │ │ │ │ ├── LICENSE-MIT │ │ │ │ │ ├── README.md │ │ │ │ │ ├── src │ │ │ │ │ │ ├── lib.rs │ │ │ │ │ │ └── test.rs │ │ │ │ │ └── tests │ │ │ │ │ │ └── compile-fail │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ └── future_escape.rs │ │ │ │ ├── scripts │ │ │ │ │ └── analyze.sh │ │ │ │ ├── src │ │ │ │ │ ├── collections │ │ │ │ │ │ ├── binary_heap.rs │ │ │ │ │ │ ├── btree_map.rs │ │ │ │ │ │ ├── btree_set.rs │ │ │ │ │ │ ├── hash_map.rs │ │ │ │ │ │ ├── hash_set.rs │ │ │ │ │ │ ├── linked_list.rs │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ └── vec_deque.rs │ │ │ │ │ ├── delegate.rs │ │ │ │ │ ├── iter │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ ├── chain.rs │ │ │ │ │ │ ├── cloned.rs │ │ │ │ │ │ ├── collect │ │ │ │ │ │ │ ├── consumer.rs │ │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ │ └── test.rs │ │ │ │ │ │ ├── enumerate.rs │ │ │ │ │ │ ├── extend.rs │ │ │ │ │ │ ├── filter.rs │ │ │ │ │ │ ├── filter_map.rs │ │ │ │ │ │ ├── find.rs │ │ │ │ │ │ ├── find_first_last │ │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ │ └── test.rs │ │ │ │ │ │ ├── flat_map.rs │ │ │ │ │ │ ├── flatten.rs │ │ │ │ │ │ ├── fold.rs │ │ │ │ │ │ ├── for_each.rs │ │ │ │ │ │ ├── from_par_iter.rs │ │ │ │ │ │ ├── inspect.rs │ │ │ │ │ │ ├── interleave.rs │ │ │ │ │ │ ├── internal.rs │ │ │ │ │ │ ├── len.rs │ │ │ │ │ │ ├── map.rs │ │ │ │ │ │ ├── map_with.rs │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ ├── noop.rs │ │ │ │ │ │ ├── product.rs │ │ │ │ │ │ ├── reduce.rs │ │ │ │ │ │ ├── rev.rs │ │ │ │ │ │ ├── skip.rs │ │ │ │ │ │ ├── splitter.rs │ │ │ │ │ │ ├── sum.rs │ │ │ │ │ │ ├── take.rs │ │ │ │ │ │ ├── test.rs │ │ │ │ │ │ ├── unzip.rs │ │ │ │ │ │ ├── while_some.rs │ │ │ │ │ │ ├── zip.rs │ │ │ │ │ │ └── zip_eq.rs │ │ │ │ │ ├── lib.rs │ │ │ │ │ ├── option.rs │ │ │ │ │ ├── par_either.rs │ │ │ │ │ ├── prelude.rs │ │ │ │ │ ├── private.rs │ │ │ │ │ ├── range.rs │ │ │ │ │ ├── result.rs │ │ │ │ │ ├── slice │ │ │ │ │ │ ├── mergesort.rs │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ ├── quicksort.rs │ │ │ │ │ │ └── test.rs │ │ │ │ │ ├── split_producer.rs │ │ │ │ │ ├── str.rs │ │ │ │ │ ├── test.rs │ │ │ │ │ └── vec.rs │ │ │ │ └── tests │ │ │ │ │ ├── compile-fail-unstable │ │ │ │ │ └── README.md │ │ │ │ │ ├── compile-fail │ │ │ │ │ ├── README.md │ │ │ │ │ ├── cannot_collect_filtermap_data.rs │ │ │ │ │ ├── cannot_zip_filtered_data.rs │ │ │ │ │ ├── cell_par_iter.rs │ │ │ │ │ ├── must_use.rs │ │ │ │ │ ├── no_send_par_iter.rs │ │ │ │ │ ├── quicksort_race1.rs │ │ │ │ │ ├── quicksort_race2.rs │ │ │ │ │ ├── quicksort_race3.rs │ │ │ │ │ ├── rc_par_iter.rs │ │ │ │ │ ├── rc_return.rs │ │ │ │ │ ├── rc_upvar.rs │ │ │ │ │ └── scope_join_bad.rs │ │ │ │ │ ├── run-fail-unstable │ │ │ │ │ └── README.md │ │ │ │ │ ├── run-fail │ │ │ │ │ ├── README.md │ │ │ │ │ ├── iter_panic.rs │ │ │ │ │ └── simple_panic.rs │ │ │ │ │ ├── run-pass-unstable │ │ │ │ │ └── README.md │ │ │ │ │ └── run-pass │ │ │ │ │ ├── README.md │ │ │ │ │ ├── double_init_fail.rs │ │ │ │ │ ├── init_zero_threads.rs │ │ │ │ │ ├── named-threads.rs │ │ │ │ │ ├── scope_join.rs │ │ │ │ │ ├── sort-panic-safe.rs │ │ │ │ │ └── stack_overflow_crash.rs │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── rayon-blocking-2 │ │ │ ├── Cargo.toml │ │ │ ├── README.md │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── redox-blocking-1 │ │ │ ├── Cargo.toml │ │ │ ├── README.md │ │ │ └── src │ │ │ │ └── main.rs │ │ └── tikv-blocking-3 │ │ │ ├── Cargo.toml │ │ │ ├── README.md │ │ │ └── src │ │ │ └── main.rs │ └── non-blocking-bugs │ │ ├── servo-nonblocking-16 │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ └── main.rs │ │ └── servo-nonblocking-6 │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ └── main.rs ├── section-6-1-blocking-bugs │ ├── ManualDropPrinter │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ ├── Common │ │ │ │ └── CallerFunc.h │ │ │ └── PrintManualDrop │ │ │ │ └── PrintManualDrop.h │ │ └── lib │ │ │ ├── CMakeLists.txt │ │ │ ├── Common │ │ │ ├── CMakeLists.txt │ │ │ └── CallerFunc.cpp │ │ │ └── PrintManualDrop │ │ │ ├── CMakeLists.txt │ │ │ └── PrintManualDrop.cpp │ ├── README.md │ ├── blocking-bugs │ │ ├── crossbeam │ │ │ ├── 5987357a740a5a2768c264301ba7243edb1ccb71.txt │ │ │ └── cfbbb6687792517dd5f9c60ac98f1b13f3f49259.txt │ │ ├── lazy-static.rs │ │ │ └── eae87a9f9736b5c35e9e03dec1a8f8c3f8d2cf36.txt │ │ ├── parity-ethereum │ │ │ ├── 05f9606bf2fc9fb51a7dd3033d9fc2ce55f1a2e9.txt │ │ │ ├── 0d593199d0352915077828abb03568a84116f289.txt │ │ │ ├── 114e93ab308f4b401b6e3e4a5c44920233bf9c65.txt │ │ │ ├── 12fd8563a9d6a4f8d6c8182e235e13a2ce72ee24.txt │ │ │ ├── 16ddb8843513c4864c3a66ba6b4e9ae0399289c6.txt │ │ │ ├── 18965be0473d19aa6f1d2a2d587deeac3337d899.txt │ │ │ ├── 19a67254304075017190311ce869853ea052a166.txt │ │ │ ├── 1f39a1bd768ae8b490068313bb41ca78bccf964b.txt │ │ │ ├── 31e64c0a5f644aa364c28db9ee3cd8ac20e430b4.txt │ │ │ ├── 43cc4ea13dec86cc4721f85bdbd8cc0e151bd5a2.txt │ │ │ ├── 44e1e74bfad2588ac1906e1171f0a3e00188f958.txt │ │ │ ├── 5bdd9a1a0e06813eda559ac1fb01d7de4251faa0.txt │ │ │ ├── 5f1ce7f281b4f4bb03995ead519d948ae64237a4-0.txt │ │ │ ├── 5f1ce7f281b4f4bb03995ead519d948ae64237a4-1.txt │ │ │ ├── 5fc944ae1d2bf24017c6976acc20a4601484280c.txt │ │ │ ├── 63c959c4ee9aec1e8040ce3040fde9b55e388952.txt │ │ │ ├── 73c19fd4b517dada829c31182e4fa15b872adbd0.txt │ │ │ ├── 79d996300bdfd2990cb7d60c50c11667fec5fcc7.txt │ │ │ ├── 7c015f023fa8fa7eae9d0836595faa274b23ae5a.txt │ │ │ ├── 89011dcc34e5255efd830f808d4e6bcb5f10b3a9.txt │ │ │ ├── 8a8cfb133fbc8ed8652acd1559367c3e3cda451e.txt │ │ │ ├── 8b692e6d9db18f0f7150b8ee79b5a901039c573b.txt │ │ │ ├── 8ed632eb961debe5b09fe1ed38fe2ff58701e607.txt │ │ │ ├── 8fe73c9dd4bc37b7577c4a8391794ec651004b4c.txt │ │ │ ├── a1a002f4da3713e312f11b5aa207268af163670b.txt │ │ │ ├── a33e2f2e0d262382b6cc2bb77863c7d21cfb34b5.txt │ │ │ ├── a7505be627fdc6ac25d32133b6e7dd2a49dd891b.txt │ │ │ ├── ab079fd7bf7d7f9ad04c6fe581dd680480fe5303.txt │ │ │ ├── b246806571d4fe4378cd056858ef4b10f855e0a9.txt │ │ │ ├── c1aed4af45c523dbbf84b5db8720ddad6fedcfd3.txt │ │ │ ├── d95e9710306e95552a2ba3ad4df66067c77bea96.txt │ │ │ ├── eef9586c57694142fabf79a50b953185219d42b0.txt │ │ │ ├── f057b88f998b968641856dca42b2c84570f0982f.txt │ │ │ └── f20f4c74d2aba567cc80133f222bd47c97634551.txt │ │ ├── rayon │ │ │ ├── 36577d60a1b54bfa5618f1fda34a6b12a2380a10.txt │ │ │ └── f17d745e12511516396f6ba5027a30e88e981bfb.txt │ │ ├── redox │ │ │ ├── c7eccb3a13493c582de8d452a1112b28224a973d.txt │ │ │ └── d329f7c7d2540fb5bd73624adee6151092248dc8.txt │ │ ├── rust-threadpool │ │ │ └── 2694e24bebed9ee9af8d59e6c7d4d93eec1b0ff9.txt │ │ ├── servo │ │ │ ├── 13fe502cd63d3adc19a36a34447c09fab38ae47c.txt │ │ │ ├── 183c387d8b5c9c2b19fea77517f09bf8b23f42f2.txt │ │ │ ├── 1e380137831eaf94a1f602c9d8dfae08f10893fa.txt │ │ │ ├── 2416072dc2b264191ab9a6515a8f9c3415849b71.txt │ │ │ ├── 2952ccfae2e4883efc4886988dcf17d07d89f66c.txt │ │ │ ├── 2accabd554a4d34e1d5fe2cbc112c85763e7ac3e.txt │ │ │ ├── 6d3429ad03728028fa4059dd192456de292f939d.txt │ │ │ ├── 6fbd2aa5b7628bd47971806ddf438cd350a60bee.txt │ │ │ ├── 702445a3ec4d406472a618750f5dab64c38459bb.txt │ │ │ ├── 7a72981d87c54017ae2cc0bc4c0af02a7d654f1c.txt │ │ │ ├── 8bed7713dbd1cae1192ac10d27bcd7f787888e85.txt │ │ │ ├── ccfd977076ca09aa89de236a55071938a562176b.txt │ │ │ └── fdb1e511bde3fa9e3b3c524a07687dc52131fa0b.txt │ │ └── tikv │ │ │ ├── 237c23017d439def50e04cdea36144e5dabb328b.txt │ │ │ ├── 6c487ed44adbf297cd054f09e2892809c8718bc6.txt │ │ │ ├── bcb7745e56f351946902d858df593a15faa9f76c.txt │ │ │ └── cd330aa9c1cea04b99d9f813e2c9e03d453ac1b8.txt │ ├── final_result.txt │ ├── parse_manual_drop_log.py │ ├── run.sh │ └── run_all.sh └── section-6-2-non-blocking-bugs │ └── non-blocking-bugs │ ├── RUSTSEC │ └── 22351fe532cf480e26a7ad8717d86a023da8f1d6.txt │ ├── crossbeam │ ├── 268c02814a6589577dffada83174532f6111c352.txt │ ├── 525c22fe097543c5db6051e2e2cb0338017e7b58.txt │ ├── 6e333047cebf3bcb6d9e87794ee809b653d8bdba.txt │ ├── 9178ce15a59f1ef8398323d0a5890c3db3f3f59d.txt │ ├── 9d423946835b69edb395a5654b85649161f34d3b.txt │ ├── a30957726d1437326c60e6dd7e2a303ae255b591.txt │ ├── eab00e91147c93ca4646c1ba06f2f16054b30e77.txt │ └── f8bee404e7aa9bd005b6a16c6bbcbe59d04ce0a7.txt │ ├── parity-ethereum │ ├── 145e766db2de4b20b208a9bb2478479b74f855fe.txt │ ├── 6999957869a14b22fe3b22d797a232ab8976caf5.txt │ ├── 7503d6695a8ef22fa0aa4530745ceed95a260f63.txt │ └── 796482c12917768e09376557f0c37adc057bf322.txt │ ├── rand │ ├── bccefbc27f6db0f59de15b6cce0b59785d383f27.txt │ └── e0e8263c25dc291f818cd20c034912de5ae05189.txt │ ├── redox │ ├── 2a66a84a507335c54e84bee3270b35a8a49f3b9e.txt │ ├── 979d80a8c71e2605859c65e46ccef674178f1e71.txt │ └── redox-303.txt │ ├── servo │ ├── 1997d034faef7a09ba2d8e3c8b5cc31a1e22b1e3.txt │ ├── 2a7f262b7df8761261a0fa618394f4e991733a5e.txt │ ├── 362c2718f7147a633eeb3b1cfd45aa13a0bf4250.txt │ ├── 3c288a5b80ff53061e44101a746c2ebd2a081fb0.txt │ ├── 432580bd043c402fad1a1dd428c2921b27456b05.txt │ ├── 4f866625ccd81a682589640b360065eb43ffdf85.txt │ ├── 89a29a7f12c3cee5af947c87602737a666919f93.txt │ ├── 89e129bf9f0d2d388f7506854aa2eb2456cb2d4d.txt │ ├── 8a4a5c0cb515242823289691a67fc553244eaa2e.txt │ ├── 96c124230b367c0c9658e3628bcb0a33533cc96c.txt │ ├── a13b2d447bdf1e6df37dea90d6df18728f3dadf8.txt │ ├── a31535a46e4191544d451f53e712402802cde736.txt │ ├── b29d0c6c318ab3bede814a97a7dd83ea42d03c7b.txt │ ├── c98d35ea6b70d341696e72f1d8aeff9dd945f423.txt │ ├── d11716e27b539a98bba64f25c79c06ad92a409aa.txt │ ├── d303f50784afedb3291d41d06b0e3bf6a9be5bad.txt │ ├── d465abdb1c2162ca9eeb72f391ea4a721332500a.txt │ └── e67ea42c3fa03264b8c897430f7c17a7c153e5bd.txt │ ├── tikv │ ├── 12c36194d325051c9cea13c2850bab108451f146.txt │ ├── a28e3606e8beeb4f81a3f5875ece0027dc805e91.txt │ └── f3a1bedd3b726e6af42e05d4a4cc3d15b739251f.txt │ └── tock │ ├── 36ac574543e13aa25fe5e9b89538ce4ff7c40739.txt │ └── bf8e0e2e0ecf11449642dab9426372b86f53227a.txt └── section-7-bug-detection ├── applications ├── README.md └── relibc_mir_detected_bugs │ ├── rustc.header-netdb-gethostbyaddr.003-027.PreCodegen.after.mir │ ├── rustc.header-netdb-gethostbyname.003-027.PreCodegen.after.mir │ ├── rustc.header-netdb-getprotoent.003-027.PreCodegen.after.mir │ └── rustc.header-netdb-getservent.003-027.PreCodegen.after.mir ├── section-7.1-detecting-memory-bugs ├── run_uaf_detector.sh └── use-after-free-detector │ ├── .gitignore │ ├── README.md │ ├── basic_block.py │ ├── define_types.py │ ├── function.py │ ├── line_parser.py │ ├── main.py │ ├── mir_detected_bugs │ ├── rustc.header-netdb-gethostbyaddr.003-027.PreCodegen.after.mir │ ├── rustc.header-netdb-gethostbyname.003-027.PreCodegen.after.mir │ ├── rustc.header-netdb-getprotoent.003-027.PreCodegen.after.mir │ └── rustc.header-netdb-getservent.003-027.PreCodegen.after.mir │ ├── sample_mir │ ├── gethostbyaddr.PreCodegen.after.mir │ ├── gethostbyname.PreCodegen.after.mir │ ├── rustc.header-inttypes-strtoimax.003-026.PreCodegen.after.mir │ ├── rustc.raftstore-store-snap-{{impl}}[19]-lt-{{closure}}.003-026.PreCodegen.after.mir │ ├── rustc.use_after_free.003-026.PreCodegen.after.mir │ ├── sample.PreCodegen.after.mir │ └── sample2.PreCodegen.after.mir │ ├── statement_parser.py │ ├── utils.py │ └── variable.py └── section-7.2-detecting-concurrency-bugs └── double-lock-detector ├── DoubleLockDetector ├── CMakeLists.txt ├── include │ ├── Common │ │ └── CallerFunc.h │ └── RustDoubleLockDetector │ │ └── RustDoubleLockDetector.h └── lib │ ├── CMakeLists.txt │ ├── Common │ ├── CMakeLists.txt │ └── CallerFunc.cpp │ └── RustDoubleLockDetector │ ├── CMakeLists.txt │ └── RustDoubleLockDetector.cpp ├── README.md ├── run.sh └── run_all.sh /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "section-7-bug-detection/applications/relibc"] 2 | path = section-7-bug-detection/applications/relibc 3 | url = https://github.com/redox-os/relibc.git 4 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-1/README.md: -------------------------------------------------------------------------------- 1 | # Figure 1. Rust History 2 | 3 | ## Plot Figure 1. 4 | 5 | Figure 1. in our PLDI submission is plotted by `ploticus`, a free plotting software. 6 | You also need to install `texlive-font-utils` to convert the figure to pdf format. 7 | If you are using the VM we provided for artifact evaluation, these packages should be already installed. 8 | If you want to generate Figure. 1. on your own machine, you can install them by: 9 | 10 | Ubuntu 16.04 11 | 12 | ``` 13 | sudo apt-get install ploticus texlive-font-utils 14 | ``` 15 | 16 | Mac OS 17 | 18 | ``` 19 | brew install ploticus texlive-font-utils 20 | ``` 21 | 22 | 23 | Then, run the following command under this directory to generate Figure. 1. (File. `Figure_1.pdf`) 24 | ``` 25 | ./plot_Figure_1.sh 26 | ``` 27 | 28 | 29 | ## Explanation of raw data 30 | 31 | `data_rust_history.tab` contents the raw data of Figure 1. There are three columns. Column 1 & 2 are 32 | collected from Rust's release note ([github link](https://github.com/rust-lang/rust/blob/master/RELEASES.md), 33 | cutting to version `1.39.0`) 34 | 35 | ### Column 1 (the first column) 36 | It represents the release date of one Rust release version. 37 | 38 | ### Column 2 39 | It represents the number of feature changes in one Rust release version. For the versions before `1.6.0`, 40 | the notes explicitly reveal how many feature changes (e.g. version `1.5.0`, ~700 changes), we just use those 41 | numbers. For the versions after `1.5.0`, we manually count the number of changes in the lists. 42 | 43 | ### Column 3 44 | 45 | It represents the lines of code (kLOC) of one Rust release version. The data is collected by `cloc`. 46 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-1/plot_Figure_1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ploticus plot_rust_histories.pl -eps -o Figure_1.eps -textsize 18 -font /Courier 3 | epstopdf Figure_1.eps 4 | rm -rf Figure_1.eps 5 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-2/data_bugs_date.tab: -------------------------------------------------------------------------------- 1 | Time Servo TiKV Ethereum Redox Tock Libs 2 | 07/2012 2 0 0 0 0 0 3 | 07/2013 2 0 0 0 0 0 4 | 07/2014 1 0 0 0 0 0 5 | 07/2015 3 0 0 0 0 1 6 | 07/2016 7 1 0 4 0 4 7 | 07/2017 0 1 0 0 0 3 8 | 07/2018 0 0 2 0 1 7 9 | 04/2015 1 0 0 0 0 1 10 | 04/2014 2 0 0 0 0 0 11 | 04/2017 3 1 1 0 0 2 12 | 04/2016 3 2 0 0 0 1 13 | 04/2018 1 0 3 0 0 5 14 | 01/2016 0 0 4 0 0 5 15 | 01/2017 3 0 0 0 0 0 16 | 01/2014 3 0 0 0 0 0 17 | 01/2018 0 1 0 0 1 1 18 | 01/2019 0 0 0 0 0 1 19 | 10/2014 2 0 0 0 0 0 20 | 10/2015 1 0 0 1 0 0 21 | 10/2016 2 0 1 0 0 0 22 | 10/2017 1 2 0 0 0 1 23 | 10/2013 2 0 0 0 0 0 24 | 10/2018 0 0 1 0 0 5 25 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-2/plot_Figure_2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ploticus plot_bugs_date.pl -eps -o Figure_2.eps -textsize 18 -font /Courier 3 | epstopdf Figure_2.eps 4 | rm -rf Figure_2.eps 5 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-2/raw_data/data_ethereum_bugs_date.tab: -------------------------------------------------------------------------------- 1 | 01/2016 4 2 | 04/2016 3 3 | 07/2016 7 4 | 10/2016 6 5 | 01/2017 3 6 | 04/2017 1 7 | 07/2017 2 8 | 04/2018 6 9 | 07/2018 2 10 | 10/2018 2 11 | 01/2019 1 12 | 07/2019 2 13 | 14 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-2/raw_data/data_libs_bugs_date.tab: -------------------------------------------------------------------------------- 1 | 04/2015 1 2 | 07/2015 1 3 | 01/2016 6 4 | 07/2016 1 5 | 04/2017 2 6 | 07/2017 3 7 | 10/2017 1 8 | 01/2018 1 9 | 04/2018 4 10 | 07/2018 5 11 | 10/2018 6 12 | 01/2019 2 13 | 04/2019 7 14 | 07/2019 5 15 | 16 | 17 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-2/raw_data/data_redox_bugs_date.tab: -------------------------------------------------------------------------------- 1 | 10/2015 1 2 | 04/2016 1 3 | 07/2016 8 4 | 04/2017 3 5 | 01/2018 2 6 | 04/2018 2 7 | 07/2018 3 8 | 10/2018 3 9 | 01/2019 1 10 | 04/2019 1 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-2/raw_data/data_servo_bugs_date.tab: -------------------------------------------------------------------------------- 1 | 07/2012 2 2 | 04/2013 1 3 | 07/2013 2 4 | 10/2013 3 5 | 01/2014 3 6 | 04/2014 2 7 | 07/2014 1 8 | 10/2014 2 9 | 01/2015 1 10 | 07/2015 3 11 | 10/2015 1 12 | 04/2016 3 13 | 07/2016 9 14 | 10/2016 2 15 | 01/2017 3 16 | 04/2017 3 17 | 10/2017 1 18 | 01/2018 1 19 | 04/2018 1 20 | 04/2019 1 21 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-2/raw_data/data_tikv_bugs_date.tab: -------------------------------------------------------------------------------- 1 | 04/2016 2 2 | 07/2016 1 3 | 04/2017 1 4 | 07/2017 2 5 | 10/2017 2 6 | 01/2018 1 7 | 8 | -------------------------------------------------------------------------------- /section-2-background-and-related-work/Figure-2/raw_data/data_tock_bugs_date.tab: -------------------------------------------------------------------------------- 1 | 01/2016 1 2 | 04/2016 1 3 | 10/2016 1 4 | 01/2017 1 5 | 07/2017 1 6 | 01/2018 1 7 | 07/2018 1 8 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/section-4-1-reasons-of-usage/README.md: -------------------------------------------------------------------------------- 1 | # Benchmark the performance for unsafe and safe code 2 | 3 | ## Usage: 4 | 5 | 1. Install 6 | ``` 7 | rustup default 1.36.0 8 | ``` 9 | 10 | 2. Benchmark memory copy 11 | ``` 12 | cd mem-copy 13 | cargo bench 14 | ``` 15 | 16 | 3. Benchmark memory access 17 | ``` 18 | cd array-access 19 | cargo bench 20 | ``` 21 | 22 | 4. Benchmark ```ptr::offset``` and array access 23 | ``` 24 | cd array-offset 25 | cargo bench 26 | ``` 27 | 28 | ## Output: 29 | 30 | Example: 31 | ``` 32 | test tests::bench_safe ... bench: 2,007 ns/iter (+/- 42) 33 | test tests::bench_unsafe ... bench: 1,629 ns/iter (+/- 14) 34 | ``` 35 | 36 | Compare numbers of ns/iter between safe and unafe code. 37 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/section-4-1-reasons-of-usage/array-access/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "array-access" 3 | version = "0.1.0" 4 | authors = ["bzq16"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/section-4-1-reasons-of-usage/array-offset/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "array-offset" 3 | version = "0.1.0" 4 | authors = ["BurtonQin"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/section-4-1-reasons-of-usage/array-offset/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | use test::Bencher; 9 | 10 | #[bench] 11 | fn bench_array(b: &mut Bencher) { 12 | const ARRAY_SIZE : usize = 100000; 13 | let mut array = [1; ARRAY_SIZE]; 14 | let mut size = 99999; 15 | size += 1; 16 | let mut sum = 0; 17 | b.iter(|| { 18 | for i in 0..size { 19 | let a = array[i]; 20 | unsafe { 21 | sum += a; 22 | } 23 | } 24 | }); 25 | } 26 | 27 | #[bench] 28 | fn bench_offset(b: &mut Bencher) { 29 | const ARRAY_SIZE : usize = 100000; 30 | let mut array = [1; ARRAY_SIZE]; 31 | let mut size = 99999; 32 | size += 1; 33 | let mut sum = 0; 34 | let p = array.as_mut_ptr(); 35 | b.iter(|| { 36 | for i in 0..size { 37 | unsafe { 38 | let a = *p.offset(i); 39 | sum += a; 40 | } 41 | } 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/section-4-1-reasons-of-usage/mem-copy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mem-copy" 3 | version = "0.1.0" 4 | authors = ["BurtonQin"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/section-4-1-reasons-of-usage/mem-copy/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | use test::Bencher; 9 | 10 | #[bench] 11 | fn bench_unsafe(b: &mut Bencher) { 12 | let src = vec![1; 10]; 13 | let mut dst_len = 11; 14 | dst_len -= 1; 15 | let mut dst = vec![2; dst_len]; 16 | let src_len = src.len(); 17 | dst.reserve(src_len); 18 | let src = src.as_slice(); 19 | let mut dst = dst.as_mut_slice(); 20 | let dst_ptr = dst.as_mut_ptr(); 21 | let src_ptr = src.as_ptr(); 22 | 23 | b.iter(|| { 24 | unsafe { 25 | for i in 0..1000 { 26 | std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); 27 | } 28 | } 29 | }); 30 | println!("{}, {}", src[0], dst[0]); 31 | } 32 | 33 | #[bench] 34 | fn bench_safe(b: &mut Bencher) { 35 | let src = vec![1; 10]; 36 | let mut dst_len = 11; 37 | dst_len -= 1; 38 | let mut dst = vec![2; dst_len]; 39 | let src_len = src.len(); 40 | dst.reserve(src_len); 41 | let src = src.as_slice(); 42 | let mut dst = dst.as_mut_slice(); 43 | let dst_ptr = dst.as_mut_ptr(); 44 | let src_ptr = src.as_ptr(); 45 | 46 | b.iter(|| { 47 | for i in 0..1000 { 48 | dst.copy_from_slice(src); 49 | } 50 | }); 51 | println!("{}, {}", src[0], dst[0]); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/section-4-1-reasons-of-usage/run_all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd mem-copy 4 | cargo bench 2>/dev/null 5 | 6 | cd ../array-access 7 | cargo bench 2>/dev/null 8 | 9 | cd ../array-offset 10 | cargo bench 2>/dev/null 11 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/unsafe-statisitcs/README.md: -------------------------------------------------------------------------------- 1 | # Count unsafe regions, functions, and traits 2 | 3 | ## Studied Benchmark App 4 | 1. https://github.com/servo/servo 5 | commit: 3a33f99cad1e80e1f1a3e12dd98cabd9c40aa246 6 | 2. https://github.com/tikv/tikv 7 | commit: 2b0296b7c779afc89c8a0dc64e31a6b41d0d035c 8 | 3. https://github.com/paritytech/parity-ethereum 9 | commit: 04c686766060d1954ba1069d7634e7458053ec43 10 | 4. https://www.redox-os.org/ 11 | commit: d68d5890a0079812e49aeacbe76acb49ee5102e1 12 | 5. https://github.com/tock/tock 13 | commit: 10723bd0efac798458ee205b04fe8786e8287cf8 14 | 6. https://github.com/rust-random/rand 15 | commit: 1eef88c78cdef80c6b1675c3553110a5f2a013d8 16 | 7. https://github.com/crossbeam-rs/crossbeam 17 | commit: 0bd562ce1710c58594d57ffa9723298a6df975e9 18 | 8. https://github.com/rust-threadpool/rust-threadpool 19 | commit: 07d1a5b1b7aaecad8983cd80623f52cbf310ce23 20 | 9. https://github.com/rayon-rs/rayon 21 | commit: 003b5e64735a6606c0aa7735cc22f0a259056c2f 22 | 10. https://github.com/rust-lang-nursery/lazy-static.rs 23 | commit: 88994b26744fac2ceb713a9285985f76195c9c89 24 | 11. https://github.com/rust-lang/rust 25 | commit: 2975a3c4befa8ad610da2e3c5f5de351d6d70a2b 26 | 27 | ## Usage: 28 | 29 | ```cd src_parser``` 30 | 31 | ```./run_all.sh COUNT_DIR``` 32 | 33 | ## Output: 34 | 35 | Number of unsafe regions, LOC of unsafe regions; 36 | Number of unsafe functions, LOC of unsafe functions; 37 | Number of unsafe traits. 38 | 39 | The final results are in `artifact.xlsx` section-4-stat tab. 40 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/unsafe-statisitcs/src_parser/comment_remover/README.md: -------------------------------------------------------------------------------- 1 | # Remove comments 2 | 3 | Remove comments in Rust source files. 4 | -------------------------------------------------------------------------------- /section-4-unsafe-usages/unsafe-statisitcs/src_parser/comment_remover/comment_remover: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/system-pclub/rust-study/403b06f30809d10d2bb066d2fbcd33caf3446d17/section-4-unsafe-usages/unsafe-statisitcs/src_parser/comment_remover/comment_remover -------------------------------------------------------------------------------- /section-4-unsafe-usages/unsafe-statisitcs/src_parser/sum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | 6 | def main(): 7 | input_file_path =sys.argv[1] 8 | sum_LOC = 0 9 | with open(input_file_path) as infile: 10 | lines = infile.readlines() 11 | for line in lines: 12 | fields = line.split(",") 13 | assert len(fields) == 2 14 | sum_LOC += len(fields[1]) - len(fields[0]) + 1 15 | print(len(lines), sum_LOC) 16 | 17 | if __name__ == "__main__": 18 | main() 19 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/CVE-2018-1000657: -------------------------------------------------------------------------------- 1 | diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs 2 | index 6836fbb7c4d..6d64e9e303f 100644 3 | --- a/src/liballoc/vec_deque.rs 4 | +++ b/src/liballoc/vec_deque.rs 5 | @@ -558,7 +558,7 @@ impl VecDeque { 6 | .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) 7 | .expect("capacity overflow"); 8 | 9 | - if new_cap > self.capacity() { 10 | + if new_cap > old_cap { 11 | self.buf.reserve_exact(used_cap, new_cap - used_cap); 12 | unsafe { 13 | self.handle_cap_increase(old_cap); 14 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/CVE-2019-15554_RUSTSEC-2019-0012: -------------------------------------------------------------------------------- 1 | diff --git a/lib.rs b/lib.rs 2 | index 5af32ba..2e0aa04 100644 3 | --- a/lib.rs 4 | +++ b/lib.rs 5 | @@ -654,6 +654,7 @@ impl SmallVec { 6 | } 7 | self.data = SmallVecData::from_inline(mem::uninitialized()); 8 | ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len); 9 | + self.capacity = len; 10 | } else if new_cap != cap { 11 | let mut vec = Vec::with_capacity(new_cap); 12 | let new_alloc = vec.as_mut_ptr(); 13 | @@ -2311,4 +2312,21 @@ mod tests { 14 | let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); 15 | assert_eq!(small_vec, decoded); 16 | } 17 | + 18 | + #[test] 19 | + fn grow_to_shrink() { 20 | + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); 21 | + v.push(1); 22 | + v.push(2); 23 | + v.push(3); 24 | + assert!(v.spilled()); 25 | + v.clear(); 26 | + // Shrink to inline. 27 | + v.grow(2); 28 | + assert!(!v.spilled()); 29 | + assert_eq!(v.capacity(), 2); 30 | + assert_eq!(v.len(), 0); 31 | + v.push(4); 32 | + assert_eq!(v[..], [4]); 33 | + } 34 | } 35 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/CVE-2019-16140_RUSTSEC-2019-0016: -------------------------------------------------------------------------------- 1 | diff --git a/src/buffer.rs b/src/buffer.rs 2 | index e857d33..c13336b 100644 3 | --- a/src/buffer.rs 4 | +++ b/src/buffer.rs 5 | @@ -192,7 +192,9 @@ impl From for Vec { 6 | let len = buffer.copy_to(&mut slice); 7 | 8 | unsafe { 9 | - Vec::from_raw_parts(slice.as_mut_ptr(), len, slice.len()) 10 | + let vec = Vec::from_raw_parts(slice.as_mut_ptr(), len, slice.len()); 11 | + mem::forget(slice); 12 | + vec 13 | } 14 | } 15 | } 16 | @@ -291,4 +293,17 @@ mod tests { 17 | buffer.copy_to(&mut out); 18 | assert!(&out == b"hello world"); 19 | } 20 | + 21 | + #[test] 22 | + fn vec_from_buffer() { 23 | + let mut buffer = Buffer::new(); 24 | + let bytes = b"hello world"; 25 | + buffer.push(bytes); 26 | + 27 | + assert!(buffer.len() == bytes.len()); 28 | + 29 | + let vec = Vec::from(buffer); 30 | + 31 | + assert!(&vec == bytes); 32 | + } 33 | } 34 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/CVE-2019-16880_RUSTSEC-2019-0021: -------------------------------------------------------------------------------- 1 | diff --git a/src/lib.rs b/src/lib.rs 2 | index f0c8330..931b089 100644 3 | --- a/src/lib.rs 4 | +++ b/src/lib.rs 5 | @@ -172,10 +172,10 @@ impl, N: ArrayLength>> Matrix { 6 | #[inline] fn map_elements B>(self, mut f: F) -> Matrix 7 | where M: ArrayLength, N: ArrayLength> { 8 | let Matrix(a) = self; 9 | - let _wrapper = mem::ManuallyDrop::new(a); 10 | + let wrapper = mem::ManuallyDrop::new(a); 11 | let mut c: GenericArray, N> = unsafe { mem::uninitialized() }; 12 | for i in 0..N::to_usize() { for j in 0..M::to_usize() { unsafe { 13 | - ptr::write(&mut c[i][j], f(ptr::read(&_wrapper[i][j]))) 14 | + ptr::write(&mut c[i][j], f(ptr::read(&wrapper[i][j]))) 15 | }}} 16 | Matrix(c) 17 | } 18 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/CVE-2019-16881_RUSTSEC-2019-0022: -------------------------------------------------------------------------------- 1 | https://github.com/mvdnes/portaudio-rs/issues/20 2 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/RUSTSEC-2018-0008: -------------------------------------------------------------------------------- 1 | diff --git a/src/lib.rs b/src/lib.rs 2 | index ecd0eb1..22ef3a6 100644 3 | --- a/src/lib.rs 4 | +++ b/src/lib.rs 5 | @@ -748,7 +748,7 @@ impl SliceDeque { 6 | new_head += cap as isize; 7 | debug_assert!(new_head >= 0); 8 | self.tail_ += cap; 9 | - } else if new_head as usize > cap { 10 | + } else if new_head as usize >= cap { 11 | // cannot panic because new_head >= 0 12 | // If the new head is larger than the capacity, we shift the range 13 | // by -capacity to move it towards the first mirrored 14 | @@ -765,6 +765,8 @@ impl SliceDeque { 15 | 16 | debug_assert!(self.tail() <= self.tail_upper_bound()); 17 | debug_assert!(self.head() <= self.head_upper_bound()); 18 | + 19 | + debug_assert!(self.head() != self.capacity()); 20 | } 21 | 22 | /// Moves the deque head by `x`. 23 | @@ -5890,4 +5892,21 @@ mod tests { 24 | assert_eq!(v.as_ptr() as usize, mem::align_of::()); 25 | } 26 | } 27 | + 28 | + #[test] 29 | + fn issue_57() { 30 | + const C: [i16; 3] = [42; 3]; 31 | + 32 | + let mut deque = SliceDeque::new(); 33 | + 34 | + for _ in 0..918 { 35 | + deque.push_front(C); 36 | + } 37 | + 38 | + for _ in 0..237 { 39 | + assert_eq!(deque.pop_front(), Some(C)); 40 | + assert!(!deque.is_empty()); 41 | + assert_eq!(*deque.back().unwrap(), C); 42 | + } 43 | + } 44 | } 45 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/RUSTSEC-2018-0010: -------------------------------------------------------------------------------- 1 | diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs 2 | index 6ee62fd0..5781a01f 100644 3 | --- a/openssl/src/cms.rs 4 | +++ b/openssl/src/cms.rs 5 | @@ -138,22 +138,14 @@ impl CmsContentInfo { 6 | flags: CMSOptions, 7 | ) -> Result { 8 | unsafe { 9 | - let signcert = match signcert { 10 | - Some(cert) => cert.as_ptr(), 11 | - None => ptr::null_mut(), 12 | - }; 13 | - let pkey = match pkey { 14 | - Some(pkey) => pkey.as_ptr(), 15 | - None => ptr::null_mut(), 16 | - }; 17 | - let data_bio_ptr = match data { 18 | - Some(data) => MemBioSlice::new(data)?.as_ptr(), 19 | - None => ptr::null_mut(), 20 | - }; 21 | - let certs = match certs { 22 | - Some(certs) => certs.as_ptr(), 23 | - None => ptr::null_mut(), 24 | + let signcert = signcert.map_or(ptr::null_mut(), |p| p.as_ptr()); 25 | + let pkey = pkey.map_or(ptr::null_mut(), |p| p.as_ptr()); 26 | + let data_bio = match data { 27 | + Some(data) => Some(MemBioSlice::new(data)?), 28 | + None => None, 29 | }; 30 | + let data_bio_ptr = data_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); 31 | + let certs = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); 32 | 33 | let cms = cvt_p(ffi::CMS_sign( 34 | signcert, 35 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/RUSTSEC-2018-0013: -------------------------------------------------------------------------------- 1 | diff --git a/src/lib.rs b/src/lib.rs 2 | index 0a8988a..f7d8c9f 100644 3 | --- a/src/lib.rs 4 | +++ b/src/lib.rs 5 | @@ -314,7 +314,7 @@ pub unsafe fn guarded_transmute_vec_permissive(mut bytes: Vec) -> Vec 6 | let capacity = bytes.capacity() / size_of::(); 7 | let len = bytes.len() / size_of::(); 8 | forget(bytes); 9 | - Vec::from_raw_parts(ptr as *mut T, capacity, len) 10 | + Vec::from_raw_parts(ptr as *mut T, len, capacity) 11 | } 12 | 13 | /// Trasform a byte vector into a vector of an arbitrary type. 14 | diff --git a/src/to_bytes.rs b/src/to_bytes.rs 15 | index 4eb13f0..3ce4d11 100644 16 | --- a/src/to_bytes.rs 17 | +++ b/src/to_bytes.rs 18 | @@ -231,7 +231,7 @@ pub unsafe fn guarded_transmute_to_bytes_vec(mut from: Vec) -> Vec { 19 | let len = from.len() * size_of::(); 20 | let ptr = from.as_mut_ptr(); 21 | forget(from); 22 | - Vec::from_raw_parts(ptr as *mut u8, capacity, len) 23 | + Vec::from_raw_parts(ptr as *mut u8, len, capacity) 24 | } 25 | 26 | /// Transmute a vector of POD types into a vector of their bytes, 27 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/CVE-RUSTSEC/RUSTSEC-2019-0009: -------------------------------------------------------------------------------- 1 | diff --git a/lib.rs b/lib.rs 2 | index 26d3f29..e45ca7a 100644 3 | --- a/lib.rs 4 | +++ b/lib.rs 5 | @@ -665,6 +665,8 @@ impl SmallVec { 6 | if unspilled { 7 | return; 8 | } 9 | + } else { 10 | + return; 11 | } 12 | deallocate(ptr, cap); 13 | } 14 | @@ -2341,4 +2343,18 @@ mod tests { 15 | v.extend(it); 16 | assert_eq!(v[..], ['a']); 17 | } 18 | + 19 | + #[test] 20 | + fn grow_spilled_same_size() { 21 | + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); 22 | + v.push(0); 23 | + v.push(1); 24 | + v.push(2); 25 | + assert!(v.spilled()); 26 | + assert_eq!(v.capacity(), 4); 27 | + // grow with the same capacity 28 | + v.grow(4); 29 | + assert_eq!(v.capacity(), 4); 30 | + assert_eq!(v[..], [0, 1, 2]); 31 | + } 32 | } 33 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/crossbeam/0ad4443d063351e86bcf8dec5c0ccfbdaaa442a7: -------------------------------------------------------------------------------- 1 | diff --git a/src/sync/seg_queue.rs b/src/sync/seg_queue.rs 2 | index 8a8d8cb..254a6a7 100644 3 | --- a/src/sync/seg_queue.rs 4 | +++ b/src/sync/seg_queue.rs 5 | @@ -62,7 +62,7 @@ impl SegQueue { 6 | let i = tail.high.fetch_add(1, Relaxed); 7 | unsafe { 8 | if i < SEG_SIZE { 9 | - *(*tail).data.get_unchecked(i).get() = t; 10 | + ptr::write((*tail).data.get_unchecked(i).get(), t); 11 | tail.ready.get_unchecked(i).store(true, Release); 12 | 13 | if i + 1 == SEG_SIZE { 14 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/crossbeam/b6868f7fd1799ffac6257e05389803fde89102b5: -------------------------------------------------------------------------------- 1 | diff --git a/crossbeam-skiplist/src/base.rs b/crossbeam-skiplist/src/base.rs 2 | index 2cd78e5..585fec0 100644 3 | --- a/crossbeam-skiplist/src/base.rs 4 | +++ b/crossbeam-skiplist/src/base.rs 5 | @@ -1,6 +1,6 @@ 6 | //! TODO: docs 7 | 8 | -use alloc::alloc::{alloc, dealloc, Layout}; 9 | +use alloc::alloc::{alloc, dealloc, handle_alloc_error, Layout}; 10 | use core::borrow::Borrow; 11 | use core::cmp; 12 | use core::fmt; 13 | @@ -101,6 +101,9 @@ impl Node { 14 | unsafe fn alloc(height: usize, ref_count: usize) -> *mut Self { 15 | let layout = Self::get_layout(height); 16 | let ptr = alloc(layout) as *mut Self; 17 | + if ptr.is_null() { 18 | + handle_alloc_error(layout); 19 | + } 20 | 21 | ptr::write( 22 | &mut (*ptr).refs_and_height, 23 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/crossbeam/c2010348b9b2be419065384189d3051e6e60416c: -------------------------------------------------------------------------------- 1 | diff --git a/src/sync/ms_queue.rs b/src/sync/ms_queue.rs 2 | index ff1e6ba..965295b 100644 3 | --- a/src/sync/ms_queue.rs 4 | +++ b/src/sync/ms_queue.rs 5 | @@ -63,7 +63,7 @@ impl MsQueue { 6 | tail: CachePadded::new(Atomic::null()), 7 | }; 8 | let sentinel = Owned::new(Node { 9 | - payload: unsafe { mem::uninitialized() }, 10 | + payload: Payload::Data(unsafe { mem::uninitialized() }), 11 | next: Atomic::null(), 12 | }); 13 | let guard = epoch::pin(); 14 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/parity-ethereum/46fe32bc2d8badfac97e2057a38d07dc58c2a2ab: -------------------------------------------------------------------------------- 1 | diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs 2 | index b8837e686..78a3d683a 100644 3 | --- a/util/network-devp2p/src/host.rs 4 | +++ b/util/network-devp2p/src/host.rs 5 | @@ -24,7 +24,6 @@ use std::cmp::{min, max}; 6 | use std::path::{Path, PathBuf}; 7 | use std::io::{Read, Write, self}; 8 | use std::fs; 9 | -use std::mem; 10 | use std::time::Duration; 11 | use ethkey::{KeyPair, Secret, Random, Generator}; 12 | use hash::keccak; 13 | @@ -829,7 +828,7 @@ impl Host { 14 | fn discovery_readable(&self, io: &IoContext) { 15 | let node_changes = match (self.udp_socket.lock().as_ref(), self.discovery.lock().as_mut()) { 16 | (Some(udp_socket), Some(discovery)) => { 17 | - let mut buf: [u8; MAX_DATAGRAM_SIZE] = unsafe { mem::uninitialized() }; 18 | + let mut buf = [0u8; MAX_DATAGRAM_SIZE]; 19 | let writable = !discovery.send_queue.is_empty(); 20 | let res = match udp_socket.recv_from(&mut buf) { 21 | Ok(Some((len, address))) => discovery.on_packet(&buf[0..len], address).unwrap_or_else(|e| { 22 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/rand/f35d51a2c82e684bd25f4c34e9a85e946af54933: -------------------------------------------------------------------------------- 1 | diff --git a/src/os.rs b/src/os.rs 2 | index d804808..fc36012 100644 3 | --- a/src/os.rs 4 | +++ b/src/os.rs 5 | @@ -311,13 +311,17 @@ mod imp { 6 | unsafe { mem::transmute(v) } 7 | } 8 | fn fill_bytes(&mut self, v: &mut [u8]) { 9 | - let ret = unsafe { 10 | - CryptGenRandom(self.hcryptprov, v.len() as DWORD, 11 | - v.as_mut_ptr()) 12 | - }; 13 | - if ret == 0 { 14 | - panic!("couldn't generate random bytes: {}", 15 | - io::Error::last_os_error()); 16 | + // CryptGenRandom takes a DWORD (u32) for the length so we need to 17 | + // split up the buffer. 18 | + for slice in v.chunks_mut(::max_value() as usize) { 19 | + let ret = unsafe { 20 | + CryptGenRandom(self.hcryptprov, slice.len() as DWORD, 21 | + slice.as_mut_ptr()) 22 | + }; 23 | + if ret == 0 { 24 | + panic!("couldn't generate random bytes: {}", 25 | + io::Error::last_os_error()); 26 | + } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/0b15e8bdfcda359501763d77eb0eb76d32f30a3b: -------------------------------------------------------------------------------- 1 | diff --git a/conc/src/sync/treiber.rs b/conc/src/sync/treiber.rs 2 | index da01f90..f97f099 100644 3 | --- a/conc/src/sync/treiber.rs 4 | +++ b/conc/src/sync/treiber.rs 5 | @@ -23,13 +23,15 @@ impl Drop for Treiber { 6 | // structure. They're all gone, thus we can safely mess with the inner structure. 7 | 8 | unsafe { 9 | - let ptr = *self.head.get_inner_mut().get_mut(); 10 | + let ptr = self.head.get_inner_mut().get_mut(); 11 | 12 | if !ptr.is_null() { 13 | // Call destructors on the stack. 14 | - (*ptr).destroy(); 15 | + (**ptr).destroy(); 16 | // Finally deallocate the pointer itself. 17 | - drop(Box::from_raw(ptr)); 18 | + drop(Box::from_raw(*ptr)); 19 | + // Set it to null to prevent `Atomic`'s destructor from running. 20 | + *ptr = ptr::null_mut(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/1ebd8a3d723291e7f120b3c95b2e5141c9ef93b3: -------------------------------------------------------------------------------- 1 | diff --git a/src/header/string/mod.rs b/src/header/string/mod.rs 2 | index 8c8acb2..c402707 100644 3 | --- a/src/header/string/mod.rs 4 | +++ b/src/header/string/mod.rs 5 | @@ -235,8 +235,10 @@ pub unsafe extern "C" fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: siz 6 | let len = strlen(msg); 7 | 8 | if len >= buflen { 9 | - memcpy(buf as *mut c_void, msg as *const c_void, buflen - 1); 10 | - *buf.add(buflen - 1) = 0; 11 | + if buflen != 0 { 12 | + memcpy(buf as *mut c_void, msg as *const c_void, buflen - 1); 13 | + *buf.add(buflen - 1) = 0; 14 | + } 15 | return ERANGE as c_int; 16 | } 17 | memcpy(buf as *mut c_void, msg as *const c_void, len + 1); 18 | diff --git a/tests/error.c b/tests/error.c 19 | index bb613b9..5cbe103 100644 20 | --- a/tests/error.c 21 | +++ b/tests/error.c 22 | @@ -19,4 +19,8 @@ int main(void) { 23 | char buf2[3]; 24 | int ret2 = strerror_r(err, buf2, 3); 25 | printf("errno: %d = %s, return: %d\n", err, buf2, ret2); 26 | + 27 | + char buf3[256]; 28 | + int ret3 = strerror_r(err, buf3, 0); 29 | + printf("errno: %d = %s, return: %d\n", err, buf3, ret3); 30 | } 31 | diff --git a/tests/expected/error.stdout b/tests/expected/error.stdout 32 | index d1c1a21..4e744d1 100644 33 | --- a/tests/expected/error.stdout 34 | +++ b/tests/expected/error.stdout 35 | @@ -1,3 +1,4 @@ 36 | errno: 2 = No such file or directory 37 | errno: 2 = No such file or directory, return: 0 38 | errno: 2 = No, return: 34 39 | +errno: 2 = , return: 34 40 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/49259d3f018284370c883ae54e2bbe7783d040ea: -------------------------------------------------------------------------------- 1 | diff --git a/src/header/netdb/mod.rs b/src/header/netdb/mod.rs 2 | index d5e199e..c6de7d8 100644 3 | --- a/src/header/netdb/mod.rs 4 | +++ b/src/header/netdb/mod.rs 5 | @@ -120,6 +120,7 @@ static mut HOST_ENTRY: hostent = hostent { 6 | }; 7 | static mut HOST_NAME: Option> = None; 8 | static mut HOST_ALIASES: Option>> = None; 9 | +static mut _HOST_ALIASES: Option> = None; 10 | static mut HOST_ADDR: Option = None; 11 | static mut HOST_ADDR_LIST: [*mut c_char; 2] = [ptr::null_mut(); 2]; 12 | static mut _HOST_ADDR_LIST: [u8; 4] = [0u8; 4]; 13 | @@ -649,6 +650,7 @@ pub unsafe extern "C" fn gethostent() -> *const hostent { 14 | h_length: 4, 15 | h_addr_list: HOST_ADDR_LIST.as_mut_ptr(), 16 | }; 17 | + _HOST_ALIASES = Some(host_aliases); 18 | if HOST_STAYOPEN == 0 { 19 | endhostent(); 20 | } 21 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/52acce0d346256f1ad3d0562a9a3a85531a9da75: -------------------------------------------------------------------------------- 1 | diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs 2 | index a0b2c1d..1fb185b 100644 3 | --- a/src/platform/src/redox/mod.rs 4 | +++ b/src/platform/src/redox/mod.rs 5 | @@ -204,9 +204,11 @@ pub fn unlink(path: *const c_char) -> c_int { 6 | 7 | pub fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t { 8 | unsafe { 9 | - let mut temp: usize = *stat_loc as usize; 10 | - let res = e(syscall::waitpid(pid as usize, &mut temp, options as usize)); 11 | - *stat_loc = temp as c_int; 12 | + let mut temp: usize = 0; 13 | + let mut res = e(syscall::waitpid(pid as usize, &mut temp, options as usize)); 14 | + if !stat_loc.is_null() { 15 | + *stat_loc = temp as c_int; 16 | + } 17 | res 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/629c20f097ed158233d65ca5ffc62e1c887709e6: -------------------------------------------------------------------------------- 1 | diff --git a/src/errno/src/lib.rs b/src/errno/src/lib.rs 2 | index 8a28cb6..3cb5cd0 100644 3 | --- a/src/errno/src/lib.rs 4 | +++ b/src/errno/src/lib.rs 5 | @@ -162,5 +162,5 @@ pub enum Errno { 6 | // Operation would block (may be the same value as [EAGAIN]) 7 | EWOULDBLOCK, 8 | // Cross-device link 9 | - EXDEV 10 | + EXDEV, 11 | } 12 | diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs 13 | index 744e541..f8a6f42 100644 14 | --- a/src/string/src/lib.rs 15 | +++ b/src/string/src/lib.rs 16 | @@ -2,9 +2,9 @@ 17 | 18 | #![no_std] 19 | 20 | +extern crate errno; 21 | extern crate platform; 22 | extern crate stdlib; 23 | -extern crate errno; 24 | 25 | use platform::types::*; 26 | use errno::*; 27 | @@ -94,10 +94,10 @@ pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char { 28 | 29 | #[no_mangle] 30 | pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char { 31 | - // the "+ 1" is to account for the NUL byte 32 | - let len = strnlen(s1, size) + 1; 33 | + let len = strnlen(s1, size); 34 | 35 | - let buffer = stdlib::malloc(len) as *mut c_char; 36 | + // the "+ 1" is to account for the NUL byte 37 | + let buffer = stdlib::malloc(len + 1) as *mut c_char; 38 | if buffer.is_null() { 39 | platform::errno = Errno::ENOMEM as c_int; 40 | } else { 41 | @@ -105,6 +105,7 @@ pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char 42 | for i in 0..len as isize { 43 | *buffer.offset(i) = *s1.offset(i); 44 | } 45 | + *buffer.offset(len as isize) = 0; 46 | } 47 | 48 | buffer 49 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/925d9f6bbfeb8c764d0ea32911bb1edbf2716953: -------------------------------------------------------------------------------- 1 | diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs 2 | index e97aebd..8ed46f1 100644 3 | --- a/src/header/stdio/mod.rs 4 | +++ b/src/header/stdio/mod.rs 5 | @@ -251,8 +251,24 @@ pub unsafe extern "C" fn ferror(stream: *mut FILE) -> c_int { 6 | /// itself. 7 | #[no_mangle] 8 | pub unsafe extern "C" fn fflush(stream: *mut FILE) -> c_int { 9 | - let mut stream = (*stream).lock(); 10 | - stream.flush().is_err() as c_int 11 | + if stream.is_null() { 12 | + //TODO: flush all files! 13 | + 14 | + if fflush(stdout) != 0 { 15 | + return EOF; 16 | + } 17 | + 18 | + if fflush(stderr) != 0 { 19 | + return EOF; 20 | + } 21 | + } else { 22 | + let mut stream = (*stream).lock(); 23 | + if stream.flush().is_err() { 24 | + return EOF; 25 | + } 26 | + } 27 | + 28 | + 0 29 | } 30 | 31 | /// Get a single char from a stream 32 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/de429a8df69b5b588ba7527f20d21548c797d14a: -------------------------------------------------------------------------------- 1 | diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs 2 | index eaf0de9..106cdd9 100644 3 | --- a/src/platform/redox/mod.rs 4 | +++ b/src/platform/redox/mod.rs 5 | @@ -411,6 +411,9 @@ impl Pal for Sys { 6 | } 7 | 8 | fn getdents(fd: c_int, mut dirents: *mut dirent, max_bytes: usize) -> c_int { 9 | + //TODO: rewrite this code. Originally the *dirents = dirent { ... } stuff below caused 10 | + // massive issues. This has been hacked around, but it still isn't perfect 11 | + 12 | // Get initial reading position 13 | let mut read = match syscall::lseek(fd as usize, 0, syscall::SEEK_CUR) { 14 | Ok(pos) => pos as isize, 15 | @@ -429,15 +432,16 @@ impl Pal for Sys { 16 | name[*i] = 0; 17 | } 18 | // Get size: full size - unused bytes 19 | - let size = mem::size_of::() - name.len().saturating_sub(*i + 1); 20 | - if *written + size > max_bytes { 21 | + if *written + mem::size_of::() > max_bytes { 22 | // Seek back to after last read entry and return 23 | match syscall::lseek(fd as usize, read, syscall::SEEK_SET) { 24 | Ok(_) => return Some(*written as c_int), 25 | Err(err) => return Some(-err.errno), 26 | } 27 | } 28 | + let size = mem::size_of::() - name.len().saturating_sub(*i + 1); 29 | unsafe { 30 | + //This is the offending code mentioned above 31 | *dirents = dirent { 32 | d_ino: 0, 33 | d_off: read as off_t, 34 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/f661d5d1c099e78ff26f0fb4754d40302bd00e19: -------------------------------------------------------------------------------- 1 | diff --git a/src/header/stdio/helpers.rs b/src/header/stdio/helpers.rs 2 | index 7f5bcad..b7dc4c0 100644 3 | --- a/src/header/stdio/helpers.rs 4 | +++ b/src/header/stdio/helpers.rs 5 | @@ -1,4 +1,4 @@ 6 | -use core::mem; 7 | +use core::{mem, ptr}; 8 | use core::sync::atomic::AtomicBool; 9 | 10 | use header::errno; 11 | @@ -67,14 +67,16 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> Option<*mut FILE> { 12 | if f.is_null() { 13 | None 14 | } else { 15 | - (*f).flags = flags; 16 | - (*f).read = None; 17 | - (*f).write = None; 18 | - (*f).fd = fd; 19 | - (*f).buf = vec![0u8; BUFSIZ + UNGET]; 20 | - (*f).buf_char = -1; 21 | - (*f).unget = UNGET; 22 | - (*f).lock = AtomicBool::new(false); 23 | + ptr::write(f, FILE { 24 | + flags: flags, 25 | + read: None, 26 | + write: None, 27 | + fd: fd, 28 | + buf: vec![0u8; BUFSIZ + UNGET], 29 | + buf_char: -1, 30 | + unget: UNGET, 31 | + lock: AtomicBool::new(false) 32 | + }); 33 | Some(f) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/redox/redox-pull#680: -------------------------------------------------------------------------------- 1 | diff --git a/kernel/arch/context.rs b/kernel/arch/context.rs 2 | index af6bc589..1d94f9eb 100644 3 | --- a/kernel/arch/context.rs 4 | +++ b/kernel/arch/context.rs 5 | @@ -533,10 +533,23 @@ impl ContextZone { 6 | /// Check permission of segment, if inside of mapped memory 7 | pub fn permission(&self, ptr: usize, len: usize, writeable: bool) -> bool { 8 | for mem in self.memory.iter() { 9 | - if ptr >= mem.virtual_address && ptr + len <= mem.virtual_address + mem.virtual_size { 10 | - if mem.writeable || ! writeable { 11 | - return true; 12 | - } 13 | + if ptr < mem.virtual_address { 14 | + continue; 15 | + } 16 | + let end = mem.virtual_address + mem.virtual_size; // Presumably guaranteed not to overflow by construction 17 | + if ptr < mem.virtual_address { 18 | + continue; 19 | + } 20 | + if ptr >= end { 21 | + continue; 22 | + } 23 | + let max_len = end - ptr; // Guaranteed not to overflow by preceding check 24 | + if len > max_len { 25 | + continue; 26 | + } 27 | + 28 | + if mem.writeable || ! writeable { 29 | + return true; 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/servo/275d4561187bf2c4cc940c4a7ae3b6215e06e39b: -------------------------------------------------------------------------------- 1 | diff --git a/src/servo/text/font.rs b/src/servo/text/font.rs 2 | index a7871bf7a0..2e2e3d08f8 100644 3 | --- a/src/servo/text/font.rs 4 | +++ b/src/servo/text/font.rs 5 | @@ -33,7 +33,7 @@ impl Font { 6 | } 7 | } 8 | 9 | -fn Font(fontbuf: ~[u8], native_font: NativeFont) -> Font { 10 | +fn Font(fontbuf: ~[u8], +native_font: NativeFont) -> Font { 11 | Font { 12 | fontbuf : @fontbuf, 13 | native_font : native_font, 14 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/servo/2fb6cc6f4d2e6ea662c781b65bcafff3221461e1: -------------------------------------------------------------------------------- 1 | diff --git a/ports/libsimpleservo/capi/src/lib.rs b/ports/libsimpleservo/capi/src/lib.rs 2 | index 50af7a4d28..b080218492 100644 3 | --- a/ports/libsimpleservo/capi/src/lib.rs 4 | +++ b/ports/libsimpleservo/capi/src/lib.rs 5 | @@ -75,13 +75,16 @@ fn init( 6 | ) { 7 | crate::env_logger::init(); 8 | 9 | - let args = unsafe { CStr::from_ptr(opts.args) }; 10 | - let args = args 11 | - .to_str() 12 | - .unwrap_or("") 13 | - .split(' ') 14 | - .map(|s| s.to_owned()) 15 | - .collect(); 16 | + let args = if !opts.args.is_null() { 17 | + let args = unsafe { CStr::from_ptr(opts.args) }; 18 | + args.to_str() 19 | + .unwrap_or("") 20 | + .split(' ') 21 | + .map(|s| s.to_owned()) 22 | + .collect() 23 | + } else { 24 | + vec![] 25 | + }; 26 | 27 | let url = unsafe { CStr::from_ptr(opts.url) }; 28 | let url = url.to_str().map(|s| s.to_string()).ok(); 29 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/servo/4d76e7570ed410c5630699f55ac3e8de858cb052: -------------------------------------------------------------------------------- 1 | diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs 2 | index e2716bfca8..53da705f9c 100644 3 | --- a/src/components/script/dom/node.rs 4 | +++ b/src/components/script/dom/node.rs 5 | @@ -223,6 +223,10 @@ impl<'self, View> AbstractNode { 6 | /// Sets the layout data, unsafely casting the type as layout wishes. Only layout is allowed 7 | /// to call this. This is wildly unsafe and is therefore marked as such. 8 | pub unsafe fn unsafe_set_layout_data(self, data: @mut T) { 9 | + // Don't decrement the refcount on data, since we're giving it to the 10 | + // base structure. 11 | + cast::forget(data); 12 | + 13 | do self.with_mut_base |base| { 14 | base.layout_data = Some(transmute(data)) 15 | } 16 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/servo/6c6d070dab43d96ba5724d3e5007025c56ff290e: -------------------------------------------------------------------------------- 1 | diff --git a/src/servo/dom/bindings/proxyhandler.rs b/src/servo/dom/bindings/proxyhandler.rs 2 | index c77e5ec952..f073f54d8c 100644 3 | --- a/src/servo/dom/bindings/proxyhandler.rs 4 | +++ b/src/servo/dom/bindings/proxyhandler.rs 5 | @@ -62,7 +62,7 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString { 6 | unsafe { 7 | let name = str::raw::from_buf(className as *u8); 8 | let nchars = "[object ]".len() + name.len(); 9 | - let chars: *mut jschar = cast::transmute(JS_malloc(cx, nchars as u64 * (size_of::() as u64))); 10 | + let chars: *mut jschar = cast::transmute(JS_malloc(cx, (nchars + 1) as u64 * (size_of::() as u64))); 11 | if chars.is_null() { 12 | return ptr::null(); 13 | } 14 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/servo/865e81749a6530a02f608dddae154b7b0bef827e: -------------------------------------------------------------------------------- 1 | diff --git a/components/gfx/platform/freetype/font_context.rs b/components/gfx/platform/freetype/font_context.rs 2 | index 8456e2cade..f4a0745eb2 100644 3 | --- a/components/gfx/platform/freetype/font_context.rs 4 | +++ b/components/gfx/platform/freetype/font_context.rs 5 | @@ -51,13 +51,13 @@ extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) { 6 | } 7 | } 8 | 9 | -extern fn ft_realloc(mem: FT_Memory, old_size: c_long, new_req_size: c_long, 10 | +extern fn ft_realloc(mem: FT_Memory, _old_size: c_long, new_req_size: c_long, 11 | old_ptr: *mut c_void) -> *mut c_void { 12 | let old_actual_size; 13 | let mut vec; 14 | unsafe { 15 | old_actual_size = usable_size(old_ptr as *const _); 16 | - let old_size = old_size as usize; 17 | + let old_size = old_actual_size as usize; 18 | vec = Vec::::from_raw_parts(old_ptr as *mut u8, old_size, old_size); 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/servo/9b92d0bc3a590697b2f17ef16b2dfeee057a57f2: -------------------------------------------------------------------------------- 1 | diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs 2 | index 87e69aabef..f0c7f2446d 100644 3 | --- a/ports/geckolib/glue.rs 4 | +++ b/ports/geckolib/glue.rs 5 | @@ -355,10 +355,12 @@ pub extern "C" fn Servo_GetComputedValuesForPseudoElement(parent_style: *mut Ser 6 | pub extern "C" fn Servo_InheritComputedValues(parent_style: *mut ServoComputedValues) 7 | -> *mut ServoComputedValues { 8 | type Helpers = ArcHelpers; 9 | - Helpers::with(parent_style, |parent| { 10 | - let style = ComputedValues::inherit_from(parent); 11 | - Helpers::from(style) 12 | - }) 13 | + let style = if parent_style.is_null() { 14 | + Arc::new(ComputedValues::initial_values().clone()) 15 | + } else { 16 | + Helpers::with(parent_style, ComputedValues::inherit_from) 17 | + }; 18 | + Helpers::from(style) 19 | } 20 | 21 | #[no_mangle] 22 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/servo/f298089f0216f50b64d1197b36075f606566e609: -------------------------------------------------------------------------------- 1 | diff --git a/components/gfx/platform/macos/font_template.rs b/components/gfx/platform/macos/font_template.rs 2 | index c6eb84d974..0286573399 100644 3 | --- a/components/gfx/platform/macos/font_template.rs 4 | +++ b/components/gfx/platform/macos/font_template.rs 5 | @@ -16,6 +16,7 @@ use std::borrow::ToOwned; 6 | pub struct FontTemplateData { 7 | pub ctfont: Option, 8 | pub identifier: String, 9 | + pub font_data: Option> 10 | } 11 | 12 | unsafe impl Send for FontTemplateData {} 13 | @@ -24,7 +25,7 @@ unsafe impl Sync for FontTemplateData {} 14 | impl FontTemplateData { 15 | pub fn new(identifier: &str, font_data: Option>) -> FontTemplateData { 16 | let ctfont = match font_data { 17 | - Some(bytes) => { 18 | + Some(ref bytes) => { 19 | let fontprov = CGDataProvider::from_buffer(bytes.as_slice()); 20 | let cgfont_result = CGFont::from_data_provider(fontprov); 21 | match cgfont_result { 22 | @@ -40,6 +41,7 @@ impl FontTemplateData { 23 | FontTemplateData { 24 | ctfont: ctfont, 25 | identifier: identifier.to_owned(), 26 | + font_data: font_data 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/tock/43760ae9137db07ea2a79cd6b551bda53e6fd7d6: -------------------------------------------------------------------------------- 1 | diff --git a/kernel/src/process.rs b/kernel/src/process.rs 2 | index f36e9f7c..55f8c03f 100644 3 | --- a/kernel/src/process.rs 4 | +++ b/kernel/src/process.rs 5 | @@ -8,7 +8,7 @@ use core::{mem, ptr, slice, str}; 6 | use core::cell::Cell; 7 | use core::fmt::Write; 8 | use core::intrinsics; 9 | -use core::ptr::{read_volatile, write_volatile}; 10 | +use core::ptr::{read_volatile, write_volatile, write}; 11 | 12 | use platform::mpu; 13 | use returncode::ReturnCode; 14 | @@ -1142,7 +1142,11 @@ impl<'a> Process<'a> { 15 | if (*ctr_ptr).is_null() { 16 | self.alloc(mem::size_of::()).map(|root_arr| { 17 | let root_ptr = root_arr.as_mut_ptr() as *mut T; 18 | - *root_ptr = Default::default(); 19 | + // Initialize the container contents using ptr::write, to 20 | + // ensure that we don't try to drop the contents of 21 | + // uninitialized memory when T implements Drop. 22 | + write(root_ptr, Default::default()); 23 | + // Record the location in the container pointer. 24 | write_volatile(ctr_ptr, root_ptr); 25 | root_ptr 26 | }) 27 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/tock/87ef34b31890ee8c3d405b45924492d76376f3fa: -------------------------------------------------------------------------------- 1 | diff --git a/kernel/src/grant.rs b/kernel/src/grant.rs 2 | index e25c1447..981b8f40 100644 3 | --- a/kernel/src/grant.rs 4 | +++ b/kernel/src/grant.rs 5 | @@ -3,7 +3,7 @@ 6 | use core::marker::PhantomData; 7 | use core::mem::size_of; 8 | use core::ops::{Deref, DerefMut}; 9 | -use core::ptr::Unique; 10 | +use core::ptr::{write, Unique}; 11 | 12 | use callback::AppId; 13 | use process::Error; 14 | @@ -90,9 +90,11 @@ impl Allocator { 15 | process 16 | .alloc(size_of::()) 17 | .map_or(Err(Error::OutOfMemory), |arr| { 18 | - let mut owned = Owned::new(arr.as_mut_ptr() as *mut T, self.appid); 19 | - *owned = data; 20 | - Ok(owned) 21 | + let ptr = arr.as_mut_ptr() as *mut T; 22 | + // We use `ptr::write` to avoid `Drop`ping the uninitialized memory in 23 | + // case `T` implements the `Drop` trait. 24 | + write(ptr, data); 25 | + Ok(Owned::new(ptr, self.appid)) 26 | }) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/memory-bugs/tock/bb5c6f6410a16a404778d12d21d4e0f78ef50943: -------------------------------------------------------------------------------- 1 | diff --git a/src/process/process.rs b/src/process/process.rs 2 | index 60b8ef87..70e440f8 100644 3 | --- a/src/process/process.rs 4 | +++ b/src/process/process.rs 5 | @@ -159,7 +159,7 @@ impl<'a> Process<'a> { 6 | // Entry point is offset from app code 7 | let init_fn = start_addr as usize + load_info.entry_loc; 8 | 9 | - let heap_start = exposed_memory_start.offset(load_info.init_data_size as isize); 10 | + let heap_start = exposed_memory_start.offset(load_info.bss_end_offset as isize); 11 | 12 | self.callbacks.enqueue(Callback { 13 | pc: init_fn as usize, 14 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/README.md: -------------------------------------------------------------------------------- 1 | # Reproduced Memory Bugs 2 | 3 | This directory contents some memory bugs that we reproduced. To reproduce the corresponding 4 | bug, go to the root directory of each one. And then run it by 5 | 6 | ``cargo run`` 7 | 8 | Some bugs require specific version of external library or release build to reproduce. Please read the comment 9 | `How to reproduce this bug` in their `main.rs`. -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/CVE-2018-1000657/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "CVE-2018-1000657" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/CVE-2018-1000810/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "CVE-2018-1000810" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2017-0004/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2017-0004/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "RUSTSEC-2017-0004" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2017-0004/src/main.rs: -------------------------------------------------------------------------------- 1 | /** 2 | * How to reproduce this bug: 3 | * - This bug need to be reproduced in release build. 4 | * - cargo run --release 5 | */ 6 | 7 | fn mock_encode_size_buggy(bytes_len: usize) -> usize { 8 | let rem = bytes_len % 3; 9 | 10 | let complete_input_chunks = bytes_len / 3; 11 | let complete_output_chars = complete_input_chunks * 4; 12 | let printing_output_chars = if rem == 0 { 13 | complete_output_chars 14 | } else { 15 | complete_output_chars + 4 16 | }; 17 | let line_ending_output_chars = printing_output_chars * 2; 18 | 19 | return printing_output_chars + line_ending_output_chars; 20 | } 21 | 22 | fn mock_encoded_size_patch(bytes_len: usize) -> Option { 23 | let printing_output_chars = bytes_len 24 | .checked_add(2) 25 | .map(|x| x / 3) 26 | .and_then(|x| x.checked_mul(4)); 27 | 28 | let line_ending_output_chars = printing_output_chars.and_then(|y| y.checked_mul(2)); 29 | 30 | printing_output_chars.and_then(|x| 31 | line_ending_output_chars.and_then(|y| x.checked_add(y))) 32 | } 33 | 34 | 35 | fn main() { 36 | let bytes_len = 1 << 63; 37 | let mut ret = mock_encode_size_buggy(bytes_len); 38 | println!("buggy ret: {}", ret); 39 | let resv_size = match mock_encoded_size_patch(bytes_len) { 40 | Some(ret) => { 41 | println!("patch ret: {}", ret); 42 | }, 43 | None => panic!("integer overflow when calculating buffer size"), 44 | }; 45 | 46 | // If you use the ret as a hint to allocate memory, it can lead to memory corruption 47 | } 48 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0003/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0003/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "RUSTSEC-2018-0003" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | smallvec = { path = "../rust-smallvec" } 9 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0008/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0008/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "RUSTSEC-2018-0008" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | slice-deque = { path = "./slice_deque" } 9 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0008/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate slice_deque; 2 | 3 | use slice_deque::SliceDeque; 4 | 5 | /** 6 | * How to reproduce this bug 7 | * This bug need to be reproduced with release build 8 | * - Get slice_deque source code - git clone https://github.com/gnzlbg/slice_deque 9 | * - git checkout 57b1a84 10 | * - compile this package and run 11 | */ 12 | const VALUE: [i32; 3] = [45, 46, 47]; 13 | 14 | fn main() { 15 | let mut v = SliceDeque::new(); 16 | // construct the slice that can trigger the bug 17 | v.push_back(VALUE); 18 | v.push_back(VALUE); 19 | v.push_back(VALUE); 20 | v.push_front(VALUE); 21 | 22 | // trigger the bug 23 | let first = v.pop_front().unwrap(); 24 | println!("first: {:?}", first); 25 | let second = v.pop_front().unwrap(); 26 | println!("value_second: {:?}", second); 27 | } 28 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0009/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0009/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "RUSTSEC-2018-0009" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | crossbeam = { path = "../crossbeam" } 9 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0009/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate crossbeam; 2 | 3 | use crossbeam::queue::MsQueue; 4 | 5 | #[derive(Debug)] 6 | struct Printer(Vec); 7 | 8 | impl Drop for Printer { 9 | fn drop(&mut self) { 10 | println!("Dropping: {:?}", self.0); 11 | } 12 | } 13 | 14 | /** 15 | * How to reproduce 16 | * - git clone https://github.com/crossbeam-rs/crossbeam 17 | * - git checkout v0.4.0 (buggy version) 18 | * - git checkout v0.4.1 (fix version) 19 | * - Set the right path of crossbeam in Cargo.toml 20 | * - run this program: cargo run 21 | */ 22 | fn main() { 23 | let queue: MsQueue = MsQueue::new(); 24 | 25 | // 200 loop is enough to trigger GC to work. 26 | for i in 0..200 { 27 | queue.push(Printer(vec![i])); 28 | let item = queue.pop(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0010/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0010/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "RUSTSEC-2018-0010" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/cve/RUSTSEC-2018-0010/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::ptr; 2 | use std::vec::Vec; 3 | 4 | #[derive(Debug)] 5 | struct MockMemBioSlice { 6 | v: Vec 7 | } 8 | 9 | impl MockMemBioSlice { 10 | fn new(data: &[u8]) -> MockMemBioSlice { 11 | let ret = MockMemBioSlice { 12 | v: data.to_vec() 13 | }; 14 | ret 15 | } 16 | 17 | fn as_ptr(&self) -> *const u8 { 18 | self.v.as_ptr() 19 | } 20 | } 21 | 22 | fn sign_bug(data: Option<&[u8]>) -> Result<(), ()> { 23 | unsafe { 24 | let data_bio_ptr = match data { 25 | Some(data) => MockMemBioSlice::new(data).as_ptr(), 26 | None => ptr::null() 27 | }; 28 | println!("data_bio_ptr: {}", *data_bio_ptr); 29 | Ok(()) 30 | } 31 | } 32 | 33 | fn sign_patch(data: Option<&[u8]>) -> Result<(), ()> { 34 | unsafe { 35 | let data_bio = match data { 36 | Some(data) => { 37 | Some(MockMemBioSlice::new(data)) 38 | }, 39 | None => None 40 | 41 | }; 42 | let data_bio_ptr = data_bio.as_ref().map_or(ptr::null(), |p| p.as_ptr()); 43 | println!("data_bio_ptr: {}", *data_bio_ptr); 44 | Ok(()) 45 | } 46 | } 47 | 48 | fn main() { 49 | let v: Vec = vec![1, 2, 3]; 50 | let data = Some(v.as_slice()); 51 | sign_bug(data); 52 | // sign_patch(data); 53 | } 54 | 55 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/servo/1/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/servo/1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "memory-corruption-1" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/servo/4/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/servo/4/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "memory-corruption-2" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | libc = "0.1" 9 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/servo/4/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate libc; 2 | 3 | use libc::c_char; 4 | use std::ffi::CStr; 5 | use std::str; 6 | use std::ptr; 7 | 8 | unsafe fn c_str_to_string(s: *const c_char) -> String { 9 | str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap().to_owned() 10 | } 11 | 12 | 13 | fn main() { 14 | unsafe { 15 | c_str_to_string(ptr::null() as *const c_char); 16 | // let s = String::from("sss"); 17 | // c_str_to_string(s.as_ptr() as *const c_char); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/tock/1/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /section-5-memory-safety-issues/reproduced-bugs/tock/1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "random-drop-1" 3 | version = "0.1.0" 4 | authors = ["Yilun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | libc = "0.2" -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/README.md: -------------------------------------------------------------------------------- 1 | # Reproduced concurrency bugs 2 | 3 | ## Build and Run 4 | 5 | ``` 6 | cd BUG_DIR 7 | cargo run 8 | ``` 9 | ## Result 10 | 11 | The description of the bugs are in README.md under each directory. 12 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/deadlock-test/README.md: -------------------------------------------------------------------------------- 1 | # dead lock test 2 | 3 | ## 1. Build & Run 4 | 5 | ``` 6 | rustc deadlock1.rs 7 | ./deadlock1 8 | ``` 9 | So it is with other files. 10 | 11 | ## 2. Results 12 | 13 | deadlock1 and deadlock2 will cause blocking. 14 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/deadlock-test/deadlock1.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex}; 2 | 3 | fn main() { 4 | let data = Arc::new(Mutex::new(0)); 5 | 6 | { 7 | let mut num = data.lock().unwrap(); 8 | 9 | *num = 10; 10 | 11 | let num1 = data.lock().unwrap(); 12 | 13 | println!("{}", num1); 14 | 15 | } 16 | 17 | 18 | let num = data.lock().unwrap(); 19 | 20 | assert!(*num == 10); 21 | } -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/deadlock-test/deadlock2.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex}; 2 | 3 | fn main() { 4 | let data = Arc::new(Mutex::new(0)); 5 | 6 | { 7 | let mut num = data.lock().unwrap(); 8 | 9 | *num = 10; 10 | 11 | *data.lock().unwrap() = 20; 12 | 13 | println!("{}", num); 14 | 15 | } 16 | 17 | 18 | let num = data.lock().unwrap(); 19 | 20 | assert!(*num == 10); 21 | } -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/deadlock-test/non-deadlock1.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex}; 2 | 3 | fn main() { 4 | let data = Arc::new(Mutex::new(0)); 5 | 6 | { 7 | let mut num = data.lock().unwrap(); 8 | 9 | *num = 10 10 | 11 | } 12 | 13 | 14 | let num = data.lock().unwrap(); 15 | 16 | assert!(*num == 10); 17 | } -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/deadlock-test/non-deadlock2.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex}; 2 | 3 | fn main() { 4 | let data = Arc::new(Mutex::new(0)); 5 | 6 | { 7 | let _ = data.lock().unwrap(); 8 | 9 | let _ = data.lock().unwrap(); 10 | 11 | } 12 | 13 | 14 | let num = data.lock().unwrap(); 15 | 16 | assert!(*num == 0); 17 | } -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/deadlock-test/non-deadlock3.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex}; 2 | 3 | fn main() { 4 | let data = Arc::new(Mutex::new(0)); 5 | 6 | { 7 | 8 | *data.lock().unwrap() = 20; 9 | 10 | let num = data.lock().unwrap(); 11 | 12 | println!("{}", num); 13 | 14 | } 15 | 16 | 17 | let num = data.lock().unwrap(); 18 | 19 | assert!(*num == 20); 20 | } -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/ethereum-blocking-3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ethereum-blocking-3" 3 | version = "0.1.0" 4 | authors = ["BurtonQin "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/ethereum-blocking-3/README.md: -------------------------------------------------------------------------------- 1 | #parity-ethereum-9952 2 | 3 | This is a blocking bug caused by acquiring two locks in conflicting orders. 4 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/ethereum-blocking-3/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::sync::RwLock; 2 | use std::thread; 3 | use std::sync::Arc; 4 | use std::time; 5 | 6 | struct BlockChain { 7 | best_block: RwLock<()>, 8 | best_ancient_block: RwLock<()>, 9 | } 10 | 11 | impl BlockChain { 12 | fn new() -> Self { 13 | BlockChain { 14 | best_block: RwLock::new(()), 15 | best_ancient_block: RwLock::new(()), 16 | } 17 | } 18 | 19 | fn chain_info(&self) { 20 | let best_block = self.best_block.read(); 21 | let best_ancient_block = self.best_ancient_block.read(); 22 | } 23 | 24 | fn commit(&self) { 25 | let mut best_ancient_block = self.best_ancient_block.write(); 26 | thread::sleep(time::Duration::from_millis(500)); 27 | let mut best_block = self.best_block.write(); 28 | } 29 | } 30 | 31 | fn main() { 32 | let bc = Arc::new(BlockChain::new()); 33 | let cloned_bc = bc.clone(); 34 | thread::spawn(move || { 35 | cloned_bc.chain_info(); 36 | }); 37 | bc.commit(); 38 | println!("Hello, world!"); 39 | } 40 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/ethereum-blocking-4/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ethereum-blocking-4" 3 | version = "0.1.0" 4 | authors = ["BurtonQin "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | parking_lot = "0.10.0" 11 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/ethereum-blocking-4/README.md: -------------------------------------------------------------------------------- 1 | #parity-ethereum-8977 2 | 3 | [parking_lot::RwLock](https://docs.rs/parking_lot/0.7.1/parking_lot/type.RwLock.html) 4 | 5 | This lock uses a task-fair locking policy which avoids both reader and writer starvation. This means that readers trying to acquire the lock will block if there are writers waiting to acquire the lock. Therefore, attempts to recursively acquire a read lock from the same thread may result in a deadlock. 6 | 7 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/ethereum-blocking-4/src/main.rs: -------------------------------------------------------------------------------- 1 | use parking_lot::RwLock; 2 | use std::sync::Arc; 3 | use std::thread; 4 | use std::time; 5 | 6 | fn main() { 7 | let foo = Arc::new(RwLock::new(1)); 8 | let foo2 = foo.clone(); 9 | 10 | let t = thread::spawn(move || { 11 | thread::sleep(time::Duration::from_millis(500)); 12 | let mut wl = foo2.write(); 13 | *wl = 2; 14 | println!("Write lock {}", *wl); 15 | }); 16 | { 17 | let rl1 = foo.read(); 18 | println!("read lock1 {}", *rl1); 19 | thread::sleep(time::Duration::from_millis(1000)); 20 | let rl2 = foo.read(); 21 | println!("read lock2 {}", *rl2); 22 | } 23 | t.join().unwrap(); 24 | return (); 25 | } 26 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/lazy-static-blocking-1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lazy-static-blocking-1" 3 | version = "0.1.0" 4 | authors = ["BurtonQin "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/lazy-static-blocking-1/README.md: -------------------------------------------------------------------------------- 1 | #lazy-static.rs 2 | 3 | When the input closure of `Once.call_once()` recursively call `Once.call_once()` of the same Once object, 4 | a deadlock or a panic can be triggered. 5 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/lazy-static-blocking-1/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Once; 2 | 3 | static START: Once = Once::new(); 4 | fn main() { 5 | START.call_once(|| { 6 | START.call_once(|| { 7 | println!("deadlock!"); 8 | }); 9 | }); 10 | } -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rayon-449" 3 | version = "0.1.0" 4 | authors = ["linhai.song "] 5 | 6 | [dependencies] 7 | rayon={path="rayon"} 8 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/README.md: -------------------------------------------------------------------------------- 1 | #rayon-f17d745e12511516396f6ba5027a30e88e981bfb 2 | 3 | This is a blocking bug related to missing `Condvar` `notify`. 4 | 5 | The buggy version implements latch using an atomic bool variable (b), a mutex without any shared variable to protect (m), and a conditional variable (v). The blocking functionality inside `Latch.wait()` is achieved through `Condvar.wait()`. Inside `Latch.set()`, `Convar.notify_all()` is called to awake all blocking threads. 6 | 7 | There is a possible interleave, where a thread can miss `Convar.notify_all()` and block for ever (block for a while unnecessarily). 8 | 9 | 10 | run `./install.sh` before `cargo run` 11 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | git clone https://github.com/rayon-rs/rayon.git 4 | cd rayon 5 | git checkout f17d745e12511516396f6ba5027a30e88e981bfb 6 | cd .. 7 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | *~ 4 | TAGS 5 | *.bk 6 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - 1.12.0 4 | - stable 5 | - nightly 6 | os: 7 | - linux 8 | - osx 9 | 10 | # Using 16MB stacks for deep test/debug recursion 11 | env: 12 | global: 13 | - RUST_MIN_STACK=16777216 14 | 15 | matrix: 16 | include: 17 | - rust: stable 18 | env: RUSTFLAGS='--cfg rayon_unstable' 19 | os: linux 20 | - rust: stable 21 | env: RUSTFLAGS='--cfg rayon_unstable' 22 | os: osx 23 | - rust: nightly 24 | env: RUSTFLAGS='--cfg rayon_unstable' 25 | os: linux 26 | - rust: nightly 27 | env: RUSTFLAGS='--cfg rayon_unstable' 28 | os: osx 29 | 30 | script: 31 | - cargo build 32 | - | 33 | if [ $TRAVIS_RUST_VERSION == nightly ]; then 34 | cargo test && 35 | cargo test -p rayon-core && 36 | cargo test -p rayon-demo && 37 | ./ci/highlander.sh 38 | fi 39 | - | 40 | if [ -n "$RUSTFLAGS" ]; then 41 | cargo build -p rayon-futures && 42 | if [ $TRAVIS_RUST_VERSION == nightly ]; then 43 | cargo test -p rayon-futures 44 | fi 45 | fi 46 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rayon" 3 | # Reminder to update html_rool_url in lib.rs when updating version 4 | version = "0.8.2" 5 | authors = ["Niko Matsakis ", 6 | "Josh Stone "] 7 | description = "Simple work-stealing parallelism for Rust" 8 | license = "Apache-2.0/MIT" 9 | repository = "https://github.com/nikomatsakis/rayon" 10 | documentation = "https://docs.rs/rayon/" 11 | 12 | [workspace] 13 | members = ["rayon-demo", "rayon-core", "rayon-futures"] 14 | exclude = ["ci"] 15 | 16 | [dependencies] 17 | rayon-core = { version = "1.2", path = "rayon-core" } 18 | 19 | # This is a public dependency! 20 | [dependencies.either] 21 | version = "1.0" 22 | default-features = false 23 | 24 | [dev-dependencies] 25 | compiletest_rs = "0.2.1" 26 | docopt = "0.7" 27 | futures = "0.1.7" 28 | rand = "0.3" 29 | rustc-serialize = "0.3" 30 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/ci/alt-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alt-core" 3 | version = "0.0.0" 4 | authors = ["Josh Stone "] 5 | links = "rayon-core" 6 | build = "build.rs" 7 | publish = false 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/ci/alt-core/build.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/ci/alt-core/src/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/system-pclub/rust-study/403b06f30809d10d2bb066d2fbcd33caf3446d17/section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/ci/alt-core/src/lib.rs -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/ci/highlander.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | echo "INFO: There Can Be Only One!" >&2 6 | 7 | if cargo build --manifest-path "$DIR/highlander/Cargo.toml"; then 8 | echo "ERROR: we built with multiple rayon-core!" >&2 9 | exit 1 10 | fi 11 | 12 | echo "PASS: using multiple rayon-core failed." >&2 13 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/ci/highlander/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Josh Stone "] 3 | name = "highlander" 4 | description = "There Can Be Only One" 5 | version = "0.0.0" 6 | publish = false 7 | 8 | [dependencies] 9 | 10 | [dependencies.alt-core] 11 | optional = false 12 | path = "../alt-core" 13 | 14 | [dependencies.rayon-core] 15 | optional = false 16 | path = "../../rayon-core" 17 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/ci/highlander/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/examples/README.md: -------------------------------------------------------------------------------- 1 | We use this directory for interactive tests that can't be run in an 2 | automatic fashion. For examples of how to use Rayon, or benchmarks, 3 | see `rayon-demo`. 4 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rayon-core" 3 | version = "1.2.2" # reminder to update html_root_url attribute 4 | authors = ["Niko Matsakis ", 5 | "Josh Stone "] 6 | description = "Core APIs for Rayon" 7 | license = "Apache-2.0/MIT" 8 | repository = "https://github.com/nikomatsakis/rayon" 9 | documentation = "https://docs.rs/rayon/" 10 | links = "rayon-core" 11 | build = "build.rs" 12 | 13 | [dependencies] 14 | rand = "0.3" 15 | num_cpus = "1.2" 16 | coco = "0.1.1" 17 | libc = "0.2.16" 18 | lazy_static = "0.2.2" 19 | 20 | [dev-dependencies] 21 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-core/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-core/build.rs: -------------------------------------------------------------------------------- 1 | // We need a build script to use `link = "rayon-core"`. But we're not 2 | // *actually* linking to anything, just making sure that we're the only 3 | // rayon-core in use. 4 | fn main() { 5 | // we don't need to rebuild for anything else 6 | println!("cargo:rerun-if-changed=build.rs"); 7 | } 8 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-core/src/internal/mod.rs: -------------------------------------------------------------------------------- 1 | //! The internal directory contains internal APIs not meant to be 2 | //! exposed to "end-users" of Rayon, but rather which are useful for 3 | //! constructing abstractions. 4 | 5 | pub mod task; 6 | pub mod worker; 7 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-core/src/unwind.rs: -------------------------------------------------------------------------------- 1 | //! Package up unwind recovery. Note that if you are in some sensitive 2 | //! place, you can use the `AbortIfPanic` helper to protect against 3 | //! accidental panics in the rayon code itself. 4 | 5 | use libc; 6 | use std::any::Any; 7 | use std::panic::{self, AssertUnwindSafe}; 8 | use std::io::stderr; 9 | use std::io::prelude::*; 10 | use std::thread; 11 | 12 | /// Executes `f` and captures any panic, translating that panic into a 13 | /// `Err` result. The assumption is that any panic will be propagated 14 | /// later with `resume_unwinding`, and hence `f` can be treated as 15 | /// exception safe. 16 | pub fn halt_unwinding(func: F) -> thread::Result 17 | where F: FnOnce() -> R 18 | { 19 | panic::catch_unwind(AssertUnwindSafe(func)) 20 | } 21 | 22 | pub fn resume_unwinding(payload: Box) -> ! { 23 | panic::resume_unwind(payload) 24 | } 25 | 26 | pub struct AbortIfPanic; 27 | 28 | impl Drop for AbortIfPanic { 29 | fn drop(&mut self) { 30 | unsafe { 31 | let _ = writeln!(&mut stderr(), "Rayon: detected unexpected panic; aborting"); 32 | libc::abort(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-core/src/util.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | pub fn leak(v: T) -> &'static T { 4 | unsafe { 5 | let b = Box::new(v); 6 | let p: *const T = &*b; 7 | mem::forget(b); // leak our reference, so that `b` is never freed 8 | &*p 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rayon-demo" 3 | version = "0.0.0" 4 | authors = ["Niko Matsakis "] 5 | publish = false 6 | 7 | [dependencies] 8 | rayon = { path = "../" } 9 | cgmath = "0.14" 10 | docopt = "0.7" 11 | glium = "0.17" 12 | rand = "0.3" 13 | rustc-serialize = "0.3" 14 | time = "0.1" 15 | odds = "0.2" 16 | lazy_static = "0.2.1" 17 | fixedbitset = "0.1.5" 18 | regex = "0.2" 19 | 20 | [dev-dependencies] 21 | num = "0.1.30" 22 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/data/README.md: -------------------------------------------------------------------------------- 1 | Data for various benchmarks. All in public domain or otherwise freely 2 | licensed. 3 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/data/tsp/README.md: -------------------------------------------------------------------------------- 1 | Inputs for the Traveling Salesman Problem solver. These are in TSPLIB 2 | format. 3 | 4 | Sources: 5 | 6 | - `dj15.tsp`: derived from `dj38.tsp` 7 | - `dj38.tsp`: 8 | 9 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/data/tsp/dj10.tsp: -------------------------------------------------------------------------------- 1 | NAME: dj10 2 | COMMENT : 10 locations in Djibouti; chosen from dj38.tsp 3 | TYPE: TSP 4 | DIMENSION: 10 5 | EDGE_WEIGHT_TYPE: EUC_2D 6 | NODE_COORD_SECTION 7 | 1 11003.611100 42102.500000 8 | 2 11108.611100 42373.888900 9 | 3 11133.333300 42885.833300 10 | 4 11155.833300 42712.500000 11 | 5 11183.333300 42933.333300 12 | 6 11297.500000 42853.333300 13 | 7 11310.277800 42929.444400 14 | 8 11416.666700 42983.333300 15 | 9 11423.888900 43000.277800 16 | 10 11438.333300 42057.222200 17 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/data/tsp/dj15.tsp: -------------------------------------------------------------------------------- 1 | NAME: dj15 2 | COMMENT : 15 locations in Djibouti; chosen from dj38.tsp 3 | TYPE: TSP 4 | DIMENSION: 15 5 | EDGE_WEIGHT_TYPE: EUC_2D 6 | NODE_COORD_SECTION 7 | 1 11003.611100 42102.500000 8 | 2 11108.611100 42373.888900 9 | 3 11133.333300 42885.833300 10 | 4 11155.833300 42712.500000 11 | 5 11183.333300 42933.333300 12 | 6 11297.500000 42853.333300 13 | 7 11310.277800 42929.444400 14 | 8 11416.666700 42983.333300 15 | 9 11423.888900 43000.277800 16 | 10 11438.333300 42057.222200 17 | 11 11461.111100 43252.777800 18 | 12 11485.555600 43187.222200 19 | 13 11503.055600 42855.277800 20 | 14 11511.388900 42106.388900 21 | 15 11522.222200 42841.944400 22 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/src/life/bench.rs: -------------------------------------------------------------------------------- 1 | use super::Board; 2 | 3 | #[bench] 4 | fn generations(b: &mut ::test::Bencher) { 5 | b.iter(|| super::generations(Board::new(200, 200).random(), 100)); 6 | } 7 | 8 | #[bench] 9 | fn parallel_generations(b: &mut ::test::Bencher) { 10 | b.iter(|| super::parallel_generations(Board::new(200, 200).random(), 100)); 11 | } 12 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/src/matmul/bench.rs: -------------------------------------------------------------------------------- 1 | use test; 2 | 3 | const ROW_SIZE: usize = 256; 4 | 5 | #[bench] 6 | fn bench_matmul_strassen(b: &mut test::Bencher) { 7 | let n = ROW_SIZE * ROW_SIZE; 8 | let x = vec![1f32; n]; 9 | let y = vec![2f32; n]; 10 | let mut z = vec![0f32; n]; 11 | 12 | b.iter(|| { 13 | super::matmul_strassen(&x, &y, &mut z); 14 | }); 15 | } -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/src/mergesort/bench.rs: -------------------------------------------------------------------------------- 1 | use test; 2 | 3 | // Size to use when doing `cargo bench`; extensively tuned to run in 4 | // "not too long" on my laptop -nmatsakis 5 | const BENCH_SIZE: usize = 250_000_000 / 512; 6 | 7 | fn bench_harness(mut f: F, b: &mut test::Bencher) { 8 | let base_vec = super::default_vec(BENCH_SIZE); 9 | let mut sort_vec = vec![]; 10 | b.iter(|| { 11 | sort_vec = base_vec.clone(); 12 | f(&mut sort_vec); 13 | }); 14 | assert!(super::is_sorted(&mut sort_vec)); 15 | } 16 | 17 | #[bench] 18 | fn merge_sort_par_bench(b: &mut test::Bencher) { 19 | bench_harness(super::merge_sort, b); 20 | } 21 | 22 | #[bench] 23 | fn merge_sort_seq_bench(b: &mut test::Bencher) { 24 | bench_harness(super::seq_merge_sort, b); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/src/nbody/bench.rs: -------------------------------------------------------------------------------- 1 | use rand::{SeedableRng, XorShiftRng}; 2 | use test; 3 | 4 | use super::nbody::NBodyBenchmark; 5 | 6 | // Because benchmarks run iteratively, use smaller constants by default: 7 | const BENCH_BODIES: usize = 1000; 8 | 9 | const BENCH_TICKS: usize = 10; 10 | 11 | fn nbody_bench(b: &mut test::Bencher, mut tick: TICK) 12 | where TICK: FnMut(&mut NBodyBenchmark) 13 | { 14 | let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]); 15 | let mut benchmark = NBodyBenchmark::new(BENCH_BODIES, &mut rng); 16 | b.iter(|| { 17 | for _ in 0 .. BENCH_TICKS { 18 | tick(&mut benchmark); 19 | } 20 | }); 21 | } 22 | 23 | #[bench] 24 | fn nbody_seq(b: &mut ::test::Bencher) { 25 | nbody_bench(b, |n| { n.tick_seq(); }); 26 | } 27 | 28 | #[bench] 29 | fn nbody_par(b: &mut ::test::Bencher) { 30 | nbody_bench(b, |n| { n.tick_par(); }); 31 | } 32 | 33 | #[bench] 34 | fn nbody_parreduce(b: &mut ::test::Bencher) { 35 | nbody_bench(b, |n| { n.tick_par_reduce(); }); 36 | } 37 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/src/quicksort/bench.rs: -------------------------------------------------------------------------------- 1 | use test; 2 | 3 | use super::{Parallel, Sequential}; 4 | 5 | // Size to use when doing `cargo bench`; extensively tuned to run in 6 | // "not too long" on my laptop -nmatsakis 7 | const BENCH_SIZE: usize = 250_000_000 / 512; 8 | 9 | fn bench_harness(mut f: F, b: &mut test::Bencher) { 10 | let base_vec = super::default_vec(BENCH_SIZE); 11 | let mut sort_vec = vec![]; 12 | b.iter(|| { 13 | sort_vec = base_vec.clone(); 14 | f(&mut sort_vec); 15 | }); 16 | assert!(super::is_sorted(&mut sort_vec)); 17 | } 18 | 19 | #[bench] 20 | fn quick_sort_par_bench(b: &mut test::Bencher) { 21 | bench_harness(super::quick_sort::, b); 22 | } 23 | 24 | #[bench] 25 | fn quick_sort_seq_bench(b: &mut test::Bencher) { 26 | bench_harness(super::quick_sort::, b); 27 | } 28 | 29 | #[bench] 30 | fn quick_sort_splitter(b: &mut test::Bencher) { 31 | use rayon::iter::ParallelIterator; 32 | 33 | bench_harness(|vec| { 34 | ::rayon::split(vec, |vec| { 35 | if vec.len() > 1 { 36 | let mid = super::partition(vec); 37 | let (left, right) = vec.split_at_mut(mid); 38 | (left, Some(right)) 39 | } else { 40 | (vec, None) 41 | } 42 | }).for_each(super::quick_sort::) 43 | }, b); 44 | } 45 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/src/sieve/bench.rs: -------------------------------------------------------------------------------- 1 | use test; 2 | 3 | use super::NUM_PRIMES; 4 | 5 | const MAGNITUDE: usize = 7; 6 | 7 | fn sieve_bench(b: &mut test::Bencher, mut tick: TICK) 8 | where TICK: FnMut(usize) -> Vec 9 | { 10 | let mut result = vec![]; 11 | b.iter(|| result = tick(super::max(MAGNITUDE))); 12 | let num_primes = 1 + result.into_iter().filter(|&b| b).count(); 13 | assert_eq!(num_primes, NUM_PRIMES[MAGNITUDE]); 14 | } 15 | 16 | #[bench] 17 | fn sieve_serial(b: &mut ::test::Bencher) { 18 | sieve_bench(b, super::sieve_serial); 19 | } 20 | 21 | #[bench] 22 | fn sieve_chunks(b: &mut ::test::Bencher) { 23 | sieve_bench(b, super::sieve_chunks); 24 | } 25 | 26 | #[bench] 27 | fn sieve_parallel(b: &mut ::test::Bencher) { 28 | sieve_bench(b, super::sieve_parallel); 29 | } 30 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/src/str_split.rs: -------------------------------------------------------------------------------- 1 | //! Some microbenchmarks for splitting strings 2 | 3 | use rayon::prelude::*; 4 | use rand::{Rng, SeedableRng, XorShiftRng}; 5 | use test::Bencher; 6 | 7 | lazy_static! { 8 | static ref HAYSTACK: String = { 9 | let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]); 10 | let mut bytes: Vec = "abcdefg ".bytes().cycle().take(1_000_000).collect(); 11 | rng.shuffle(&mut bytes); 12 | String::from_utf8(bytes).unwrap() 13 | }; 14 | 15 | static ref COUNT: usize = { 16 | HAYSTACK.split(' ').count() 17 | }; 18 | } 19 | 20 | fn get_string_count() -> (&'static str, usize) { 21 | (&HAYSTACK, *COUNT) 22 | } 23 | 24 | #[bench] 25 | fn parallel_space_char(b: &mut Bencher) { 26 | let (string, count) = get_string_count(); 27 | b.iter(|| assert_eq!(string.par_split(' ').count(), count)) 28 | } 29 | 30 | #[bench] 31 | fn parallel_space_fn(b: &mut Bencher) { 32 | let (string, count) = get_string_count(); 33 | b.iter(|| assert_eq!(string.par_split(|c| c == ' ').count(), count)) 34 | } 35 | 36 | #[bench] 37 | fn serial_space_char(b: &mut Bencher) { 38 | let (string, count) = get_string_count(); 39 | b.iter(|| assert_eq!(string.split(' ').count(), count)) 40 | } 41 | 42 | #[bench] 43 | fn serial_space_fn(b: &mut Bencher) { 44 | let (string, count) = get_string_count(); 45 | b.iter(|| assert_eq!(string.split(|c| c == ' ').count(), count)) 46 | } 47 | 48 | #[bench] 49 | fn serial_space_str(b: &mut Bencher) { 50 | let (string, count) = get_string_count(); 51 | b.iter(|| assert_eq!(string.split(" ").count(), count)) 52 | } 53 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-demo/src/tsp/bench.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use test; 3 | 4 | use super::parse_solver; 5 | use super::graph::Node; 6 | use super::solver::SolverCx; 7 | 8 | fn run_dir(b: &mut test::Bencher, 9 | name: &str, 10 | seq_threshold: usize, 11 | exp_weight: usize, 12 | exp_path: Vec) { 13 | let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); 14 | let tsp_path = manifest_dir.join("data/tsp/").join(name); 15 | let graph = parse_solver(&tsp_path).unwrap(); 16 | let mut solution = None; 17 | b.iter(|| { 18 | let mut solver = SolverCx::new(&graph, seq_threshold); 19 | solver.search_from(Node::new(0)); 20 | solution = Some(solver.into_result()); 21 | }); 22 | let (path, weight) = solution.unwrap(); 23 | let mut path: Vec = path.unwrap().iter().map(|n| n.index()).collect(); 24 | if path.iter().rev().lt(&path) { 25 | path.reverse(); // normalize the direction 26 | } 27 | assert_eq!(exp_weight, weight.to_usize(), 28 | "actual weight ({:?}) did not match expectation ({:?})", weight, exp_weight); 29 | assert_eq!(exp_path, path, 30 | "best path ({:?}) did not match expectation ({:?})", path, exp_path); 31 | } 32 | 33 | #[bench] 34 | fn dj10(b: &mut test::Bencher) { 35 | // these numbers are tuned to "not take THAT long" in cargo bench, 36 | // basically, but still exercise the spawning stuff -- each run 37 | // should spawn 6! (720) tasks or so this way. 38 | run_dir(b, "dj10.tsp", 4, 2577, vec![0, 1, 3, 2, 4, 6, 8, 7, 5, 9, 0]); 39 | } 40 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-futures/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rayon-futures" 3 | version = "0.1.0" # reminder to update html_root_url attribute 4 | authors = ["Niko Matsakis ", 5 | "Josh Stone "] 6 | description = "Futures integration into Rayon" 7 | license = "Apache-2.0/MIT" 8 | repository = "https://github.com/nikomatsakis/rayon" 9 | documentation = "https://docs.rs/rayon-futures/" 10 | 11 | [dependencies] 12 | rayon-core = { version = "1.2.2", path = "../rayon-core" } 13 | futures = "0.1.7" 14 | 15 | [dev-dependencies] 16 | compiletest_rs = "0.2.1" 17 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-futures/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-futures/tests/compile-fail/README.md: -------------------------------------------------------------------------------- 1 | This directory contains test files that are **not expected to 2 | compile**. It is useful for writing tests that things which ought not 3 | to type-check do not, in fact, type-check. 4 | 5 | To write a test, just write a `.rs` file using Rayon. Then, for each 6 | compilation error, write a `//~ ERROR E123` annotation on the line 7 | where the error occurs. `E123` should be the error code that is issued 8 | by rustc. This should be reasonably robust against future compiler 9 | changes, though in some cases the errors may start showing up on 10 | different lines etc as compiler heuristics change. 11 | 12 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/rayon-futures/tests/compile-fail/future_escape.rs: -------------------------------------------------------------------------------- 1 | extern crate futures; 2 | extern crate rayon; 3 | extern crate rayon_futures; 4 | 5 | use futures::future::lazy; 6 | use rayon_futures::ScopeFutureExt; 7 | 8 | fn a() { 9 | let data = &mut [format!("Hello, ")]; 10 | 11 | let mut future = None; 12 | rayon::scope(|s| { 13 | let data = &mut *data; 14 | future = Some(s.spawn_future(lazy(move || Ok::<_, ()>(&mut data[0])))); 15 | }); 16 | 17 | // `data` is still borrowed as part of future here: 18 | assert_eq!(data[0], "Hello, world!"); //~ ERROR E0501 19 | } 20 | 21 | fn b() { 22 | let data = &mut [format!("Hello, ")]; 23 | 24 | let mut future = None; 25 | rayon::scope(|s| { 26 | future = Some(s.spawn_future(lazy(move || Ok::<_, ()>(&mut data[0])))); 27 | }); 28 | 29 | // `data` is moved into the scope above, can't use here 30 | assert_eq!(data[0], "Hello, world!"); //~ ERROR E0382 31 | } 32 | 33 | fn c() { 34 | let mut future = None; 35 | let data = &mut [format!("Hello, ")]; 36 | rayon::scope(|s| { 37 | future = Some(s.spawn_future(lazy(move || Ok::<_, ()>(&mut data[0])))); 38 | }); 39 | } //~ ERROR borrowed value does not live long enough 40 | 41 | fn main() { } 42 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/scripts/analyze.sh: -------------------------------------------------------------------------------- 1 | # Rough and dirty shell script to scrape the `log.rs` output and 2 | # analyze what kinds of tasks have been started and stopped. Very 3 | # useful in tracking down deadlocks. 4 | 5 | TICKLES=$(grep Tickle $1 | wc -l) 6 | 7 | INJECT_JOBS=$(grep InjectJobs $1 | wc -l) 8 | echo "Injected jobs:" $(((INJECT_JOBS * 2))) 9 | 10 | JOINS=$(grep Join $1 | wc -l) 11 | echo "Joins: " $JOINS 12 | 13 | POPPED_RHS=$(grep PoppedRhs $1 | wc -l) 14 | POPPED_JOB=$(grep PoppedJob $1 | wc -l) 15 | POPPED_TOTAL=$((($POPPED_RHS + $POPPED_JOB))) 16 | echo "Popped jobs: " $POPPED_TOTAL = rhs $POPPED_RHS + other $POPPED_JOB 17 | 18 | FOUND_WORK=$(grep FoundWork $1 | wc -l) 19 | echo "Found work: " $FOUND_WORK 20 | 21 | STOLE_WORK=$(grep StoleWork $1 | wc -l) 22 | echo "Stole work: " $STOLE_WORK 23 | 24 | UNINJECTED_WORK=$(grep UninjectedWork $1 | wc -l) 25 | echo "Uninjected: " $UNINJECTED_WORK 26 | 27 | echo "Join balance: " $((( $JOINS - $POPPED_TOTAL - $STOLE_WORK ))) 28 | echo "Inj. balance: " $((( $INJECT_JOBS * 2 - $UNINJECTED_WORK ))) 29 | echo "Total balance:" $((( $FOUND_WORK + $POPPED_TOTAL - $JOINS - $INJECT_JOBS * 2 ))) 30 | 31 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/collections/binary_heap.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the parallel iterator types for heaps 2 | //! (`BinaryHeap`). You will rarely need to interact with it directly 3 | //! unless you have need to name one of the iterator types. 4 | 5 | use std::collections::BinaryHeap; 6 | 7 | use iter::*; 8 | use iter::internal::*; 9 | 10 | use vec; 11 | 12 | impl IntoParallelIterator for BinaryHeap { 13 | type Item = T; 14 | type Iter = IntoIter; 15 | 16 | fn into_par_iter(self) -> Self::Iter { 17 | IntoIter { inner: Vec::from(self).into_par_iter() } 18 | } 19 | } 20 | 21 | into_par_vec!{ 22 | &'a BinaryHeap => Iter<'a, T>, 23 | impl<'a, T: Ord + Sync> 24 | } 25 | 26 | // `BinaryHeap` doesn't have a mutable `Iterator` 27 | 28 | 29 | delegate_indexed_iterator!{ 30 | #[doc = "Parallel iterator over a binary heap"] 31 | IntoIter => vec::IntoIter, 32 | impl 33 | } 34 | 35 | 36 | delegate_indexed_iterator!{ 37 | #[doc = "Parallel iterator over an immutable reference to a binary heap"] 38 | Iter<'a, T> => vec::IntoIter<&'a T>, 39 | impl<'a, T: Ord + Sync + 'a> 40 | } 41 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/collections/btree_map.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the parallel iterator types for B-Tree maps 2 | //! (`BTreeMap`). You will rarely need to interact with it directly 3 | //! unless you have need to name one of the iterator types. 4 | 5 | use std::collections::BTreeMap; 6 | 7 | use iter::*; 8 | use iter::internal::*; 9 | 10 | use vec; 11 | 12 | into_par_vec!{ 13 | BTreeMap => IntoIter, 14 | impl 15 | } 16 | 17 | into_par_vec!{ 18 | &'a BTreeMap => Iter<'a, K, V>, 19 | impl<'a, K: Ord + Sync, V: Sync> 20 | } 21 | 22 | into_par_vec!{ 23 | &'a mut BTreeMap => IterMut<'a, K, V>, 24 | impl<'a, K: Ord + Sync, V: Send> 25 | } 26 | 27 | 28 | delegate_iterator!{ 29 | #[doc = "Parallel iterator over a B-Tree map"] 30 | IntoIter => vec::IntoIter<(K, V)>, 31 | impl 32 | } 33 | 34 | 35 | delegate_iterator!{ 36 | #[doc = "Parallel iterator over an immutable reference to a B-Tree map"] 37 | Iter<'a, K, V> => vec::IntoIter<(&'a K, &'a V)>, 38 | impl<'a, K: Ord + Sync + 'a, V: Sync + 'a> 39 | } 40 | 41 | 42 | delegate_iterator!{ 43 | #[doc = "Parallel iterator over a mutable reference to a B-Tree map"] 44 | IterMut<'a, K, V> => vec::IntoIter<(&'a K, &'a mut V)>, 45 | impl<'a, K: Ord + Sync + 'a, V: Send + 'a> 46 | } 47 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/collections/btree_set.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the parallel iterator types for B-Tree sets 2 | //! (`BTreeSet`). You will rarely need to interact with it directly 3 | //! unless you have need to name one of the iterator types. 4 | 5 | use std::collections::BTreeSet; 6 | 7 | use iter::*; 8 | use iter::internal::*; 9 | 10 | use vec; 11 | 12 | into_par_vec!{ 13 | BTreeSet => IntoIter, 14 | impl 15 | } 16 | 17 | into_par_vec!{ 18 | &'a BTreeSet => Iter<'a, T>, 19 | impl<'a, T: Ord + Sync> 20 | } 21 | 22 | // `BTreeSet` doesn't have a mutable `Iterator` 23 | 24 | 25 | delegate_iterator!{ 26 | #[doc = "Parallel iterator over a B-Tree set"] 27 | IntoIter => vec::IntoIter, 28 | impl 29 | } 30 | 31 | 32 | delegate_iterator!{ 33 | #[doc = "Parallel iterator over an immutable reference to a B-Tree set"] 34 | Iter<'a, T> => vec::IntoIter<&'a T>, 35 | impl<'a, T: Ord + Sync + 'a> 36 | } 37 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/collections/hash_map.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the parallel iterator types for hash maps 2 | //! (`HashMap`). You will rarely need to interact with it directly 3 | //! unless you have need to name one of the iterator types. 4 | 5 | use std::collections::HashMap; 6 | use std::hash::{Hash, BuildHasher}; 7 | 8 | use iter::*; 9 | use iter::internal::*; 10 | 11 | use vec; 12 | 13 | into_par_vec!{ 14 | HashMap => IntoIter, 15 | impl 16 | } 17 | 18 | into_par_vec!{ 19 | &'a HashMap => Iter<'a, K, V>, 20 | impl<'a, K: Hash + Eq + Sync, V: Sync, S: BuildHasher> 21 | } 22 | 23 | into_par_vec!{ 24 | &'a mut HashMap => IterMut<'a, K, V>, 25 | impl<'a, K: Hash + Eq + Sync, V: Send, S: BuildHasher> 26 | } 27 | 28 | 29 | delegate_iterator!{ 30 | #[doc = "Parallel iterator over a hash map"] 31 | IntoIter => vec::IntoIter<(K, V)>, 32 | impl 33 | } 34 | 35 | 36 | delegate_iterator!{ 37 | #[doc = "Parallel iterator over an immutable reference to a hash map"] 38 | Iter<'a, K, V> => vec::IntoIter<(&'a K, &'a V)>, 39 | impl<'a, K: Hash + Eq + Sync + 'a, V: Sync + 'a> 40 | } 41 | 42 | 43 | delegate_iterator!{ 44 | #[doc = "Parallel iterator over a mutable reference to a hash map"] 45 | IterMut<'a, K, V> => vec::IntoIter<(&'a K, &'a mut V)>, 46 | impl<'a, K: Hash + Eq + Sync + 'a, V: Send + 'a> 47 | } 48 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/collections/hash_set.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the parallel iterator types for hash sets 2 | //! (`HashSet`). You will rarely need to interact with it directly 3 | //! unless you have need to name one of the iterator types. 4 | 5 | use std::collections::HashSet; 6 | use std::hash::{Hash, BuildHasher}; 7 | 8 | use iter::*; 9 | use iter::internal::*; 10 | 11 | use vec; 12 | 13 | into_par_vec!{ 14 | HashSet => IntoIter, 15 | impl 16 | } 17 | 18 | into_par_vec!{ 19 | &'a HashSet => Iter<'a, T>, 20 | impl<'a, T: Hash + Eq + Sync, S: BuildHasher> 21 | } 22 | 23 | // `HashSet` doesn't have a mutable `Iterator` 24 | 25 | 26 | delegate_iterator!{ 27 | #[doc = "Parallel iterator over a hash set"] 28 | IntoIter => vec::IntoIter, 29 | impl 30 | } 31 | 32 | 33 | delegate_iterator!{ 34 | #[doc = "Parallel iterator over an immutable reference to a hash set"] 35 | Iter<'a, T> => vec::IntoIter<&'a T>, 36 | impl<'a, T: Hash + Eq + Sync + 'a> 37 | } 38 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/collections/linked_list.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the parallel iterator types for linked lists 2 | //! (`LinkedList`). You will rarely need to interact with it directly 3 | //! unless you have need to name one of the iterator types. 4 | 5 | use std::collections::LinkedList; 6 | 7 | use iter::*; 8 | use iter::internal::*; 9 | 10 | use vec; 11 | 12 | into_par_vec!{ 13 | LinkedList => IntoIter, 14 | impl 15 | } 16 | 17 | into_par_vec!{ 18 | &'a LinkedList => Iter<'a, T>, 19 | impl<'a, T: Sync> 20 | } 21 | 22 | into_par_vec!{ 23 | &'a mut LinkedList => IterMut<'a, T>, 24 | impl<'a, T: Send> 25 | } 26 | 27 | 28 | 29 | delegate_iterator!{ 30 | #[doc = "Parallel iterator over a linked list"] 31 | IntoIter => vec::IntoIter, 32 | impl 33 | } 34 | 35 | 36 | delegate_iterator!{ 37 | #[doc = "Parallel iterator over an immutable reference to a linked list"] 38 | Iter<'a, T> => vec::IntoIter<&'a T>, 39 | impl<'a, T: Sync + 'a> 40 | } 41 | 42 | 43 | delegate_iterator!{ 44 | #[doc = "Parallel iterator over a mutable reference to a linked list"] 45 | IterMut<'a, T> => vec::IntoIter<&'a mut T>, 46 | impl<'a, T: Send + 'a> 47 | } 48 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/collections/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the parallel iterator types for standard 2 | //! collections. You will rarely need to interact with it directly 3 | //! unless you have need to name one of the iterator types. 4 | 5 | /// Convert an iterable collection into a parallel iterator by first 6 | /// collecting into a temporary `Vec`, then iterating that. 7 | macro_rules! into_par_vec { 8 | ($t:ty => $iter:ident<$($i:tt),*>, impl $($args:tt)*) => { 9 | impl $($args)* IntoParallelIterator for $t { 10 | type Item = <$t as IntoIterator>::Item; 11 | type Iter = $iter<$($i),*>; 12 | 13 | fn into_par_iter(self) -> Self::Iter { 14 | use std::iter::FromIterator; 15 | $iter { inner: Vec::from_iter(self).into_par_iter() } 16 | } 17 | } 18 | }; 19 | } 20 | 21 | pub mod binary_heap; 22 | pub mod btree_map; 23 | pub mod btree_set; 24 | pub mod hash_map; 25 | pub mod hash_set; 26 | pub mod linked_list; 27 | pub mod vec_deque; 28 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/iter/flatten.rs: -------------------------------------------------------------------------------- 1 | use super::internal::*; 2 | use super::*; 3 | 4 | /// `Flatten` turns each element to an iterator, then flattens these iterators 5 | /// together. This struct is created by the [`flatten()`] method on 6 | /// [`ParallelIterator`]. 7 | /// 8 | /// [`flatten()`]: trait.ParallelIterator.html#method.flatten 9 | /// [`ParallelIterator`]: trait.ParallelIterator.html 10 | #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] 11 | #[derive(Debug)] 12 | pub struct Flatten { 13 | base: I, 14 | } 15 | 16 | /// Create a new `Flatten` iterator. 17 | /// 18 | /// NB: Not part of the public API. 19 | pub fn new(base: I) -> Flatten 20 | where I: ParallelIterator, 21 | PI: IntoParallelIterator + Send 22 | { 23 | Flatten { 24 | base: base, 25 | } 26 | } 27 | 28 | impl ParallelIterator for Flatten 29 | where I: ParallelIterator, 30 | PI: IntoParallelIterator + Send 31 | { 32 | type Item = PI::Item; 33 | 34 | fn drive_unindexed(self, consumer: C) -> C::Result 35 | where C: UnindexedConsumer 36 | { 37 | self.base.flat_map(|x| x).drive_unindexed(consumer) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/iter/for_each.rs: -------------------------------------------------------------------------------- 1 | use super::ParallelIterator; 2 | use super::internal::*; 3 | use super::noop::*; 4 | 5 | pub fn for_each(pi: I, op: &F) 6 | where I: ParallelIterator, 7 | F: Fn(T) + Sync, 8 | T: Send 9 | { 10 | let consumer = ForEachConsumer { op: op }; 11 | pi.drive_unindexed(consumer) 12 | } 13 | 14 | struct ForEachConsumer<'f, F: 'f> { 15 | op: &'f F, 16 | } 17 | 18 | impl<'f, F, T> Consumer for ForEachConsumer<'f, F> 19 | where F: Fn(T) + Sync 20 | { 21 | type Folder = ForEachConsumer<'f, F>; 22 | type Reducer = NoopReducer; 23 | type Result = (); 24 | 25 | fn split_at(self, _index: usize) -> (Self, Self, NoopReducer) { 26 | (self.split_off_left(), self, NoopReducer) 27 | } 28 | 29 | fn into_folder(self) -> Self { 30 | self 31 | } 32 | 33 | fn full(&self) -> bool { 34 | false 35 | } 36 | } 37 | 38 | impl<'f, F, T> Folder for ForEachConsumer<'f, F> 39 | where F: Fn(T) + Sync 40 | { 41 | type Result = (); 42 | 43 | fn consume(self, item: T) -> Self { 44 | (self.op)(item); 45 | self 46 | } 47 | 48 | fn complete(self) {} 49 | 50 | fn full(&self) -> bool { 51 | false 52 | } 53 | } 54 | 55 | impl<'f, F, T> UnindexedConsumer for ForEachConsumer<'f, F> 56 | where F: Fn(T) + Sync 57 | { 58 | fn split_off_left(&self) -> Self { 59 | ForEachConsumer { op: self.op } 60 | } 61 | 62 | fn to_reducer(&self) -> NoopReducer { 63 | NoopReducer 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/iter/noop.rs: -------------------------------------------------------------------------------- 1 | use super::internal::*; 2 | 3 | pub struct NoopConsumer; 4 | 5 | impl NoopConsumer { 6 | pub fn new() -> Self { 7 | NoopConsumer 8 | } 9 | } 10 | 11 | impl Consumer for NoopConsumer { 12 | type Folder = NoopConsumer; 13 | type Reducer = NoopReducer; 14 | type Result = (); 15 | 16 | fn split_at(self, _index: usize) -> (Self, Self, NoopReducer) { 17 | (NoopConsumer, NoopConsumer, NoopReducer) 18 | } 19 | 20 | fn into_folder(self) -> Self { 21 | self 22 | } 23 | 24 | fn full(&self) -> bool { 25 | false 26 | } 27 | } 28 | 29 | impl Folder for NoopConsumer { 30 | type Result = (); 31 | 32 | fn consume(self, _item: T) -> Self { 33 | self 34 | } 35 | 36 | fn complete(self) {} 37 | 38 | fn full(&self) -> bool { 39 | false 40 | } 41 | } 42 | 43 | impl UnindexedConsumer for NoopConsumer { 44 | fn split_off_left(&self) -> Self { 45 | NoopConsumer 46 | } 47 | 48 | fn to_reducer(&self) -> NoopReducer { 49 | NoopReducer 50 | } 51 | } 52 | 53 | pub struct NoopReducer; 54 | 55 | impl Reducer<()> for NoopReducer { 56 | fn reduce(self, _left: (), _right: ()) {} 57 | } 58 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc(html_root_url = "https://docs.rs/rayon/0.8.2")] 2 | #![allow(non_camel_case_types)] // I prefer to use ALL_CAPS for type parameters 3 | #![deny(missing_debug_implementations)] 4 | #![cfg_attr(test, feature(conservative_impl_trait))] 5 | #![cfg_attr(test, feature(i128_type))] 6 | 7 | // If you're not compiling the unstable code, it often happens that 8 | // there is stuff that is considered "dead code" and so forth. So 9 | // disable warnings in that scenario. 10 | #![cfg_attr(not(rayon_unstable), allow(warnings))] 11 | 12 | extern crate rayon_core; 13 | extern crate either; 14 | 15 | #[cfg(test)] 16 | extern crate rand; 17 | 18 | #[macro_use] 19 | mod delegate; 20 | 21 | #[macro_use] 22 | mod private; 23 | 24 | mod split_producer; 25 | 26 | pub mod collections; 27 | pub mod iter; 28 | pub mod option; 29 | pub mod prelude; 30 | pub mod range; 31 | pub mod result; 32 | pub mod slice; 33 | pub mod str; 34 | pub mod vec; 35 | 36 | mod par_either; 37 | mod test; 38 | 39 | pub use iter::split; 40 | 41 | pub use rayon_core::current_num_threads; 42 | pub use rayon_core::Configuration; 43 | pub use rayon_core::initialize; 44 | pub use rayon_core::ThreadPool; 45 | pub use rayon_core::join; 46 | pub use rayon_core::{scope, Scope}; 47 | pub use rayon_core::spawn; 48 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/prelude.rs: -------------------------------------------------------------------------------- 1 | //! The rayon prelude imports the various `ParallelIterator` traits. 2 | //! The intention is that one can include `use rayon::prelude::*` and 3 | //! have easy access to the various traits and methods you will need. 4 | 5 | pub use iter::FromParallelIterator; 6 | pub use iter::IntoParallelIterator; 7 | pub use iter::IntoParallelRefIterator; 8 | pub use iter::IntoParallelRefMutIterator; 9 | pub use iter::IndexedParallelIterator; 10 | pub use iter::ParallelExtend; 11 | pub use iter::ParallelIterator; 12 | pub use slice::ParallelSlice; 13 | pub use slice::ParallelSliceMut; 14 | pub use str::ParallelString; 15 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/private.rs: -------------------------------------------------------------------------------- 1 | //! The public parts of this private module are used to create traits 2 | //! that cannot be implemented outside of our own crate. This way we 3 | //! can feel free to extend those traits without worrying about it 4 | //! being a breaking change for other implementations. 5 | 6 | 7 | /// If this type is pub but not publicly reachable, third parties 8 | /// can't name it and can't implement traits using it. 9 | #[allow(missing_debug_implementations)] 10 | pub struct PrivateMarker; 11 | 12 | macro_rules! private_decl { 13 | () => { 14 | /// This trait is private; this method exists to make it 15 | /// impossible to implement outside the crate. 16 | #[doc(hidden)] 17 | fn __rayon_private__(&self) -> ::private::PrivateMarker; 18 | } 19 | } 20 | 21 | macro_rules! private_impl { 22 | () => { 23 | fn __rayon_private__(&self) -> ::private::PrivateMarker { 24 | ::private::PrivateMarker 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate compiletest_rs as compiletest; 4 | 5 | use std::path::PathBuf; 6 | 7 | fn run_compiletest(mode: &str, path: &str) { 8 | let mut config = compiletest::default_config(); 9 | config.mode = mode.parse().ok().expect("Invalid mode"); 10 | config.src_base = PathBuf::from(path); 11 | config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned()); 12 | 13 | compiletest::run_tests(&config); 14 | } 15 | 16 | #[test] 17 | fn negative_tests_compile_fail() { 18 | run_compiletest("compile-fail", "tests/compile-fail"); 19 | } 20 | 21 | #[test] 22 | #[cfg(rayon_unstable)] 23 | fn negative_tests_compile_fail_unstable() { 24 | run_compiletest("compile-fail", "tests/compile-fail-unstable"); 25 | } 26 | 27 | #[test] 28 | fn negative_tests_run_fail() { 29 | run_compiletest("run-fail", "tests/run-fail"); 30 | } 31 | 32 | #[test] 33 | #[cfg(rayon_unstable)] 34 | fn negative_tests_run_fail_unstable() { 35 | run_compiletest("run-fail", "tests/run-fail-unstable"); 36 | } 37 | 38 | #[test] 39 | fn positive_test_run_pass() { 40 | run_compiletest("run-pass", "tests/run-pass"); 41 | } 42 | 43 | #[test] 44 | #[cfg(rayon_unstable)] 45 | fn positive_test_run_pass_unstable() { 46 | run_compiletest("run-pass", "tests/run-pass-unstable"); 47 | } 48 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail-unstable/README.md: -------------------------------------------------------------------------------- 1 | This directory contains test files that are **expected not to 2 | compile** and which **use unstable features**. See `compile-fail` for 3 | more details. 4 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/README.md: -------------------------------------------------------------------------------- 1 | This directory contains test files that are **not expected to 2 | compile**. It is useful for writing tests that things which ought not 3 | to type-check do not, in fact, type-check. 4 | 5 | To write a test, just write a `.rs` file using Rayon. Then, for each 6 | compilation error, write a `//~ ERROR E123` annotation on the line 7 | where the error occurs. `E123` should be the error code that is issued 8 | by rustc. This should be reasonably robust against future compiler 9 | changes, though in some cases the errors may start showing up on 10 | different lines etc as compiler heuristics change. 11 | 12 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/cannot_collect_filtermap_data.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use rayon::prelude::*; 4 | 5 | // zip requires data of exact size, but filter yields only bounded 6 | // size, so check that we cannot apply it. 7 | 8 | fn main() { 9 | let a: Vec = (0..1024).collect(); 10 | let mut v = vec![]; 11 | a.par_iter() 12 | .filter_map(|&x| Some(x as f32)) 13 | .collect_into(&mut v); //~ ERROR no method 14 | } 15 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/cannot_zip_filtered_data.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use rayon::prelude::*; 4 | 5 | // zip requires data of exact size, but filter yields only bounded 6 | // size, so check that we cannot apply it. 7 | 8 | fn main() { 9 | let mut a: Vec = (0..1024).rev().collect(); 10 | let b: Vec = (0..1024).collect(); 11 | 12 | a.par_iter() 13 | .zip(b.par_iter().filter(|&&x| x > 3)); //~ ERROR E0277 14 | } 15 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/cell_par_iter.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | // Check that we can't use the par-iter API to access contents of a `Cell`. 4 | 5 | use rayon::prelude::*; 6 | use std::cell::Cell; 7 | 8 | fn main() { 9 | let c = Cell::new(42_i32); 10 | (0_i32..1024).into_par_iter() 11 | .map(|_| c.get()) //~ ERROR Sync` is not satisfied 12 | .min(); 13 | } 14 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/no_send_par_iter.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | // Check that `!Send` types fail early. 4 | 5 | use rayon::prelude::*; 6 | use std::ptr::null; 7 | 8 | #[derive(Copy, Clone)] 9 | struct NoSend(*const ()); 10 | 11 | unsafe impl Sync for NoSend {} 12 | 13 | fn main() { 14 | let x = Some(NoSend(null())); 15 | 16 | x.par_iter() 17 | .map(|&x| x) //~ ERROR E0277 18 | .count(); //~ ERROR E0599 19 | 20 | x.par_iter() 21 | .filter_map(|&x| Some(x)) //~ ERROR E0277 22 | .count(); //~ ERROR E0599 23 | 24 | x.par_iter() 25 | .cloned() //~ ERROR E0277 26 | .count(); //~ ERROR E0599 27 | } 28 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/quicksort_race1.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | fn quick_sort(v: &mut [T]) { 4 | if v.len() <= 1 { 5 | return; 6 | } 7 | 8 | let mid = partition(v); 9 | let (lo, _hi) = v.split_at_mut(mid); 10 | rayon::join(|| quick_sort(lo), || quick_sort(lo)); //~ ERROR E0524 11 | } 12 | 13 | fn partition(v: &mut [T]) -> usize { 14 | let pivot = v.len() - 1; 15 | let mut i = 0; 16 | for j in 0..pivot { 17 | if v[j] <= v[pivot] { 18 | v.swap(i, j); 19 | i += 1; 20 | } 21 | } 22 | v.swap(i, pivot); 23 | i 24 | } 25 | 26 | fn main() { } 27 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/quicksort_race2.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | fn quick_sort(v: &mut [T]) { 4 | if v.len() <= 1 { 5 | return; 6 | } 7 | 8 | let mid = partition(v); 9 | let (lo, _hi) = v.split_at_mut(mid); 10 | rayon::join(|| quick_sort(lo), || quick_sort(v)); //~ ERROR E0500 11 | } 12 | 13 | fn partition(v: &mut [T]) -> usize { 14 | let pivot = v.len() - 1; 15 | let mut i = 0; 16 | for j in 0..pivot { 17 | if v[j] <= v[pivot] { 18 | v.swap(i, j); 19 | i += 1; 20 | } 21 | } 22 | v.swap(i, pivot); 23 | i 24 | } 25 | 26 | fn main() { } 27 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/quicksort_race3.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | fn quick_sort(v: &mut [T]) { 4 | if v.len() <= 1 { 5 | return; 6 | } 7 | 8 | let mid = partition(v); 9 | let (_lo, hi) = v.split_at_mut(mid); 10 | rayon::join(|| quick_sort(hi), || quick_sort(hi)); //~ ERROR E0524 11 | } 12 | 13 | fn partition(v: &mut [T]) -> usize { 14 | let pivot = v.len() - 1; 15 | let mut i = 0; 16 | for j in 0..pivot { 17 | if v[j] <= v[pivot] { 18 | v.swap(i, j); 19 | i += 1; 20 | } 21 | } 22 | v.swap(i, pivot); 23 | i 24 | } 25 | 26 | fn main() { } 27 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/rc_par_iter.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | // Check that we can't use the par-iter API to access contents of an 4 | // `Rc`. 5 | 6 | use rayon::iter::IntoParallelIterator; 7 | use std::rc::Rc; 8 | 9 | fn main() { 10 | let x = vec![Rc::new(22), Rc::new(23)]; 11 | let mut y = vec![]; 12 | x.into_par_iter() //~ ERROR no method named `into_par_iter` 13 | .map(|rc| *rc) 14 | .collect_into(&mut y); 15 | } 16 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/rc_return.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use std::rc::Rc; 4 | 5 | fn main() { 6 | rayon::join(|| Rc::new(22), || ()); //~ ERROR E0277 7 | rayon::join(|| (), || Rc::new(23)); //~ ERROR E0277 8 | } 9 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/rc_upvar.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use std::rc::Rc; 4 | 5 | fn main() { 6 | let r = Rc::new(22); 7 | rayon::join(|| r.clone(), || r.clone()); 8 | //~^ ERROR E0277 9 | } 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/compile-fail/scope_join_bad.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | fn bad_scope(f: F) 4 | where F: FnOnce(&i32) + Send, 5 | { 6 | rayon::scope(|s| { 7 | let x = 22; 8 | s.spawn(|_| f(&x)); //~ ERROR `x` does not live long enough 9 | }); 10 | } 11 | 12 | fn good_scope(f: F) 13 | where F: FnOnce(&i32) + Send, 14 | { 15 | let x = 22; 16 | rayon::scope(|s| { 17 | s.spawn(|_| f(&x)); 18 | }); 19 | } 20 | 21 | fn main() { 22 | } 23 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-fail-unstable/README.md: -------------------------------------------------------------------------------- 1 | This directory contains test files that are **expected to run and 2 | panic** and which **use unstable features**. See `run-fail` for more 3 | details. 4 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-fail/README.md: -------------------------------------------------------------------------------- 1 | This directory contains test files that are **expected to run and 2 | panic**. Usually, though, these tests are better written with 3 | `#[test]` tests. To use it, create a `.rs` file and include a comment 4 | like 5 | 6 | ``` 7 | // error-pattern:boom 8 | ``` 9 | 10 | indicating the panic message we should expect to see. 11 | 12 | Note: if the test uses unstable features, prefer the 13 | `run-fail-unstable` directory. 14 | 15 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-fail/iter_panic.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use rayon::*; 4 | use rayon::prelude::*; 5 | 6 | // error-pattern:boom 7 | 8 | fn main() { 9 | (0i32..2_000_000).into_par_iter().for_each(|i| if i == 1_350_000 { panic!("boom") }); 10 | } 11 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-fail/simple_panic.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use rayon::*; 4 | 5 | // error-pattern:should panic 6 | 7 | fn main() { 8 | join(|| {}, || panic!("should panic")); 9 | } 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-pass-unstable/README.md: -------------------------------------------------------------------------------- 1 | This directory contains test files that are **expected to run and 2 | execute successfully** and which **contain unstable features**. See 3 | the `run-pass` directory for more details. 4 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-pass/README.md: -------------------------------------------------------------------------------- 1 | This directory contains test files that are **expected to run and 2 | execute successfully**. Often, though, such tests are better written 3 | just using the standard `#[test]` mechanism. In any case, to create 4 | such a test, just make a `.rs` file. 5 | 6 | Note: if the test uses unstable features, prefer the 7 | `run-pass-unstable` directory. 8 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-pass/double_init_fail.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use rayon::*; 4 | 5 | fn main() { 6 | let result1 = initialize(Configuration::new()); 7 | assert_eq!(result1.unwrap(), ()); 8 | let err = initialize(Configuration::new()).unwrap_err(); 9 | assert!(err.description() == "The global thread pool has already been initialized."); 10 | } 11 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-pass/init_zero_threads.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use rayon::*; 4 | 5 | fn main() { 6 | initialize(Configuration::new().num_threads(0)).unwrap(); 7 | } 8 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-pass/named-threads.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use std::collections::HashSet; 4 | 5 | use rayon::*; 6 | use rayon::prelude::*; 7 | 8 | fn main() { 9 | let result = initialize(Configuration::new().thread_name(|i| format!("hello-name-test-{}", i))); 10 | 11 | const N: usize = 10000; 12 | 13 | let thread_names = (0..N).into_par_iter() 14 | .flat_map(|_| ::std::thread::current().name().map(|s| s.to_owned())) 15 | .collect::>(); 16 | 17 | let all_contains_name = thread_names.iter().all(|name| name.starts_with("hello-name-test-")); 18 | assert!(all_contains_name); 19 | } 20 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/rayon/tests/run-pass/scope_join.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | /// Test that one can emulate join with `scope`: 4 | fn pseudo_join(f: F, g: G) 5 | where F: FnOnce() + Send, 6 | G: FnOnce() + Send, 7 | { 8 | rayon::scope(|s| { 9 | s.spawn(|_| g()); 10 | f(); 11 | }); 12 | } 13 | 14 | fn quick_sort(v: &mut [T]) { 15 | if v.len() <= 1 { 16 | return; 17 | } 18 | 19 | let mid = partition(v); 20 | let (lo, hi) = v.split_at_mut(mid); 21 | pseudo_join(|| quick_sort(lo), || quick_sort(hi)); 22 | } 23 | 24 | fn partition(v: &mut [T]) -> usize { 25 | let pivot = v.len() - 1; 26 | let mut i = 0; 27 | for j in 0..pivot { 28 | if v[j] <= v[pivot] { 29 | v.swap(i, j); 30 | i += 1; 31 | } 32 | } 33 | v.swap(i, pivot); 34 | i 35 | } 36 | 37 | pub fn is_sorted(v: &[T]) -> bool { 38 | (1..v.len()).all(|i| v[i-1] <= v[i]) 39 | } 40 | 41 | fn main() { 42 | let mut v: Vec = (0 .. 256).rev().collect(); 43 | quick_sort(&mut v); 44 | assert!(is_sorted(&v)); 45 | } 46 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-1/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | fn main(){ 4 | let pool1 = rayon::Configuration::new().num_threads(1).build().unwrap(); 5 | let pool2 = rayon::Configuration::new().num_threads(1).build().unwrap(); 6 | 7 | pool1.install(|| { // JOB_A 8 | // this will block pool1's thread: 9 | pool2.install(|| { //JOB_B 10 | // this will block pool2's thread: 11 | pool1.install(|| { //JOB_C 12 | // there are no threads left to run this! 13 | println!("hello?"); 14 | }); 15 | }); 16 | }); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rayon-blocking-2" 3 | version = "0.1.0" 4 | authors = ["BurtonQin "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-2/README.md: -------------------------------------------------------------------------------- 1 | # rayon-449 2 | 3 | This is a blocking bug. 4 | 5 | There are three threads involved in this deadlock. One is the main thread. It creates two thread-pools and submits one job to the first thread-pool. The other two are worker threads inside the two thread-pools. 6 | 7 | When a job is submitted to a thread pool, the submitting thread creates a StackJob object and blocks itself by invoking StackJob.latch.wait(). When a submitted job is finished by one of the worker threads inside the thread-pool, StackJob.latch.set() is invoked to unblock the submitting thread. 8 | 9 | There are three jobs created, Job A, Job B, and Job C. Job A is submitted the first thread-pool, and it is to submit Job B to the second thread-pool. Job B is to submit Job C to the first thread pool. 10 | 11 | When the main thread submits Job A to the first thread-pool, it blocks itself and waits for the worker thread inside the first thread-pool to finish the Job A. When the worker thread inside the first thread-pool processes Job A, it submits Job B to the second thread-pool and waits for the worker thread inside the second thread-pool to process Job B. When the worker thread inside the second thread-pool processes Job B, it submits Job C to the first thread-pool and wait for any worker thread inside the first thread-pool to process Job C. However, there is no available worker thread inside the first thread-pool. 12 | 13 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/rayon-blocking-2/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::AtomicBool; 2 | use std::sync::atomic::Ordering; 3 | use std::sync::Arc; 4 | use std::sync::Condvar; 5 | use std::sync::Mutex; 6 | use std::thread; 7 | use std::time; 8 | 9 | struct LockLatch { 10 | b: AtomicBool, 11 | m: Mutex<()>, 12 | v: Condvar, 13 | } 14 | 15 | unsafe impl Sync for LockLatch {} 16 | 17 | pub trait Latch { 18 | fn set(&self); 19 | fn wait(&self); 20 | } 21 | 22 | impl LockLatch { 23 | #[inline] 24 | pub fn new() -> LockLatch { 25 | LockLatch { 26 | b: AtomicBool::new(false), 27 | m: Mutex::new(()), 28 | v: Condvar::new(), 29 | } 30 | } 31 | 32 | pub fn probe(&self) -> bool { 33 | self.b.load(Ordering::Acquire) 34 | } 35 | } 36 | 37 | impl Latch for LockLatch { 38 | /// Set the latch to true, releasing all threads who are waiting. 39 | fn set(&self) { 40 | self.b.store(true, Ordering::Release); 41 | self.v.notify_all(); 42 | } 43 | 44 | /// Spin until latch is set. Use with caution. 45 | fn wait(&self) { 46 | let mut guard = self.m.lock().unwrap(); 47 | while !self.probe() { 48 | thread::sleep(time::Duration::from_millis(2000)); 49 | guard = self.v.wait(guard).unwrap(); 50 | } 51 | } 52 | } 53 | 54 | fn main() { 55 | let latch = Arc::new(LockLatch::new()); 56 | let cloned_latch = latch.clone(); 57 | thread::spawn(move || { 58 | cloned_latch.set(); 59 | }); 60 | 61 | latch.wait(); 62 | println!("Hello World!"); 63 | } 64 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/redox-blocking-1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redox-1" 3 | version = "0.1.0" 4 | authors = ["BurtonQin "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/redox-blocking-1/README.md: -------------------------------------------------------------------------------- 1 | #redox-c7eccb3a13493c582de8d452a1112b28224a973d 2 | 3 | This deadlock is caused by double lock. 4 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/redox-blocking-1/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Mutex; 2 | use std::sync::atomic::AtomicUsize; 3 | use std::sync::atomic::Ordering; 4 | use std::collections::BTreeMap; 5 | use std::sync::Arc; 6 | 7 | pub struct DiskScheme { 8 | disks: i32, 9 | handles: Arc>>, 10 | next_id: AtomicUsize, 11 | } 12 | 13 | impl DiskScheme { 14 | fn dup(&self, _id: usize) -> Result { 15 | let mut handles = self.handles.lock().unwrap(); 16 | let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); 17 | self.handles.lock().unwrap().insert(new_id, ()); 18 | Ok(new_id) 19 | } 20 | } 21 | 22 | fn main() { 23 | let d = DiskScheme { 24 | disks: 1, 25 | handles: Arc::new(Mutex::new(BTreeMap::default())), 26 | next_id: AtomicUsize::new(1) 27 | }; 28 | let _result = d.dup(1); 29 | println!("Hello World!"); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/tikv-blocking-3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tikv-blocking-3" 3 | version = "0.1.0" 4 | authors = ["BurtonQin "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/blocking-bugs/tikv-blocking-3/README.md: -------------------------------------------------------------------------------- 1 | # tikv-539 2 | 3 | This is a blocking bug related to `Condvar` 4 | 5 | A thread can wait for an `Event` object to be set or to be cleared by invoking `Event.inner.1.wait()`. However, if a thread is the last one holding `Event.inner` `Arc`, it will stop the waiting, since no other threads can wake it up. `Arc::strong_count(&Event.inner) == 1` is used to decide whether a thread who is going to call `Event.inner.1.wait()` is the last thread holding `Event.inner` `Arc`. 6 | 7 | When an `Event` is dropped, `Event.inner.1.notify_all()` is called to wake up threads waiting on `Event.inner.1.wait()`, and `drop(Event.inner)` is also called to decrease the value of `Arc::strong_count(&Event.inner)`. 8 | 9 | There are two problems for the buggy version. Firstly, library users can directly call `drop(Event.inner)`, without calling `Event.inner.1.notify_all()`. Second, a waiting thread could be waked up and execute `Arc::strong_count(&Event.inner) == 1` before `drop(Event.inner)` is called. 10 | 11 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/non-blocking-bugs/servo-nonblocking-16/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "servo-nonblocking-16" 3 | version = "0.1.0" 4 | authors = ["BurtonQin "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/non-blocking-bugs/servo-nonblocking-16/README.md: -------------------------------------------------------------------------------- 1 | #servo-1772 2 | 3 | This is a non-blocking bug. 4 | 5 | A mutable borrow held by thread A live while thread B tries to get an immutable borrow, leading to panic inside `RefCell`. 6 | 7 | Result: 8 | ``` 9 | '' panicked at 'error in borrow_mut: BorrowMutError', src/libcore/result.rs:1187:5 10 | ``` 11 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/non-blocking-bugs/servo-nonblocking-16/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut}; 2 | use std::sync::Arc; 3 | use std::thread; 4 | 5 | #[derive(Clone, Debug)] 6 | pub struct TESTRefCell { 7 | value: RefCell, 8 | } 9 | 10 | unsafe impl Sync for TESTRefCell {} 11 | 12 | impl TESTRefCell { 13 | pub fn new(value: i32) -> TESTRefCell { 14 | TESTRefCell { 15 | value: RefCell::new(value), 16 | } 17 | } 18 | 19 | pub fn try_borrow(&self) -> Result, BorrowError> { 20 | self.value.try_borrow() 21 | } 22 | 23 | pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { 24 | self.value.try_borrow_mut() 25 | } 26 | 27 | pub fn borrow(&self) -> Ref { 28 | self.try_borrow().expect("error in borrow") 29 | } 30 | 31 | pub fn borrow_mut(&self) -> RefMut { 32 | self.try_borrow_mut().expect("error in borrow_mut") 33 | } 34 | } 35 | 36 | fn main() { 37 | let c = TESTRefCell::new(5); 38 | let c = Arc::new(c); 39 | 40 | let x = c.borrow(); 41 | { 42 | let c2 = c.clone(); 43 | thread::spawn(move || { 44 | { 45 | let mut v = c2.borrow_mut(); 46 | *v = 100; 47 | } 48 | println!("{:?} in child", c2.value); 49 | }) 50 | .join() 51 | .unwrap(); 52 | } 53 | 54 | println!("{:?} in main", x); 55 | } 56 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/non-blocking-bugs/servo-nonblocking-6/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "servo-nonblocking-6" 3 | version = "0.1.0" 4 | authors = ["BurtonQin "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/non-blocking-bugs/servo-nonblocking-6/README.md: -------------------------------------------------------------------------------- 1 | #servo-12639 2 | 3 | Rust provides a poisoning mechanism. While a thread holds a mutex and triggers a panic, other threads that are waiting for the mutex will receive an `Err` as return from the `mutex.lock()` function. Therefore, panic information can be propagated across threads. 4 | 5 | `Poisoned.into_inner()` will return the protected shared variable by the mutex. 6 | 7 | For the buggy version of servo, when poison happens, log message will not be sent out, leading to some log is missing. 8 | 9 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/reproduced_concurrency_bugs/non-blocking-bugs/servo-nonblocking-6/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Mutex; 2 | use std::sync::Arc; 3 | use std::thread; 4 | 5 | fn main() { 6 | let lock = Arc::new(Mutex::new(0_u32)); 7 | 8 | let lock_new = Arc::clone(&lock); 9 | 10 | let result = thread::spawn(move || { 11 | let mut data = lock_new.lock().unwrap(); 12 | *data += 4; 13 | panic!(); 14 | }).join(); 15 | 16 | match lock.lock() { 17 | Ok(data) => println!("{}", *data), 18 | Err(poisoned) => println!("Poison: {}", poisoned.into_inner()), 19 | }; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/ManualDropPrinter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(RustBugDetector) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | find_package(LLVM REQUIRED CONFIG) 7 | add_definitions(${LLVM_DEFINITIONS}) 8 | include_directories(${LLVM_INCLUDE_DIRS}) 9 | link_directories(${LLVM_LIBRARY_DIRS}) 10 | include_directories("${PROJECT_SOURCE_DIR}/include") 11 | add_subdirectory(lib) -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/ManualDropPrinter/include/Common/CallerFunc.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINTPASS_GETCALLERFUNC_H 2 | #define PRINTPASS_GETCALLERFUNC_H 3 | 4 | #include "llvm/IR/Instruction.h" 5 | #include "llvm/IR/Function.h" 6 | #include "llvm/IR/CallSite.h" 7 | 8 | bool isCallOrInvokeInst(llvm::Instruction *I); 9 | 10 | llvm::Function *getCalledFunc(llvm::Instruction *pInst, llvm::CallSite &CS); 11 | 12 | #endif //PRINTPASS_GETCALLERFUNC_H 13 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/ManualDropPrinter/include/PrintManualDrop/PrintManualDrop.h: -------------------------------------------------------------------------------- 1 | #ifndef RUSTBUGDETECTOR_PRINTMANUALDROP_H 2 | #define RUSTBUGDETECTOR_PRINTMANUALDROP_H 3 | 4 | #include "llvm/Pass.h" 5 | 6 | namespace detector { 7 | 8 | struct PrintManualDrop : llvm::ModulePass { 9 | 10 | static char ID; 11 | 12 | PrintManualDrop(); 13 | 14 | void getAnalysisUsage(llvm::AnalysisUsage &AU) const override; 15 | 16 | bool runOnModule(llvm::Module &M) override; 17 | 18 | private: 19 | 20 | llvm::Module *pModule; 21 | }; 22 | } 23 | 24 | 25 | #endif //RUSTBUGDETECTOR_PRINTMANUALDROP_H 26 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/ManualDropPrinter/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Common) 2 | add_subdirectory(PrintManualDrop) 3 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/ManualDropPrinter/lib/Common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(CommonLib STATIC 2 | # List your source files here. 3 | CallerFunc.cpp 4 | ) 5 | 6 | # Use C++11 to compile our pass (i.e., supply -std=c++11). 7 | target_compile_features(CommonLib PRIVATE cxx_range_for cxx_auto_type) 8 | 9 | # LLVM is (typically) built with no C++ RTTI. We need to match that; 10 | # otherwise, we'll get linker errors about missing RTTI data. 11 | set_target_properties(CommonLib PROPERTIES 12 | COMPILE_FLAGS "-fno-rtti -fPIC" 13 | ) 14 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/ManualDropPrinter/lib/Common/CallerFunc.cpp: -------------------------------------------------------------------------------- 1 | #include "Common/CallerFunc.h" 2 | 3 | #include "llvm/IR/Instruction.h" 4 | #include "llvm/IR/IntrinsicInst.h" 5 | #include "llvm/IR/CallSite.h" 6 | 7 | using namespace llvm; 8 | 9 | bool isCallOrInvokeInst(Instruction *I) { 10 | if (!I) { 11 | return false; 12 | } 13 | if (isa(I)) { 14 | return false; 15 | } 16 | if (isa(I)) { 17 | return false; 18 | } 19 | if (isa(I) || isa(I)) { 20 | return true; 21 | } 22 | return false; 23 | } 24 | 25 | Function *getCalledFunc(Instruction *pInst, CallSite &CS) { 26 | if (!pInst) { 27 | return nullptr; 28 | } 29 | if (isa(pInst)) { 30 | return nullptr; 31 | // } else if (isa(pInst)) { 32 | // return nullptr; 33 | } else if (isa(pInst) || isa(pInst)) { 34 | CS = CallSite(pInst); 35 | try { 36 | Function *pCalled = CS.getCalledFunction(); 37 | if (pCalled) { 38 | return pCalled; 39 | } else { 40 | // errs() << "Call FuncPtr:" << '\n'; 41 | return nullptr; 42 | } 43 | } catch (...) { 44 | errs() << "Bad Inst\n"; 45 | pInst->print(errs()); 46 | errs() << '\n'; 47 | return nullptr; 48 | } 49 | } 50 | return nullptr; 51 | } 52 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/ManualDropPrinter/lib/PrintManualDrop/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(PrintManualDrop MODULE 2 | # List your source files here. 3 | PrintManualDrop.cpp 4 | ) 5 | 6 | target_link_libraries(PrintManualDrop CommonLib) 7 | 8 | # Use C++11 to compile our pass (i.e., supply -std=c++11). 9 | target_compile_features(PrintManualDrop PRIVATE cxx_range_for cxx_auto_type) 10 | 11 | # LLVM is (typically) built with no C++ RTTI. We need to match that; 12 | # otherwise, we'll get linker errors about missing RTTI data. 13 | set_target_properties(PrintManualDrop PROPERTIES 14 | COMPILE_FLAGS "-fno-rtti" 15 | ) 16 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/crossbeam/5987357a740a5a2768c264301ba7243edb1ccb71.txt: -------------------------------------------------------------------------------- 1 | diff --git a/tests/zero.rs b/tests/zero.rs 2 | index a3e9c3cc..ae1b377a 100644 3 | --- a/tests/zero.rs 4 | +++ b/tests/zero.rs 5 | @@ -397,14 +397,14 @@ fn fairness() { 6 | assert!(hit.iter().all(|x| *x)); 7 | }); 8 | 9 | + let mut hit = [false; 2]; 10 | for _ in 0..COUNT { 11 | - let mut hit = [false; 2]; 12 | select! { 13 | send(s1, ()) => hit[0] = true, 14 | send(s2, ()) => hit[1] = true, 15 | } 16 | - assert!(hit.iter().all(|x| *x)); 17 | } 18 | + assert!(hit.iter().all(|x| *x)); 19 | }); 20 | } 21 | 22 | diff --git a/tests/zero_select.rs b/tests/zero_select.rs 23 | index 3dede3ac..39d9e4bc 100644 24 | --- a/tests/zero_select.rs 25 | +++ b/tests/zero_select.rs 26 | @@ -463,12 +463,14 @@ fn fairness() { 27 | assert!(hit.iter().all(|x| *x)); 28 | }); 29 | 30 | + let mut hit = [false; 2]; 31 | for _ in 0..COUNT { 32 | select! { 33 | - send(s1.0, ()) => {} 34 | - send(s2.0, ()) => {} 35 | + send(s1.0, ()) => hit[0] = true, 36 | + send(s2.0, ()) => hit[1] = true, 37 | } 38 | } 39 | + assert!(hit.iter().all(|x| *x)); 40 | }); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/lazy-static.rs/eae87a9f9736b5c35e9e03dec1a8f8c3f8d2cf36.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/lib.rs b/src/lib.rs 2 | index 4837066..8f57d08 100644 3 | --- a/src/lib.rs 4 | +++ b/src/lib.rs 5 | @@ -26,7 +26,8 @@ implements `Deref` and stores it in a static with name `NAME`. (Metadata e 6 | attaching to this type.) 7 | 8 | On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs 9 | -can return a reference to the same object. 10 | +can return a reference to the same object. Note that this can lead to deadlocks 11 | +if you have multiple lazy statics that depend on each other in their initialization. 12 | 13 | Like regular `static mut`s, this macro only works for types that fulfill the `Sync` 14 | trait. 15 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/16ddb8843513c4864c3a66ba6b4e9ae0399289c6.txt: -------------------------------------------------------------------------------- 1 | diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs 2 | index c7bff478466..d9e591ca41a 100644 3 | --- a/ethcore/src/miner/miner.rs 4 | +++ b/ethcore/src/miner/miner.rs 5 | @@ -767,9 +767,11 @@ impl MinerService for Miner { 6 | if let Some(ref ap) = self.accounts { 7 | try!(ap.sign(address.clone(), Some(password.clone()), Default::default())); 8 | } 9 | - let mut sealing_work = self.sealing_work.lock(); 10 | - sealing_work.enabled = self.engine.is_sealer(&address).unwrap_or(false); 11 | - *self.author.write() = address; 12 | + { 13 | + let mut sealing_work = self.sealing_work.lock(); 14 | + sealing_work.enabled = self.engine.is_sealer(&address).unwrap_or(false); 15 | + *self.author.write() = address; 16 | + } 17 | self.engine.set_signer(address, password); 18 | } 19 | Ok(()) 20 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/19a67254304075017190311ce869853ea052a166.txt: -------------------------------------------------------------------------------- 1 | diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs 2 | index fa79bd74556..e10368526bd 100644 3 | --- a/ethcore/src/blockchain/blockchain.rs 4 | +++ b/ethcore/src/blockchain/blockchain.rs 5 | @@ -1450,18 +1450,24 @@ impl BlockChain { 6 | 7 | /// Returns general blockchain information 8 | pub fn chain_info(&self) -> BlockChainInfo { 9 | + // Make sure to call internal methods first to avoid 10 | + // recursive locking of `best_block`. 11 | + let first_block_hash = self.first_block(); 12 | + let first_block_number = self.first_block_number().into(); 13 | + let genesis_hash = self.genesis_hash(); 14 | + 15 | // ensure data consistencly by locking everything first 16 | let best_block = self.best_block.read(); 17 | let best_ancient_block = self.best_ancient_block.read(); 18 | BlockChainInfo { 19 | total_difficulty: best_block.total_difficulty, 20 | pending_total_difficulty: best_block.total_difficulty, 21 | - genesis_hash: self.genesis_hash(), 22 | + genesis_hash, 23 | best_block_hash: best_block.header.hash(), 24 | best_block_number: best_block.header.number(), 25 | best_block_timestamp: best_block.header.timestamp(), 26 | - first_block_hash: self.first_block(), 27 | - first_block_number: From::from(self.first_block_number()), 28 | + first_block_hash, 29 | + first_block_number, 30 | ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash), 31 | ancient_block_number: best_ancient_block.as_ref().map(|b| b.number), 32 | } 33 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/31e64c0a5f644aa364c28db9ee3cd8ac20e430b4.txt: -------------------------------------------------------------------------------- 1 | diff --git a/hw/src/ledger.rs b/hw/src/ledger.rs 2 | index b6ea373721b..409f186ace2 100644 3 | --- a/hw/src/ledger.rs 4 | +++ b/hw/src/ledger.rs 5 | @@ -112,7 +112,7 @@ impl Manager { 6 | if device.vendor_id != LEDGER_VID || !LEDGER_PIDS.contains(&device.product_id) { 7 | continue; 8 | } 9 | - match self.read_device_info(&device) { 10 | + match self.read_device_info(&usb, &device) { 11 | Ok(info) => { 12 | debug!("Found device: {:?}", info); 13 | if !self.devices.iter().any(|d| d.path == info.path) { 14 | @@ -133,8 +133,7 @@ impl Manager { 15 | self.key_path = key_path; 16 | } 17 | 18 | - fn read_device_info(&self, dev_info: &hidapi::HidDeviceInfo) -> Result { 19 | - let usb = self.usb.lock(); 20 | + fn read_device_info(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { 21 | let mut handle = self.open_path(|| usb.open_path(&dev_info.path))?; 22 | let address = Self::read_wallet_address(&mut handle, self.key_path)?; 23 | let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); 24 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/43cc4ea13dec86cc4721f85bdbd8cc0e151bd5a2.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/network/src/host.rs b/util/network/src/host.rs 2 | index b5a19cc927f..98efbd6a0a5 100644 3 | --- a/util/network/src/host.rs 4 | +++ b/util/network/src/host.rs 5 | @@ -517,13 +517,13 @@ impl Host { 6 | } 7 | 8 | pub fn external_url(&self) -> Option { 9 | - self.info.read().public_endpoint.as_ref().map(|e| format!("{}", Node::new(self.info.read().id().clone(), e.clone()))) 10 | + let info = self.info.read(); 11 | + info.public_endpoint.as_ref().map(|e| format!("{}", Node::new(info.id().clone(), e.clone()))) 12 | } 13 | 14 | pub fn local_url(&self) -> String { 15 | - let r = format!("{}", Node::new(self.info.read().id().clone(), self.info.read().local_endpoint.clone())); 16 | - println!("{}", r); 17 | - r 18 | + let info = self.info.read(); 19 | + format!("{}", Node::new(info.id().clone(), info.local_endpoint.clone())) 20 | } 21 | 22 | pub fn stop(&self, io: &IoContext) -> Result<(), NetworkError> { 23 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/44e1e74bfad2588ac1906e1171f0a3e00188f958.txt: -------------------------------------------------------------------------------- 1 | diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs 2 | index 24660276e2d..22364232c7e 100644 3 | --- a/ethcore/src/miner/miner.rs 4 | +++ b/ethcore/src/miner/miner.rs 5 | @@ -867,13 +867,15 @@ impl miner::MinerService for Miner { 6 | 7 | fn set_minimal_gas_price(&self, new_price: U256) -> Result { 8 | match *self.gas_pricer.lock() { 9 | - GasPricer::Fixed(ref mut val) => { 10 | + // Binding the gas pricer to `gp` here to prevent 11 | + // a deadlock when calling recalibrate() 12 | + ref mut gp @ GasPricer::Fixed(_) => { 13 | trace!(target: "miner", "minimal_gas_price: recalibrating fixed..."); 14 | - *val = new_price; 15 | + *gp = GasPricer::new_fixed(new_price); 16 | 17 | let txq = self.transaction_queue.clone(); 18 | let mut options = self.options.pool_verification_options.clone(); 19 | - self.gas_pricer.lock().recalibrate(move |gas_price| { 20 | + gp.recalibrate(move |gas_price| { 21 | debug!(target: "miner", "minimal_gas_price: Got gas price! {}", gas_price); 22 | options.minimal_gas_price = gas_price; 23 | txq.set_verifier_options(options); 24 | @@ -1686,6 +1688,7 @@ mod tests { 25 | assert!(current_minimum_gas_price == expected_minimum_gas_price); 26 | } 27 | 28 | + #[cfg(feature = "price-info")] 29 | fn dynamic_gas_pricer() -> GasPricer { 30 | use std::time::Duration; 31 | use parity_runtime::Executor; 32 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/5f1ce7f281b4f4bb03995ead519d948ae64237a4-0.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/src/network/host.rs b/util/src/network/host.rs 2 | index 4164c3f1a6c..05ccaa147fa 100644 3 | --- a/util/src/network/host.rs 4 | +++ b/util/src/network/host.rs 5 | @@ -442,9 +442,10 @@ impl Host where Message: Send + Sync + Clone { 6 | 7 | if info.config.non_reserved_mode != mode { 8 | info.config.non_reserved_mode = mode.clone(); 9 | + drop(info); 10 | if let NonReservedPeerMode::Deny = mode { 11 | // disconnect all non-reserved peers here. 12 | - let reserved = self.reserved_nodes.read().unwrap(); 13 | + let reserved: HashSet = self.reserved_nodes.read().unwrap().clone(); 14 | let mut to_kill = Vec::new(); 15 | for e in self.sessions.write().unwrap().iter_mut() { 16 | let mut s = e.lock().unwrap(); 17 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/5f1ce7f281b4f4bb03995ead519d948ae64237a4-1.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/src/network/host.rs b/util/src/network/host.rs 2 | index 4164c3f1a6c..05ccaa147fa 100644 3 | --- a/util/src/network/host.rs 4 | +++ b/util/src/network/host.rs 5 | @@ -442,9 +442,10 @@ impl Host where Message: Send + Sync + Clone { 6 | 7 | if info.config.non_reserved_mode != mode { 8 | info.config.non_reserved_mode = mode.clone(); 9 | + drop(info); 10 | if let NonReservedPeerMode::Deny = mode { 11 | // disconnect all non-reserved peers here. 12 | - let reserved = self.reserved_nodes.read().unwrap(); 13 | + let reserved: HashSet = self.reserved_nodes.read().unwrap().clone(); 14 | let mut to_kill = Vec::new(); 15 | for e in self.sessions.write().unwrap().iter_mut() { 16 | let mut s = e.lock().unwrap(); 17 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/5fc944ae1d2bf24017c6976acc20a4601484280c.txt: -------------------------------------------------------------------------------- 1 | diff --git a/miner/src/miner.rs b/miner/src/miner.rs 2 | index a45b34f8536..1ee339f64fe 100644 3 | --- a/miner/src/miner.rs 4 | +++ b/miner/src/miner.rs 5 | @@ -247,11 +247,11 @@ impl MinerService for Miner { 6 | match import { 7 | Ok(ref res) => { 8 | trace!(target: "own_tx", "Imported transaction to {:?} (hash: {:?})", res, hash); 9 | - trace!(target: "own_tx", "Status: {:?}", self.status()); 10 | + trace!(target: "own_tx", "Status: {:?}", self.transaction_queue.status()); 11 | }, 12 | Err(ref e) => { 13 | trace!(target: "own_tx", "Failed to import transaction {:?} (hash: {:?})", e, hash); 14 | - trace!(target: "own_tx", "Status: {:?}", self.status()); 15 | + trace!(target: "own_tx", "Status: {:?}", self.transaction_queue.status()); 16 | }, 17 | } 18 | import 19 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/63c959c4ee9aec1e8040ce3040fde9b55e388952.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/src/network/host.rs b/util/src/network/host.rs 2 | index bccc37dcfa8..73359402e95 100644 3 | --- a/util/src/network/host.rs 4 | +++ b/util/src/network/host.rs 5 | @@ -888,8 +888,7 @@ impl Host { 6 | } 7 | 8 | pub fn with_context(&self, protocol: ProtocolId, io: &IoContext, action: F) where F: Fn(&NetworkContext) { 9 | - let reserved = self.reserved_nodes.read().unwrap(); 10 | - let sessions = self.sessions.write().unwrap(); 11 | + let reserved = { self.reserved_nodes.read().unwrap() }; 12 | 13 | let context = NetworkContext::new(io, protocol, None, self.sessions.clone(), &reserved); 14 | action(&context); 15 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/73c19fd4b517dada829c31182e4fa15b872adbd0.txt: -------------------------------------------------------------------------------- 1 | diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs 2 | index 3328565ebf1..728de4deb7a 100644 3 | --- a/ethcore/src/miner/miner.rs 4 | +++ b/ethcore/src/miner/miner.rs 5 | @@ -168,12 +168,11 @@ pub struct Miner { 6 | // NOTE [ToDr] When locking always lock in this order! 7 | transaction_queue: Arc>, 8 | sealing_work: Mutex, 9 | - 10 | + next_allowed_reseal: Mutex, 11 | + sealing_block_last_request: Mutex, 12 | // for sealing... 13 | options: MinerOptions, 14 | 15 | - next_allowed_reseal: Mutex, 16 | - sealing_block_last_request: Mutex, 17 | gas_range_target: RwLock<(U256, U256)>, 18 | author: RwLock
, 19 | extra_data: RwLock, 20 | @@ -736,11 +735,11 @@ impl MinerService for Miner { 21 | fn update_sealing(&self, chain: &MiningBlockChainClient) { 22 | trace!(target: "miner", "update_sealing"); 23 | let requires_reseal = { 24 | + let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions(); 25 | let mut sealing_work = self.sealing_work.lock(); 26 | if sealing_work.enabled { 27 | trace!(target: "miner", "update_sealing: sealing enabled"); 28 | let current_no = chain.chain_info().best_block_number; 29 | - let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions(); 30 | let last_request = *self.sealing_block_last_request.lock(); 31 | let should_disable_sealing = !self.forced_sealing() 32 | && !has_local_transactions 33 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/79d996300bdfd2990cb7d60c50c11667fec5fcc7.txt: -------------------------------------------------------------------------------- 1 | diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs 2 | index 686a1d09314..2b466168201 100644 3 | --- a/ethcore/src/verification/queue/mod.rs 4 | +++ b/ethcore/src/verification/queue/mod.rs 5 | @@ -85,8 +85,11 @@ impl VerifierHandle { 6 | // signal to the verifier thread that it should conclude its 7 | // operations. 8 | fn conclude(&self) { 9 | - self.wake_up(); 10 | + // these flags must be set before unparking the thread. 11 | + // is an mfence necessary? 12 | self.deleting.store(true, AtomicOrdering::Release); 13 | + self.sleep.store(false, AtomicOrdering::SeqCst); 14 | + self.thread.thread().unpark(); 15 | } 16 | 17 | // join the verifier thread. 18 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/7c015f023fa8fa7eae9d0836595faa274b23ae5a.txt: -------------------------------------------------------------------------------- 1 | diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs 2 | index cb18f4fd46a..d09eef9e0fe 100644 3 | --- a/ethcore/src/trace/db.rs 4 | +++ b/ethcore/src/trace/db.rs 5 | @@ -264,10 +264,11 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { 6 | 7 | // at first, let's insert new block traces 8 | { 9 | + // note_used must be called before locking traces to avoid cache/traces deadlock on garbage collection 10 | + self.note_used(CacheID::Trace(request.block_hash.clone())); 11 | let mut traces = self.traces.write(); 12 | // it's important to use overwrite here, 13 | // cause this value might be queried by hash later 14 | - self.note_used(CacheID::Trace(request.block_hash.clone())); 15 | batch.write_with_cache(DB_COL_TRACE, traces.deref_mut(), request.block_hash, request.traces, CacheUpdatePolicy::Overwrite); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/8a8cfb133fbc8ed8652acd1559367c3e3cda451e.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/src/network/host.rs b/util/src/network/host.rs 2 | index e38edb76fe3..69ac37fa8bc 100644 3 | --- a/util/src/network/host.rs 4 | +++ b/util/src/network/host.rs 5 | @@ -751,7 +751,8 @@ impl Host { 6 | if let Some(session) = session.clone() { 7 | let mut s = session.lock(); 8 | loop { 9 | - match s.readable(io, &self.info.read()) { 10 | + let session_result = s.readable(io, &self.info.read()); 11 | + match session_result { 12 | Err(e) => { 13 | trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); 14 | if let UtilError::Network(NetworkError::Disconnect(DisconnectReason::IncompatibleProtocol)) = e { 15 | @@ -768,7 +769,6 @@ impl Host { 16 | self.num_sessions.fetch_add(1, AtomicOrdering::SeqCst); 17 | if !s.info.originated { 18 | let session_count = self.session_count(); 19 | - let reserved_nodes = self.reserved_nodes.read(); 20 | let (ideal_peers, reserved_only) = { 21 | let info = self.info.read(); 22 | (info.config.ideal_peers, info.config.non_reserved_mode == NonReservedPeerMode::Deny) 23 | @@ -776,7 +776,7 @@ impl Host { 24 | 25 | if session_count >= ideal_peers as usize || reserved_only { 26 | // only proceed if the connecting peer is reserved. 27 | - if !reserved_nodes.contains(s.id().unwrap()) { 28 | + if !self.reserved_nodes.read().contains(s.id().unwrap()) { 29 | s.disconnect(io, DisconnectReason::TooManyPeers); 30 | return; 31 | } 32 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/8b692e6d9db18f0f7150b8ee79b5a901039c573b.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/src/network/host.rs b/util/src/network/host.rs 2 | index feddf195292..70915bee34e 100644 3 | --- a/util/src/network/host.rs 4 | +++ b/util/src/network/host.rs 5 | @@ -777,7 +777,8 @@ impl IoHandler> for Host where Messa 6 | FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), 7 | FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io), 8 | DISCOVERY => { 9 | - if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().readable() { 10 | + let node_changes = { self.discovery.as_ref().unwrap().lock().unwrap().readable() }; 11 | + if let Some(node_changes) = node_changes { 12 | self.update_nodes(io, node_changes); 13 | } 14 | io.update_registration(DISCOVERY).expect("Error updating discovery registration"); 15 | @@ -809,7 +810,8 @@ impl IoHandler> for Host where Messa 16 | io.update_registration(DISCOVERY).expect("Error updating discovery registration"); 17 | }, 18 | DISCOVERY_ROUND => { 19 | - if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().round() { 20 | + let node_changes = { self.discovery.as_ref().unwrap().lock().unwrap().round() }; 21 | + if let Some(node_changes) = node_changes { 22 | self.update_nodes(io, node_changes); 23 | } 24 | io.update_registration(DISCOVERY).expect("Error updating discovery registration"); 25 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/8ed632eb961debe5b09fe1ed38fe2ff58701e607.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/src/network/host.rs b/util/src/network/host.rs 2 | index 42e8ff93db3..f2cc9fe4865 100644 3 | --- a/util/src/network/host.rs 4 | +++ b/util/src/network/host.rs 5 | @@ -400,7 +400,8 @@ impl Host where Message: Send + Sync + Clone { 6 | // public_endpoint in host info contains local adderss at this point 7 | let listen_address = self.info.read().unwrap().public_endpoint.address.clone(); 8 | let udp_port = self.info.read().unwrap().config.udp_port.unwrap_or(listen_address.port()); 9 | - let public_endpoint = match self.info.read().unwrap().config.public_address { 10 | + let public_address = self.info.read().unwrap().config.public_address.clone(); 11 | + let public_endpoint = match public_address { 12 | None => { 13 | let public_address = select_public_address(listen_address.port()); 14 | let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port }; 15 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/8fe73c9dd4bc37b7577c4a8391794ec651004b4c.txt: -------------------------------------------------------------------------------- 1 | diff --git a/updater/src/updater.rs b/updater/src/updater.rs 2 | index f9e235dd55a..d350c0f117b 100644 3 | --- a/updater/src/updater.rs 4 | +++ b/updater/src/updater.rs 5 | @@ -18,6 +18,7 @@ use std::sync::{Arc, Weak}; 6 | use std::fs; 7 | use std::io::Write; 8 | use std::path::{PathBuf}; 9 | +use std::mem::drop; 10 | use target_info::Target; 11 | use util::misc; 12 | use ipc_common_types::{VersionInfo, ReleaseTrack}; 13 | @@ -273,6 +274,7 @@ impl Updater { 14 | if s.fetching.is_none() { 15 | info!(target: "updater", "Attempting to get parity binary {}", b); 16 | s.fetching = Some(latest.track.clone()); 17 | + drop(s); 18 | let weak_self = self.weak_self.lock().clone(); 19 | let f = move |r: Result| if let Some(this) = weak_self.upgrade() { this.fetch_done(r) }; 20 | self.fetcher.lock().as_ref().expect("Created on `new`; qed").fetch(b, Box::new(f)); 21 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/a33e2f2e0d262382b6cc2bb77863c7d21cfb34b5.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/io/src/service.rs b/util/io/src/service.rs 2 | index 123d909386c..632af8d77c6 100644 3 | --- a/util/io/src/service.rs 4 | +++ b/util/io/src/service.rs 5 | @@ -249,7 +249,8 @@ impl Handler for IoManager where Message: Send + Clone + Sync 6 | let handler_index = token.0 / TOKENS_PER_HANDLER; 7 | let token_id = token.0 % TOKENS_PER_HANDLER; 8 | if let Some(handler) = self.handlers.read().get(handler_index) { 9 | - if let Some(timer) = self.timers.read().get(&token.0) { 10 | + let maybe_timer = self.timers.read().get(&token.0).cloned(); 11 | + if let Some(timer) = maybe_timer { 12 | if timer.once { 13 | self.timers.write().remove(&token_id); 14 | event_loop.clear_timeout(&timer.timeout); 15 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/parity-ethereum/ab079fd7bf7d7f9ad04c6fe581dd680480fe5303.txt: -------------------------------------------------------------------------------- 1 | diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs 2 | index d09eef9e0fe..b03380829f1 100644 3 | --- a/ethcore/src/trace/db.rs 4 | +++ b/ethcore/src/trace/db.rs 5 | @@ -294,10 +294,11 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { 6 | .map(|p| (From::from(p.0), From::from(p.1))) 7 | .collect::>(); 8 | 9 | - let mut blooms = self.blooms.write(); 10 | + // note_used must be called before locking blooms to avoid cache/traces deadlock on garbage collection 11 | for key in blooms_to_insert.keys() { 12 | self.note_used(CacheID::Bloom(key.clone())); 13 | } 14 | + let mut blooms = self.blooms.write(); 15 | batch.extend_with_cache(DB_COL_TRACE, blooms.deref_mut(), blooms_to_insert, CacheUpdatePolicy::Remove); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/rayon/f17d745e12511516396f6ba5027a30e88e981bfb.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/latch.rs b/src/latch.rs 2 | index 436d74c8..3028f859 100644 3 | --- a/src/latch.rs 4 | +++ b/src/latch.rs 5 | @@ -44,8 +44,7 @@ impl Latch for SpinLatch { 6 | /// A Latch starts as false and eventually becomes true. You can block 7 | /// until it becomes true. 8 | pub struct LockLatch { 9 | - b: AtomicBool, 10 | - m: Mutex<()>, 11 | + m: Mutex, 12 | v: Condvar, 13 | } 14 | 15 | @@ -53,8 +52,7 @@ impl LockLatch { 16 | #[inline] 17 | pub fn new() -> LockLatch { 18 | LockLatch { 19 | - b: AtomicBool::new(false), 20 | - m: Mutex::new(()), 21 | + m: Mutex::new(false), 22 | v: Condvar::new(), 23 | } 24 | } 25 | @@ -63,14 +61,15 @@ impl LockLatch { 26 | impl Latch for LockLatch { 27 | /// Set the latch to true, releasing all threads who are waiting. 28 | fn set(&self) { 29 | - self.b.store(true, Ordering::Release); 30 | + let mut guard = self.m.lock().unwrap(); 31 | + *guard = true; 32 | self.v.notify_all(); 33 | } 34 | 35 | /// Spin until latch is set. Use with caution. 36 | fn wait(&self) { 37 | let mut guard = self.m.lock().unwrap(); 38 | - while !self.probe() { 39 | + while !*guard { 40 | guard = self.v.wait(guard).unwrap(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/servo/13fe502cd63d3adc19a36a34447c09fab38ae47c.txt: -------------------------------------------------------------------------------- 1 | diff --git a/components/net/sniffer_task.rs b/components/net/sniffer_task.rs 2 | index 05fade8ca90e..2fcc0394f522 100644 3 | --- a/components/net/sniffer_task.rs 4 | +++ b/components/net/sniffer_task.rs 5 | @@ -3,7 +3,7 @@ 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 | 8 | //! A task that sniffs data 9 | -use std::comm::{channel, Receiver, Sender, Disconnected}; 10 | +use std::comm::{channel, Receiver, Sender}; 11 | use std::task::TaskBuilder; 12 | use resource_task::{TargetedLoadResponse}; 13 | 14 | @@ -33,15 +33,11 @@ impl SnifferManager { 15 | impl SnifferManager { 16 | fn start(self) { 17 | loop { 18 | - match self.data_receiver.try_recv() { 19 | + match self.data_receiver.recv_opt() { 20 | Ok(snif_data) => { 21 | - let result = snif_data.consumer.send_opt(snif_data.load_response); 22 | - if result.is_err() { 23 | - break; 24 | - } 25 | + let _ = snif_data.consumer.send_opt(snif_data.load_response); 26 | } 27 | - Err(Disconnected) => break, 28 | - Err(_) => (), 29 | + Err(_) => break, 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/servo/183c387d8b5c9c2b19fea77517f09bf8b23f42f2.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/components/main/compositing/run.rs b/src/components/main/compositing/run.rs 2 | index b8125665543b..12bdafa2df71 100644 3 | --- a/src/components/main/compositing/run.rs 4 | +++ b/src/components/main/compositing/run.rs 5 | @@ -421,4 +421,8 @@ pub fn run_compositor(compositor: &CompositorTask) { 6 | None => {} 7 | Some(ref mut layer) => layer.forget_all_tiles(), 8 | } 9 | + 10 | + // Drain compositor port, sometimes messages contain channels that are blocking 11 | + // another task from finishing (i.e. SetIds) 12 | + while compositor.port.peek() { compositor.port.recv(); } 13 | } 14 | diff --git a/src/components/main/constellation.rs b/src/components/main/constellation.rs 15 | index bdd1b87c8d59..aa63afb6fc2d 100644 16 | --- a/src/components/main/constellation.rs 17 | +++ b/src/components/main/constellation.rs 18 | @@ -807,9 +807,13 @@ impl Constellation { 19 | fn set_ids(&self, frame_tree: @mut FrameTree) { 20 | let (port, chan) = comm::stream(); 21 | self.compositor_chan.send(SetIds(frame_tree.to_sendable(), chan, self.chan.clone())); 22 | - port.try_recv(); 23 | - for frame in frame_tree.iter() { 24 | - frame.pipeline.grant_paint_permission(); 25 | + match port.try_recv() { 26 | + Some(()) => { 27 | + for frame in frame_tree.iter() { 28 | + frame.pipeline.grant_paint_permission(); 29 | + } 30 | + } 31 | + None => {} // message has been discarded, probably shutting down 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/servo/2952ccfae2e4883efc4886988dcf17d07d89f66c.txt: -------------------------------------------------------------------------------- 1 | diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs 2 | index bc77361b5ae2..1f1573a05d5a 100644 3 | --- a/components/script/dom/cssrulelist.rs 4 | +++ b/components/script/dom/cssrulelist.rs 5 | @@ -90,9 +90,12 @@ impl CSSRuleList { 6 | let index = idx as usize; 7 | 8 | let parent_stylesheet = self.parent_stylesheet.style_stylesheet(); 9 | - let mut guard = parent_stylesheet.shared_lock.write(); 10 | - let new_rule = css_rules.write_with(&mut guard) 11 | - .insert_rule(rule, parent_stylesheet, index, nested)?; 12 | + let new_rule = { 13 | + let mut guard = parent_stylesheet.shared_lock.write(); 14 | + css_rules.write_with(&mut guard).insert_rule(rule, parent_stylesheet, index, nested)? 15 | + // Drop `guard` here, 16 | + // CSSRule::new_specific re-acquires the lock for @support and @media. 17 | + }; 18 | 19 | let parent_stylesheet = &*self.parent_stylesheet; 20 | let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule); 21 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/servo/6fbd2aa5b7628bd47971806ddf438cd350a60bee.txt: -------------------------------------------------------------------------------- 1 | diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs 2 | index 23fb67ce82b9..1f3eb0e5a24c 100644 3 | --- a/components/net/fetch/methods.rs 4 | +++ b/components/net/fetch/methods.rs 5 | @@ -361,13 +361,14 @@ fn main_fetch(request: Rc, cache: &mut CORSCache, cors_flag: bool, 6 | } 7 | } 8 | } else if let Some(ref mut target) = *target { 9 | - if let ResponseBody::Done(ref vec) = *response.body.lock().unwrap() { 10 | + let body = response.body.lock().unwrap(); 11 | + if let ResponseBody::Done(ref vec) = *body { 12 | // in case there was no channel to wait for, the body was 13 | // obtained synchronously via basic_fetch for data/file/about/etc 14 | // We should still send the body across as a chunk 15 | target.process_response_chunk(vec.clone()); 16 | } else { 17 | - assert!(*response.body.lock().unwrap() == ResponseBody::Empty) 18 | + assert!(*body == ResponseBody::Empty) 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/servo/702445a3ec4d406472a618750f5dab64c38459bb.txt: -------------------------------------------------------------------------------- 1 | diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs 2 | index 2237514bd3d3..018c616bca54 100644 3 | --- a/components/script/dom/window.rs 4 | +++ b/components/script/dom/window.rs 5 | @@ -450,13 +450,15 @@ impl WindowMethods for Window { 6 | // Right now, just print to the console 7 | // Ensure that stderr doesn't trample through the alert() we use to 8 | // communicate test results (see executorservo.py in wptrunner). 9 | - let stderr = stderr(); 10 | - let mut stderr = stderr.lock(); 11 | - let stdout = stdout(); 12 | - let mut stdout = stdout.lock(); 13 | - writeln!(&mut stdout, "ALERT: {}", s).unwrap(); 14 | - stdout.flush().unwrap(); 15 | - stderr.flush().unwrap(); 16 | + { 17 | + let stderr = stderr(); 18 | + let mut stderr = stderr.lock(); 19 | + let stdout = stdout(); 20 | + let mut stdout = stdout.lock(); 21 | + writeln!(&mut stdout, "ALERT: {}", s).unwrap(); 22 | + stdout.flush().unwrap(); 23 | + stderr.flush().unwrap(); 24 | + } 25 | 26 | let (sender, receiver) = ipc::channel().unwrap(); 27 | self.constellation_chan().send(ConstellationMsg::Alert(self.pipeline(), s.to_string(), sender)).unwrap(); 28 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/blocking-bugs/tikv/cd330aa9c1cea04b99d9f813e2c9e03d453ac1b8.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/storage/txn/scheduler.rs b/src/storage/txn/scheduler.rs 2 | index fb39329a6e..584a7ed577 100644 3 | --- a/src/storage/txn/scheduler.rs 4 | +++ b/src/storage/txn/scheduler.rs 5 | @@ -540,6 +540,8 @@ impl Scheduler { 6 | } else { 7 | execute_callback(cb, pr); 8 | } 9 | + 10 | + self.release_lock(&ctx.lock, cid); 11 | } 12 | 13 | fn on_write_prepare_failed(&mut self, cid: u64, e: Error) { 14 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/parse_manual_drop_log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | 6 | INIT = 0 7 | INFO = 1 8 | LOCK = 2 9 | NEXT = 3 10 | 11 | def main(): 12 | input_file = sys.argv[1] 13 | lock_line = "" 14 | drop_line = "" 15 | with open(input_file) as infile: 16 | state = INIT 17 | for line in infile.readlines(): 18 | if state == INIT: 19 | if line == "Manual Drop Info:\n": 20 | state = INFO 21 | else: 22 | state = NEXT 23 | elif state == INFO: 24 | content = line.strip() 25 | if content.startswith("/rust"): 26 | state = NEXT 27 | else: 28 | lock_line = line 29 | state = LOCK 30 | elif state == LOCK: 31 | content = line.strip() 32 | if content.startswith("/rust"): 33 | state = NEXT 34 | else: 35 | drop_line = line 36 | print("Manual Drop Info:") 37 | print(lock_line, end="") 38 | print(drop_line, end="") 39 | state = NEXT 40 | elif state == NEXT: 41 | if line == "Manual Drop Info:\n": 42 | state = INFO 43 | else: 44 | state = NEXT 45 | else: 46 | assert False 47 | 48 | if __name__ == "__main__": 49 | main() -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BC_DIR="$1" 4 | MANUAL_DROP_LIB=ManualDropPrinter/build/lib/PrintManualDrop/libPrintManualDrop.so 5 | LOG_FILE=./manual_drop.log 6 | 7 | for bc in `ls -1v ${BC_DIR}/*.m2r.bc` 8 | do 9 | opt -load ${MANUAL_DROP_LIB} -print $bc 10 | done 1>/dev/null 2>${LOG_FILE} 11 | 12 | ./parse_manual_drop_log.py ${LOG_FILE} 13 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-1-blocking-bugs/run_all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BC_DIR="$1" 4 | 5 | # build 6 | cd ManualDropPrinter 7 | mkdir -p build 8 | cd build 9 | cmake .. 10 | make 11 | cd ../.. 12 | 13 | # run 14 | for APP in ${BC_DIR}/* 15 | do 16 | if [ -d ${APP} ] 17 | then 18 | echo ${APP} 19 | ./run.sh ${APP}/m2r 20 | fi 21 | done 22 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/crossbeam/268c02814a6589577dffada83174532f6111c352.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/mem/epoch/garbage.rs b/src/mem/epoch/garbage.rs 2 | index 38c96494..d331e455 100644 3 | --- a/src/mem/epoch/garbage.rs 4 | +++ b/src/mem/epoch/garbage.rs 5 | @@ -9,7 +9,7 @@ 6 | use std::ptr; 7 | use std::mem; 8 | use std::sync::atomic::AtomicPtr; 9 | -use std::sync::atomic::Ordering::{Relaxed, Release}; 10 | +use std::sync::atomic::Ordering::{Relaxed, Release, Acquire}; 11 | 12 | use mem::ZerosValid; 13 | 14 | @@ -124,13 +124,17 @@ impl ConcBag { 15 | } 16 | 17 | pub unsafe fn collect(&self) { 18 | + // check to avoid xchg instruction 19 | + // when no garbage exists 20 | let mut head = self.head.load(Relaxed); 21 | - self.head.store(ptr::null_mut(), Relaxed); 22 | - 23 | - while head != ptr::null_mut() { 24 | - let mut n = Box::from_raw(head); 25 | - n.data.collect(); 26 | - head = n.next.load(Relaxed); 27 | + if head != ptr::null_mut() { 28 | + head = self.head.swap(ptr::null_mut(), Acquire); 29 | + 30 | + while head != ptr::null_mut() { 31 | + let mut n = Box::from_raw(head); 32 | + n.data.collect(); 33 | + head = n.next.load(Relaxed); 34 | + } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/crossbeam/6e333047cebf3bcb6d9e87794ee809b653d8bdba.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/sync/ms_queue.rs b/src/sync/ms_queue.rs 2 | index c28d1097..b0154c14 100644 3 | --- a/src/sync/ms_queue.rs 4 | +++ b/src/sync/ms_queue.rs 5 | @@ -1,5 +1,5 @@ 6 | -use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; 7 | -use std::sync::atomic::AtomicBool; 8 | +use std::sync::atomic::Ordering::{Acquire, Release, Relaxed, SeqCst}; 9 | +use std::sync::atomic::{AtomicBool, fence}; 10 | use std::{ptr, mem}; 11 | use std::thread::{self, Thread}; 12 | 13 | @@ -174,8 +174,10 @@ impl MsQueue { 14 | unsafe { 15 | // signal the thread 16 | (*signal).data = Some(cache.into_data()); 17 | - (*signal).ready.store(true, Release); 18 | - (*signal).thread.unpark(); 19 | + let thread = (*signal).thread.clone(); 20 | + 21 | + (*signal).ready.store(true, Relaxed); 22 | + thread.unpark(); 23 | guard.unlinked(head); 24 | return; 25 | } 26 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/crossbeam/9d423946835b69edb395a5654b85649161f34d3b.txt: -------------------------------------------------------------------------------- 1 | diff --git a/crossbeam-channel/src/flavors/list.rs b/crossbeam-channel/src/flavors/list.rs 2 | index fc7acd93..fed645cb 100644 3 | --- a/crossbeam-channel/src/flavors/list.rs 4 | +++ b/crossbeam-channel/src/flavors/list.rs 5 | @@ -247,10 +247,8 @@ impl Channel { 6 | // If we've reached the end of the block, install the next one. 7 | if offset + 1 == BLOCK_CAP { 8 | let next_block = Box::into_raw(next_block.unwrap()); 9 | - let next_index = new_tail.wrapping_add(1 << SHIFT); 10 | - 11 | self.tail.block.store(next_block, Ordering::Release); 12 | - self.tail.index.store(next_index, Ordering::Release); 13 | + self.tail.index.fetch_add(1 << SHIFT, Ordering::Release); 14 | (*block).next.store(next_block, Ordering::Release); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/crossbeam/eab00e91147c93ca4646c1ba06f2f16054b30e77.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/mem/epoch/participant.rs b/src/mem/epoch/participant.rs 2 | index e7466a40..94a7fe8a 100644 3 | --- a/src/mem/epoch/participant.rs 4 | +++ b/src/mem/epoch/participant.rs 5 | @@ -99,10 +99,10 @@ impl Participant { 6 | return false 7 | } 8 | 9 | - self.epoch.store(new_epoch, Relaxed); 10 | unsafe { 11 | global::get().garbage[new_epoch.wrapping_add(1) % 3].collect(); 12 | } 13 | + self.epoch.store(new_epoch, Release); 14 | self.num_ops.set(0); 15 | 16 | true 17 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/parity-ethereum/145e766db2de4b20b208a9bb2478479b74f855fe.txt: -------------------------------------------------------------------------------- 1 | diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs 2 | index 52aecb465b7..1130b8fb8a0 100644 3 | --- a/rpc/src/v1/impls/ethcore.rs 4 | +++ b/rpc/src/v1/impls/ethcore.rs 5 | @@ -302,7 +302,9 @@ impl Ethcore for EthcoreClient where 6 | .map(Into::into); 7 | 8 | // Receive ready and invoke with result. 9 | - let ready: Ready = rx.try_recv().expect("When on_done is invoked ready object is always sent."); 10 | + let ready: Ready = rx.recv().expect( 11 | + "recv() fails when `tx` has been dropped, if this closure is invoked `tx` is not dropped (`res == Ok()`); qed" 12 | + ); 13 | ready.ready(result); 14 | })); 15 | 16 | @@ -310,7 +312,9 @@ impl Ethcore for EthcoreClient where 17 | if let Err(e) = res { 18 | ready.ready(Err(errors::from_fetch_error(e))); 19 | } else { 20 | - tx.send(ready).expect("Rx end is sent to on_done closure."); 21 | + tx.send(ready).expect( 22 | + "send() fails when `rx` end is dropped, if `res == Ok()`: `rx` is moved to the closure; qed" 23 | + ); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/parity-ethereum/7503d6695a8ef22fa0aa4530745ceed95a260f63.txt: -------------------------------------------------------------------------------- 1 | diff --git a/util/src/network/host.rs b/util/src/network/host.rs 2 | index 04dda02bd6e..fe283e21a2d 100644 3 | --- a/util/src/network/host.rs 4 | +++ b/util/src/network/host.rs 5 | @@ -635,7 +635,13 @@ impl Host where Message: Send + Sync + Clone { 6 | 7 | // turn a handshake into a session 8 | let mut sessions = self.sessions.write().unwrap(); 9 | - let h = handshakes.remove(token).unwrap(); 10 | + let mut h = handshakes.remove(token).unwrap(); 11 | + // wait for other threads to stop using it 12 | + { 13 | + while Arc::get_mut(&mut h).is_none() { 14 | + h.lock().ok(); 15 | + } 16 | + } 17 | let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap(); 18 | let result = sessions.insert_with(move |session_token| { 19 | let session = Session::new(h, session_token, &self.info.read().unwrap()).expect("Session creation error"); 20 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/parity-ethereum/796482c12917768e09376557f0c37adc057bf322.txt: -------------------------------------------------------------------------------- 1 | diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs 2 | index 22860ebbd74..a00fe70ca14 100644 3 | --- a/ethcore/src/engines/authority_round.rs 4 | +++ b/ethcore/src/engines/authority_round.rs 5 | @@ -319,14 +319,20 @@ impl Engine for AuthorityRound { 6 | /// This operation is synchronous and may (quite reasonably) not be available, in which `false` will 7 | /// be returned. 8 | fn generate_seal(&self, block: &ExecutedBlock) -> Seal { 9 | + // first check to avoid generating signature most of the time 10 | + // (but there's still a race to the `compare_and_swap`) 11 | if self.proposed.load(AtomicOrdering::SeqCst) { return Seal::None; } 12 | + 13 | let header = block.header(); 14 | let step = self.step.load(); 15 | if self.is_step_proposer(header.parent_hash(), step, header.author()) { 16 | if let Ok(signature) = self.signer.sign(header.bare_hash()) { 17 | trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step); 18 | - self.proposed.store(true, AtomicOrdering::SeqCst); 19 | - return Seal::Regular(vec![encode(&step).to_vec(), encode(&(&H520::from(signature) as &[u8])).to_vec()]); 20 | + 21 | + // only issue the seal if we were the first to reach the compare_and_swap. 22 | + if !self.proposed.compare_and_swap(false, true, AtomicOrdering::SeqCst) { 23 | + return Seal::Regular(vec![encode(&step).to_vec(), encode(&(&H520::from(signature) as &[u8])).to_vec()]); 24 | + } 25 | } else { 26 | warn!(target: "engine", "generate_seal: FAIL: Accounts secret key unavailable."); 27 | } 28 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/rand/e0e8263c25dc291f818cd20c034912de5ae05189.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/os.rs b/src/os.rs 2 | index 1b32ccbbdd..116641f9e3 100644 3 | --- a/src/os.rs 4 | +++ b/src/os.rs 5 | @@ -96,11 +96,12 @@ mod imp { 6 | target_arch = "powerpc")))] 7 | fn is_getrandom_available() -> bool { 8 | use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; 9 | + use std::sync::{Once, ONCE_INIT}; 10 | 11 | - static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT; 12 | - static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; 13 | + static CHECKER: Once = ONCE_INIT; 14 | + static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; 15 | 16 | - if !GETRANDOM_CHECKED.load(Ordering::Relaxed) { 17 | + CHECKER.call_once(|| { 18 | let mut buf: [u8; 0] = []; 19 | let result = getrandom(&mut buf); 20 | let available = if result == -1 { 21 | @@ -109,12 +110,10 @@ mod imp { 22 | } else { 23 | true 24 | }; 25 | - GETRANDOM_AVAILABLE.store(available, Ordering::Relaxed); 26 | - GETRANDOM_CHECKED.store(true, Ordering::Relaxed); 27 | - available 28 | - } else { 29 | - GETRANDOM_AVAILABLE.load(Ordering::Relaxed) 30 | - } 31 | + AVAILABLE.store(available, Ordering::Relaxed); 32 | + }); 33 | + 34 | + AVAILABLE.load(Ordering::Relaxed) 35 | } 36 | 37 | #[cfg(not(all(target_os = "linux", 38 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/servo/2a7f262b7df8761261a0fa618394f4e991733a5e.txt: -------------------------------------------------------------------------------- 1 | diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs 2 | index d7a9e9f243a5..4e90cc71012d 100644 3 | --- a/components/script/dom/window.rs 4 | +++ b/components/script/dom/window.rs 5 | @@ -72,6 +72,7 @@ use std::cell::{Cell, Ref, RefMut, RefCell}; 6 | use std::collections::HashSet; 7 | use std::default::Default; 8 | use std::ffi::CString; 9 | +use std::io::{stdout, Write}; 10 | use std::mem as std_mem; 11 | use std::rc::Rc; 12 | use std::sync::Arc; 13 | @@ -342,7 +343,10 @@ impl<'a> WindowMethods for &'a Window { 14 | // https://html.spec.whatwg.org/#dom-alert 15 | fn Alert(self, s: DOMString) { 16 | // Right now, just print to the console 17 | - println!("ALERT: {}", s); 18 | + let stdout = stdout(); 19 | + let mut stdout = stdout.lock(); 20 | + writeln!(&mut stdout, "ALERT: {}", s).unwrap(); 21 | + stdout.flush().unwrap(); 22 | } 23 | 24 | // https://html.spec.whatwg.org/multipage/#dom-window-close 25 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/servo/362c2718f7147a633eeb3b1cfd45aa13a0bf4250.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/components/main/css/matching.rs b/src/components/main/css/matching.rs 2 | index 299147b01a2f..1186ebb17daa 100644 3 | --- a/src/components/main/css/matching.rs 4 | +++ b/src/components/main/css/matching.rs 5 | @@ -46,7 +46,9 @@ impl MatchMethods for AbstractNode { 6 | } 7 | } 8 | fn match_subtree(&self, stylist: RWArc) { 9 | - let num_tasks = rt::default_sched_threads() * 2; 10 | + // FIXME(pcwalton): Racy. Parallel CSS selector matching is disabled. 11 | + //let num_tasks = rt::default_sched_threads() * 2; 12 | + let num_tasks = 1; 13 | let mut node_count = 0; 14 | let mut nodes_per_task = vec::from_elem(num_tasks, ~[]); 15 | 16 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/servo/89e129bf9f0d2d388f7506854aa2eb2456cb2d4d.txt: -------------------------------------------------------------------------------- 1 | diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs 2 | index d2f045de0d1c..2017f0b4b09f 100644 3 | --- a/components/constellation/constellation.rs 4 | +++ b/components/constellation/constellation.rs 5 | @@ -342,9 +342,8 @@ impl Log for FromScriptLogger { 6 | let pipeline_id = PipelineId::installed(); 7 | let thread_name = thread::current().name().map(ToOwned::to_owned); 8 | let msg = FromScriptMsg::LogEntry(pipeline_id, thread_name, entry); 9 | - if let Ok(chan) = self.constellation_chan.lock() { 10 | - let _ = chan.send(msg); 11 | - } 12 | + let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner()); 13 | + let _ = chan.send(msg); 14 | } 15 | } 16 | } 17 | @@ -381,9 +380,8 @@ impl Log for FromCompositorLogger { 18 | let pipeline_id = PipelineId::installed(); 19 | let thread_name = thread::current().name().map(ToOwned::to_owned); 20 | let msg = FromCompositorMsg::LogEntry(pipeline_id, thread_name, entry); 21 | - if let Ok(chan) = self.constellation_chan.lock() { 22 | - let _ = chan.send(msg); 23 | - } 24 | + let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner()); 25 | + let _ = chan.send(msg); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/servo/c98d35ea6b70d341696e72f1d8aeff9dd945f423.txt: -------------------------------------------------------------------------------- 1 | diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs 2 | index d31eb3d35270..38100d87d16e 100644 3 | --- a/components/script/dom/window.rs 4 | +++ b/components/script/dom/window.rs 5 | @@ -72,7 +72,7 @@ use std::cell::{Cell, Ref, RefMut, RefCell}; 6 | use std::collections::HashSet; 7 | use std::default::Default; 8 | use std::ffi::CString; 9 | -use std::io::{stdout, Write}; 10 | +use std::io::{stdout, stderr, Write}; 11 | use std::mem as std_mem; 12 | use std::rc::Rc; 13 | use std::sync::Arc; 14 | @@ -361,10 +361,15 @@ impl<'a> WindowMethods for &'a Window { 15 | // https://html.spec.whatwg.org/#dom-alert 16 | fn Alert(self, s: DOMString) { 17 | // Right now, just print to the console 18 | + // Ensure that stderr doesn't trample through the alert() we use to 19 | + // communicate test results. 20 | + let stderr = stderr(); 21 | + let mut stderr = stderr.lock(); 22 | let stdout = stdout(); 23 | let mut stdout = stdout.lock(); 24 | writeln!(&mut stdout, "ALERT: {}", s).unwrap(); 25 | stdout.flush().unwrap(); 26 | + stderr.flush().unwrap(); 27 | } 28 | 29 | // https://html.spec.whatwg.org/multipage/#dom-window-close 30 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/servo/d11716e27b539a98bba64f25c79c06ad92a409aa.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/components/main/layout/parallel.rs b/src/components/main/layout/parallel.rs 2 | index 983ba09d4d52..44ce3b9fad89 100644 3 | --- a/src/components/main/layout/parallel.rs 4 | +++ b/src/components/main/layout/parallel.rs 5 | @@ -299,7 +299,15 @@ fn recalc_style_for_node(unsafe_layout_node: UnsafeLayoutNode, 6 | } 7 | &None => fail!("no layout data"), 8 | } 9 | + } 10 | 11 | + // It's *very* important that this block is in a separate scope to the block above, 12 | + // to avoid a data race that can occur (github issue #2308). The block above issues 13 | + // a borrow on the node layout data. That borrow must be dropped before the child 14 | + // nodes are actually pushed into the work queue. Otherwise, it's possible for a child 15 | + // node to get into construct_flows() and move up it's parent hierarchy, which can call 16 | + // borrow on the layout data before it is dropped from the block above. 17 | + if child_count != 0 { 18 | // Enqueue kids. 19 | for kid in node.children() { 20 | proxy.push(WorkUnit { 21 | -------------------------------------------------------------------------------- /section-6-thread-safety-issues/section-6-2-non-blocking-bugs/non-blocking-bugs/tikv/f3a1bedd3b726e6af42e05d4a4cc3d15b739251f.txt: -------------------------------------------------------------------------------- 1 | diff --git a/src/util/config.rs b/src/util/config.rs 2 | index 9b1d9748d1..e2148834d3 100644 3 | --- a/src/util/config.rs 4 | +++ b/src/util/config.rs 5 | @@ -749,6 +749,7 @@ mod check_data_dir { 6 | use std::io::Read; 7 | use std::ffi::{CStr, CString}; 8 | use std::path::Path; 9 | + use std::sync::Mutex; 10 | use libc; 11 | 12 | use super::{canonicalize_path, ConfigError}; 13 | @@ -762,7 +763,16 @@ mod check_data_dir { 14 | } 15 | 16 | fn get_fs_info(path: &str, mnt_file: &str) -> Result { 17 | + lazy_static! { 18 | + // According `man 3 getmntent`, The pointer returned by `getmntent` points 19 | + // to a static area of memory which is overwritten by subsequent calls. 20 | + // So we use a lock to protect it in order to avoid `make dev` fail. 21 | + static ref GETMNTENT_LOCK: Mutex<()> = Mutex::new(()); 22 | + } 23 | + 24 | unsafe { 25 | + let _lock = GETMNTENT_LOCK.lock().unwrap(); 26 | + 27 | let profile = CString::new(mnt_file).unwrap(); 28 | let retype = CString::new("r").unwrap(); 29 | let afile = libc::setmntent(profile.as_ptr(), retype.as_ptr()); 30 | -------------------------------------------------------------------------------- /section-7-bug-detection/applications/README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | This directory contents source code and the Rust's mid-level intermediate representation 4 | (MIR) of the application (Redox-relibc. [GitLab](https://gitlab.redox-os.org/redox-os/relibc)), 5 | which has four previously unknown use-after-free bugs detected by our use-after-free detector. (Sec. 7.1. Lines 1228-1229). 6 | 7 | ## relibc 8 | 9 | This directory contents the source code of the relibc version we used for PLDI'20 submission. 10 | 11 | 12 | ## relibc_mir_detected_bugs 13 | 14 | You can directly run our use-after-free detector on those MIR files. The detailed 15 | instructions is in the README file under the detector's root directory. 16 | This directory only has the MIR files of the four detected bugs mentioned Sec. 7.1. 17 | You can dump all MIR files by 18 | 19 | ``` 20 | cd relibc 21 | cargo clean && cargo rustc -- -Zdump-mir="PreCodegen" 22 | ``` -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.1-detecting-memory-bugs/run_uaf_detector.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd ../applications/relibc 3 | cargo clean && cargo rustc -- -Zdump-mir="PreCodegen" 4 | cd ../../section-7.1-detecting-memory-bugs/use-after-free-detector 5 | python3 main.py ../../applications/relibc/mir_dump 6 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.1-detecting-memory-bugs/use-after-free-detector/basic_block.py: -------------------------------------------------------------------------------- 1 | class BasicBlock: 2 | def __init__(self, name): 3 | self.name = name 4 | self.statements = [] 5 | self.marked = 0 6 | 7 | def get_name(self): 8 | return self.name 9 | 10 | def add_statement(self, statement): 11 | self.statements.append(statement.strip()) 12 | 13 | def get_statements(self): 14 | return self.statements 15 | 16 | def dump(self): 17 | print(" BasicBlock: " + self.name) 18 | for s in self.statements: 19 | print(" " + s) 20 | 21 | def find_lifetime_termination(self): 22 | for s in self.statements: 23 | left = s.split('(')[0] 24 | if left == 'drop': 25 | print(self.name + ': ' + s) 26 | 27 | def find_successors(self): 28 | successors = [] 29 | for statement in self.statements: 30 | if '->' in statement: 31 | right = statement.split('->')[1].split('//')[0].strip().strip(';') 32 | if right.startswith('[') and right.endswith(']'): 33 | tokens = right[1:-1].split(', ') 34 | for token in tokens: 35 | bb_name = token.split(': ')[1] 36 | successors.append(bb_name) 37 | else: 38 | if self.is_basic_block_name(right): 39 | successors.append(right) 40 | return successors 41 | 42 | @staticmethod 43 | def is_basic_block_name(name): 44 | if name.startswith('bb'): 45 | return True 46 | else: 47 | return False -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.1-detecting-memory-bugs/use-after-free-detector/define_types.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class VariableType(Enum): 5 | Scalar = 0 6 | Object = 1 7 | Reference = 2 8 | Pointer = 3 9 | Unset = 999 10 | 11 | 12 | class LifetimeState(Enum): 13 | Alive = 0 14 | Terminated = 1 15 | Forgot = 2 16 | Uninitialized = 999 17 | 18 | 19 | class StatementType(Enum): 20 | Assignment = 0 21 | TerminateLifetime = 1 22 | Other = 10 23 | Unset = 999 24 | 25 | 26 | class DestinationType(Enum): 27 | Local = 0 28 | Global = 1 29 | LocalPartial = 2 30 | GlobalPartial = 3 31 | 32 | 33 | class AssignmentType(Enum): 34 | Regular = 0, 35 | # destination variable cannot be this type 36 | Reference = 1, 37 | Dereference = 2, 38 | 39 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/DoubleLockDetector/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(RustBugDetector) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | find_package(LLVM REQUIRED CONFIG) 7 | add_definitions(${LLVM_DEFINITIONS}) 8 | include_directories(${LLVM_INCLUDE_DIRS}) 9 | link_directories(${LLVM_LIBRARY_DIRS}) 10 | include_directories("${PROJECT_SOURCE_DIR}/include") 11 | add_subdirectory(lib) -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/DoubleLockDetector/include/Common/CallerFunc.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINTPASS_GETCALLERFUNC_H 2 | #define PRINTPASS_GETCALLERFUNC_H 3 | 4 | #include "llvm/IR/Instruction.h" 5 | #include "llvm/IR/Function.h" 6 | #include "llvm/IR/CallSite.h" 7 | 8 | bool isCallOrInvokeInst(llvm::Instruction *I); 9 | 10 | llvm::Function *getCalledFunc(llvm::Instruction *pInst, llvm::CallSite &CS); 11 | 12 | #endif //PRINTPASS_GETCALLERFUNC_H 13 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/DoubleLockDetector/include/RustDoubleLockDetector/RustDoubleLockDetector.h: -------------------------------------------------------------------------------- 1 | #ifndef RUSTBUGDETECTOR_RUSTDOUBLELOCKDETECTOR_H 2 | #define RUSTBUGDETECTOR_RUSTDOUBLELOCKDETECTOR_H 3 | 4 | #include "llvm/Pass.h" 5 | 6 | namespace detector { 7 | struct RustDoubleLockDetector : public llvm::ModulePass { 8 | 9 | static char ID; 10 | 11 | RustDoubleLockDetector(); 12 | 13 | void getAnalysisUsage(llvm::AnalysisUsage &AU) const override; 14 | 15 | bool runOnModule(llvm::Module &M) override; 16 | 17 | private: 18 | 19 | llvm::Module *pModule; 20 | }; 21 | } 22 | 23 | #endif //RUSTBUGDETECTOR_RustDOUBLELOCKDETECTOR_H 24 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/DoubleLockDetector/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Common) 2 | add_subdirectory(RustDoubleLockDetector) 3 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/DoubleLockDetector/lib/Common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(CommonLib STATIC 2 | # List your source files here. 3 | CallerFunc.cpp 4 | ) 5 | 6 | # Use C++11 to compile our pass (i.e., supply -std=c++11). 7 | target_compile_features(CommonLib PRIVATE cxx_range_for cxx_auto_type) 8 | 9 | # LLVM is (typically) built with no C++ RTTI. We need to match that; 10 | # otherwise, we'll get linker errors about missing RTTI data. 11 | set_target_properties(CommonLib PROPERTIES 12 | COMPILE_FLAGS "-fno-rtti -fPIC" 13 | ) 14 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/DoubleLockDetector/lib/Common/CallerFunc.cpp: -------------------------------------------------------------------------------- 1 | #include "Common/CallerFunc.h" 2 | 3 | #include "llvm/IR/Instruction.h" 4 | #include "llvm/IR/IntrinsicInst.h" 5 | #include "llvm/IR/CallSite.h" 6 | 7 | using namespace llvm; 8 | 9 | bool isCallOrInvokeInst(Instruction *I) { 10 | if (!I) { 11 | return false; 12 | } 13 | if (isa(I)) { 14 | return false; 15 | } 16 | if (isa(I)) { 17 | return false; 18 | } 19 | if (isa(I) || isa(I)) { 20 | return true; 21 | } 22 | return false; 23 | } 24 | 25 | Function *getCalledFunc(Instruction *pInst, CallSite &CS) { 26 | if (!pInst) { 27 | return nullptr; 28 | } 29 | if (isa(pInst)) { 30 | return nullptr; 31 | // } else if (isa(pInst)) { 32 | // return nullptr; 33 | } else if (isa(pInst) || isa(pInst)) { 34 | CS = CallSite(pInst); 35 | try { 36 | Function *pCalled = CS.getCalledFunction(); 37 | if (pCalled) { 38 | return pCalled; 39 | } else { 40 | // errs() << "Call FuncPtr:" << '\n'; 41 | return nullptr; 42 | } 43 | } catch (...) { 44 | errs() << "Bad Inst\n"; 45 | pInst->print(errs()); 46 | errs() << '\n'; 47 | return nullptr; 48 | } 49 | } 50 | return nullptr; 51 | } 52 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/DoubleLockDetector/lib/RustDoubleLockDetector/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(RustDoubleLockDetector MODULE 2 | # List your source files here. 3 | RustDoubleLockDetector.cpp 4 | ) 5 | 6 | target_link_libraries(RustDoubleLockDetector CommonLib) 7 | 8 | # Use C++11 to compile our pass (i.e., supply -std=c++11). 9 | target_compile_features(RustDoubleLockDetector PRIVATE cxx_range_for cxx_auto_type) 10 | 11 | # LLVM is (typically) built with no C++ RTTI. We need to match that; 12 | # otherwise, we'll get linker errors about missing RTTI data. 13 | set_target_properties(RustDoubleLockDetector PROPERTIES 14 | COMPILE_FLAGS "-fno-rtti" 15 | ) 16 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BC_DIR="$1" 4 | DOUBLE_LOCK_DETECTOR_LIB=DoubleLockDetector/build/lib/RustDoubleLockDetector/libRustDoubleLockDetector.so 5 | LOG_FILE=./double_lock.log 6 | 7 | for bc in `ls -1v ${BC_DIR}/*.m2r.bc` 8 | do 9 | #echo $bc 10 | opt -load ${DOUBLE_LOCK_DETECTOR_LIB} -detect $bc 1>/dev/null 11 | done 2>>${LOG_FILE} 12 | -------------------------------------------------------------------------------- /section-7-bug-detection/section-7.2-detecting-concurrency-bugs/double-lock-detector/run_all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BC_DIR="$1" 4 | 5 | # build 6 | cd DoubleLockDetector 7 | mkdir -p build 8 | cd build 9 | cmake .. 10 | make 11 | cd ../.. 12 | 13 | # run 14 | for APP in ${BC_DIR}/* 15 | do 16 | if [ -d ${APP} ] 17 | then 18 | echo ${APP} 19 | ./run.sh ${APP}/m2r 20 | fi 21 | done 22 | --------------------------------------------------------------------------------