starlark/util/
rtabort.rs

1/*
2 * Copyright 2018 The Starlark in Rust Authors.
3 * Copyright (c) Facebook, Inc. and its affiliates.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18use std::fmt::Arguments;
19use std::io;
20use std::process;
21
22/// Like `panic!`, but aborts the process instead of unwinding.
23///
24/// Although we compile buck2 with `panic=abort`, this is safer because
25/// others may copy-paste code.
26macro_rules! rtabort {
27    ($m:literal) => {
28        $crate::util::rtabort::rtabort_impl_fixed_string(
29            file!(),
30            line!(),
31            $m,
32        )
33    };
34    ($($t:tt)*) => {
35        $crate::util::rtabort::rtabort_impl(
36            file!(),
37            line!(),
38            format_args!($($t)*),
39        )
40    };
41}
42
43pub(crate) use rtabort;
44
45#[cold]
46pub(crate) fn rtabort_impl_fixed_string(file: &str, line: u32, message: &str) -> ! {
47    rtabort_impl(file, line, format_args!("{}", message));
48}
49
50#[cold]
51pub(crate) fn rtabort_impl(file: &str, line: u32, msg: Arguments) -> ! {
52    // Make sure we abort even if formatting panics.
53    let _abort = AbortOnDrop;
54
55    // `eprintln!` followed by `abort` does not print anything in tests.
56    io::Write::write_fmt(
57        &mut io::stderr(),
58        format_args!("{}:{}: abort: {}\n", file, line, msg),
59    )
60    .ok();
61
62    // Tell the compiler that we never return.
63    process::abort();
64}
65
66struct AbortOnDrop;
67
68impl Drop for AbortOnDrop {
69    fn drop(&mut self) {
70        process::abort();
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    fn _test_compiles_fixed_string() {
77        rtabort!("test");
78    }
79
80    fn _test_compiles_with_format_args() {
81        rtabort!("test {}", 17);
82    }
83
84    #[test]
85    fn test_rtabort() {
86        // Uncomment to test.
87        // rtabort!("test {}", 17);
88        // rtabort!("test {}", { panic!(); 17 });
89    }
90}