Rollup merge of #127843 - workingjubilee:break-up-big-ass-stack-overf… · model-checking/verify-rust-std@bd26295

@@ -87,13 +87,18 @@ mod imp {

8787

// out many large systems and all implementations allow returning from a

8888

// signal handler to work. For a more detailed explanation see the

8989

// comments on #26458.

90+

/// SIGSEGV/SIGBUS entry point

91+

/// # Safety

92+

/// Rust doesn't call this, it *gets called*.

93+

#[forbid(unsafe_op_in_unsafe_fn)]

9094

unsafe extern "C" fn signal_handler(

9195

signum: libc::c_int,

9296

info: *mut libc::siginfo_t,

9397

_data: *mut libc::c_void,

9498

) {

9599

let (start, end) = GUARD.get();

96-

let addr = (*info).si_addr() as usize;

100+

// SAFETY: this pointer is provided by the system and will always point to a valid `siginfo_t`.

101+

let addr = unsafe { (*info).si_addr().addr() };

9710298103

// If the faulting address is within the guard page, then we print a

99104

// message saying so and abort.

@@ -105,9 +110,11 @@ mod imp {

105110

rtabort!("stack overflow");

106111

} else {

107112

// Unregister ourselves by reverting back to the default behavior.

108-

let mut action: sigaction = mem::zeroed();

113+

// SAFETY: assuming all platforms define struct sigaction as "zero-initializable"

114+

let mut action: sigaction = unsafe { mem::zeroed() };

109115

action.sa_sigaction = SIG_DFL;

110-

sigaction(signum, &action, ptr::null_mut());

116+

// SAFETY: pray this is a well-behaved POSIX implementation of fn sigaction

117+

unsafe { sigaction(signum, &action, ptr::null_mut()) };

111118112119

// See comment above for why this function returns.

113120

}

@@ -117,32 +124,45 @@ mod imp {

117124

static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());

118125

static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);

119126127+

/// # Safety

128+

/// Must be called only once

129+

#[forbid(unsafe_op_in_unsafe_fn)]

120130

pub unsafe fn init() {

121131

PAGE_SIZE.store(os::page_size(), Ordering::Relaxed);

122132123133

// Always write to GUARD to ensure the TLS variable is allocated.

124-

let guard = install_main_guard().unwrap_or(0..0);

134+

let guard = unsafe { install_main_guard().unwrap_or(0..0) };

125135

GUARD.set((guard.start, guard.end));

126136127-

let mut action: sigaction = mem::zeroed();

137+

// SAFETY: assuming all platforms define struct sigaction as "zero-initializable"

138+

let mut action: sigaction = unsafe { mem::zeroed() };

128139

for &signal in &[SIGSEGV, SIGBUS] {

129-

sigaction(signal, ptr::null_mut(), &mut action);

140+

// SAFETY: just fetches the current signal handler into action

141+

unsafe { sigaction(signal, ptr::null_mut(), &mut action) };

130142

// Configure our signal handler if one is not already set.

131143

if action.sa_sigaction == SIG_DFL {

144+

if !NEED_ALTSTACK.load(Ordering::Relaxed) {

145+

// haven't set up our sigaltstack yet

146+

NEED_ALTSTACK.store(true, Ordering::Release);

147+

let handler = unsafe { make_handler(true) };

148+

MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);

149+

mem::forget(handler);

150+

}

132151

action.sa_flags = SA_SIGINFO | SA_ONSTACK;

133152

action.sa_sigaction = signal_handler as sighandler_t;

134-

sigaction(signal, &action, ptr::null_mut());

135-

NEED_ALTSTACK.store(true, Ordering::Relaxed);

153+

// SAFETY: only overriding signals if the default is set

154+

unsafe { sigaction(signal, &action, ptr::null_mut()) };

136155

}

137156

}

138-139-

let handler = make_handler(true);

140-

MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);

141-

mem::forget(handler);

142157

}

143158159+

/// # Safety

160+

/// Must be called only once

161+

#[forbid(unsafe_op_in_unsafe_fn)]

144162

pub unsafe fn cleanup() {

145-

drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed));

163+

// FIXME: I probably cause more bugs than I'm worth!

164+

