Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ build --@rules_rust//rust/settings:clippy.toml=//tools/workspace:clippy.toml
# Strict tier lints rules_dx enforces.
common --@rules_dx//config:clippy_flag=-Dclippy::unwrap_used
common --@rules_dx//config:clippy_flag=-Dclippy::expect_used
common --@rules_dx//config:clippy_flag=-Dclippy::panic
common --@rules_dx//config:clippy_flag=-Dclippy::unreachable
common --@rules_dx//config:clippy_flag=-Dclippy::exit
common --@rules_dx//config:clippy_flag=-Dclippy::todo
Expand All @@ -47,6 +48,7 @@ common --@rules_dx//config:clippy_flag=-Dclippy::unwrap_in_result
common --@rules_dx//config:clippy_flag=-Dclippy::panic_in_result_fn
common --@rules_dx//config:clippy_flag=-Dclippy::allow_attributes
common --@rules_dx//config:clippy_flag=-Dclippy::allow_attributes_without_reason
common --@rules_dx//config:clippy_flag=-Dunsafe_code
common --@rules_dx//config:clippy_flag=-Dunsafe_op_in_unsafe_fn
common --@rules_dx//config:clippy_flag=-Dunused_must_use
build:linux --@rules_rust//rust/settings:pipelined_compilation=true
Expand Down
2 changes: 2 additions & 0 deletions cli/cli/src/exec/error_boundary_launcher_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![expect(unsafe_code, reason = "pipe and process-group tests call libc directly")]

use super::super::test_support::{Harness, hang_up};
use quality_result::proto::FileSnapshot;
use std::fs;
Expand Down
2 changes: 2 additions & 0 deletions cli/cli/src/exec/stream_probe_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![expect(unsafe_code, reason = "signal, process-group and pty tests call libc directly")]

use super::super::test_support::{closed_pipe, hang_up, reader_gone};
use std::ffi::{CStr, CString};
use std::fs;
Expand Down
1 change: 1 addition & 0 deletions cli/cli/src/exec/test_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,7 @@ pub(crate) fn failed_action(
#[cfg(unix)]
/// Reports whether the pipe behind `writer` has no reader left in any process.
#[cfg(unix)]
#[expect(unsafe_code, reason = "poll has no safe std API")]
pub(crate) fn reader_gone(writer: &io::PipeWriter, timeout_ms: i32) -> bool {
let mut fd = libc::pollfd {
fd: writer.as_raw_fd(),
Expand Down
14 changes: 14 additions & 0 deletions cli/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,24 @@ use dx_process::lifecycle::{self, EnvPolicy, StreamOutput, StreamSpec, StreamStd
use dx_process::{discover_real, operational_code, pre_exec_code, stdout_io_code};

#[cfg(unix)]
#[expect(
unsafe_code,
reason = "a signal handler saves and restores errno through a raw pointer"
)]
extern "C" fn forward_to_child(signo: libc::c_int) {
let errno = dx_process::errno_slot();
// SAFETY: `errno_slot` returns this thread's valid errno location.
let saved = unsafe { *errno };
lifecycle::forward_stop(signo);
// SAFETY: same location as above, still valid on this thread.
unsafe { *errno = saved };
}

#[cfg(unix)]
#[expect(unsafe_code, reason = "sigaction has no safe std API")]
fn install_forwarding() {
for signo in lifecycle::STOP_SIGNALS {
// SAFETY: zeroed `sigaction` is valid; the handler only calls async-signal-safe functions.
unsafe {
let mut action: libc::sigaction = std::mem::zeroed();
action.sa_sigaction = forward_to_child as *const () as libc::sighandler_t;
Expand All @@ -52,9 +60,11 @@ fn install_forwarding() {
fn install_forwarding() {}

#[cfg(unix)]
#[expect(unsafe_code, reason = "re-raising a signal has no safe std API")]
fn die_by_signal(signo: i32) {
if signo > 0 {
let _cleaned = dx_plan::plan::clean_for_stop();
// SAFETY: restoring the default disposition and raising a signal has no memory effects.
unsafe {
libc::signal(signo, libc::SIG_DFL);
libc::raise(signo);
Expand Down Expand Up @@ -160,6 +170,7 @@ fn usage_error(
)
}

#[expect(unsafe_code, reason = "set_var is unsafe in edition 2024")]
fn main() {
if let Some(code) = run_as_tool() {
std::process::exit(code);
Expand Down Expand Up @@ -195,6 +206,7 @@ fn run_as_tool() -> Option<i32> {
}
// LCOV_EXCL_STOP - reason: end thin multicall shim, issue: 6517, policy: docs/cli/commands/build-test-coverage.md

#[expect(unsafe_code, reason = "set_var is unsafe in edition 2024")]
fn run() -> i32 {
// LCOV_EXCL_START - reason: thin run shim, issue: 1055, policy: docs/cli/commands/build-test-coverage.md
let args: Vec<std::ffi::OsString> = std::env::args_os().skip(1).collect();
Expand Down Expand Up @@ -273,7 +285,9 @@ fn run() -> i32 {
let exists = |path: &Path| path.is_file();
let read = |path: &Path| std::fs::read(path).ok();
match resolve_bazel_sh(&|name| std::env::var_os(name), &exists, &read) {
// SAFETY: startup is single-threaded at this point.
Ok(BazelSh::Set(bash)) => unsafe { std::env::set_var("BAZEL_SH", bash) },
// SAFETY: startup is single-threaded at this point.
Ok(BazelSh::Unset) => unsafe { std::env::remove_var("BAZEL_SH") },
Ok(BazelSh::Keep) => {}
Err(error) => {
Expand Down
Loading