// see https://github.com/rust-lang/rust/issues/111272

165+

unsafe { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)) };

146166

}

147167148168

unsafe fn get_stack() -> libc::stack_t {

@@ -187,34 +207,48 @@ mod imp {

187207

libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size }

188208

}

189209210+

/// # Safety

211+

/// Mutates the alternate signal stack

212+

#[forbid(unsafe_op_in_unsafe_fn)]

190213

pub unsafe fn make_handler(main_thread: bool) -> Handler {

191-

if !NEED_ALTSTACK.load(Ordering::Relaxed) {

214+

if !NEED_ALTSTACK.load(Ordering::Acquire) {

192215

return Handler::null();

193216

}

194217195218

if !main_thread {

196219

// Always write to GUARD to ensure the TLS variable is allocated.

197-

let guard = current_guard().unwrap_or(0..0);

220+

let guard = unsafe { current_guard() }.unwrap_or(0..0);

198221

GUARD.set((guard.start, guard.end));

199222

}

200223201-

let mut stack = mem::zeroed();

202-

sigaltstack(ptr::null(), &mut stack);

224+

// SAFETY: assuming stack_t is zero-initializable

225+

let mut stack = unsafe { mem::zeroed() };

226+

// SAFETY: reads current stack_t into stack

227+

unsafe { sigaltstack(ptr::null(), &mut stack) };

203228

// Configure alternate signal stack, if one is not already set.

204229

if stack.ss_flags & SS_DISABLE != 0 {

205-

stack = get_stack();

206-

sigaltstack(&stack, ptr::null_mut());

230+

// SAFETY: We warned our caller this would happen!

231+

unsafe {

232+

stack = get_stack();

233+

sigaltstack(&stack, ptr::null_mut());

234+

}

207235

Handler { data: stack.ss_sp as *mut libc::c_void }

208236

} else {

209237

Handler::null()

210238

}

211239

}

212240241+

/// # Safety

242+

/// Must be called

243+

/// - only with our handler or nullptr

244+

/// - only when done with our altstack

245+

/// This disables the alternate signal stack!

246+

#[forbid(unsafe_op_in_unsafe_fn)]

213247

pub unsafe fn drop_handler(data: *mut libc::c_void) {

214248

if !data.is_null() {

215249

let sigstack_size = sigstack_size();

216250

let page_size = PAGE_SIZE.load(Ordering::Relaxed);

217-

let stack = libc::stack_t {

251+

let disabling_stack = libc::stack_t {

218252

ss_sp: ptr::null_mut(),

219253

ss_flags: SS_DISABLE,

220254

// Workaround for bug in macOS implementation of sigaltstack

@@ -223,10 +257,11 @@ mod imp {

223257

// both ss_sp and ss_size should be ignored in this case.

224258

ss_size: sigstack_size,

225259

};

226-

sigaltstack(&stack, ptr::null_mut());

227-

// We know from `get_stackp` that the alternate stack we installed is part of a mapping

228-

// that started one page earlier, so walk back a page and unmap from there.

229-

munmap(data.sub(page_size), sigstack_size + page_size);

260+

// SAFETY: we warned the caller this disables the alternate signal stack!

261+

unsafe { sigaltstack(&disabling_stack, ptr::null_mut()) };

262+

// SAFETY: We know from `get_stackp` that the alternate stack we installed is part of

263+

// a mapping that started one page earlier, so walk back a page and unmap from there.

264+

unsafe { munmap(data.sub(page_size), sigstack_size + page_size) };

230265

}

231266

}

232267

@@ -455,6 +490,7 @@ mod imp {

455490

}

456491457492

#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]

493+

// FIXME: I am probably not unsafe.

458494

unsafe fn current_guard() -> Option<Range<usize>> {

459495

let stackptr = get_stack_start()?;

460496

let stackaddr = stackptr.addr();

@@ -469,6 +505,7 @@ mod imp {

469505

target_os = "netbsd",

470506

target_os = "l4re"

471507

))]

508+

// FIXME: I am probably not unsafe.

472509

unsafe fn current_guard() -> Option<Range<usize>> {

473510

let mut ret = None;

474511

let mut attr: libc::pthread_attr_t = crate::mem::zeroed();