Rollup merge of #127843 - workingjubilee:break-up-big-ass-stack-overf… · patricklam/verify-rust-std@bd26295 (original) (raw)

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

`

87

87

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

`

88

88

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

`

89

89

`// 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)]

`

90

94

`unsafe extern "C" fn signal_handler(

`

91

95

`signum: libc::c_int,

`

92

96

`info: *mut libc::siginfo_t,

`

93

97

`_data: *mut libc::c_void,

`

94

98

`) {

`

95

99

`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() };

`

97

102

``

98

103

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

`

99

104

`// message saying so and abort.

`

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

`

105

110

`rtabort!("stack overflow");

`

106

111

`} else {

`

107

112

`// 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() };

`

109

115

` 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()) };

`

111

118

``

112

119

`// See comment above for why this function returns.

`

113

120

`}

`

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

`

117

124

`static MAIN_ALTSTACK: AtomicPtrlibc::c_void = AtomicPtr::new(ptr::null_mut());

`

118

125

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

`

119

126

``

``

127

`+

/// # Safety

`

``

128

`+

/// Must be called only once

`

``

129

`+

#[forbid(unsafe_op_in_unsafe_fn)]

`

120

130

`pub unsafe fn init() {

`

121

131

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

`

122

132

``

123

133

`// 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) };

`

125

135

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

`

126

136

``

127

``

`-

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() };

`

128

139

`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) };

`

130

142

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

`

131

143

`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

`+

}

`

132

151

` action.sa_flags = SA_SIGINFO | SA_ONSTACK;

`

133

152

` 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()) };

`

136

155

`}

`

137

156

`}

`

138

``

-

139

``

`-

let handler = make_handler(true);

`

140

``

`-

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

`

141

``

`-

mem::forget(handler);

`

142

157

`}

`

143

158

``

``

159

`+

/// # Safety

`

``

160

`+

/// Must be called only once

`

``

161

`+

#[forbid(unsafe_op_in_unsafe_fn)]

`

144

162

`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)) };

`

146

166

`}

`

147

167

``

148

168

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

`

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

`

187

207

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

`

188

208

`}

`

189

209

``

``

210

`+

/// # Safety

`

``

211

`+

/// Mutates the alternate signal stack

`

``

212

`+

#[forbid(unsafe_op_in_unsafe_fn)]

`

190

213

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

`

191

``

`-

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

`

``

214

`+

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

`

192

215

`return Handler::null();

`

193

216

`}

`

194

217

``

195

218

`if !main_thread {

`

196

219

`// 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);

`

198

221

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

`

199

222

`}

`

200

223

``

201

``

`-

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) };

`

203

228

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

`

204

229

`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

`+

}

`

207

235

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

`

208

236

`} else {

`

209

237

`Handler::null()

`

210

238

`}

`

211

239

`}

`

212

240

``

``

241

`+

/// # 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)]

`

213

247

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

`

214

248

`if !data.is_null() {

`

215

249

`let sigstack_size = sigstack_size();

`

216

250

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

`

217

``

`-

let stack = libc::stack_t {

`

``

251

`+

let disabling_stack = libc::stack_t {

`

218

252

`ss_sp: ptr::null_mut(),

`

219

253

`ss_flags: SS_DISABLE,

`

220

254

`// Workaround for bug in macOS implementation of sigaltstack

`

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

`

223

257

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

`

224

258

`ss_size: sigstack_size,

`

225

259

`};

`

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) };

`

230

265

`}

`

231

266

`}

`

232

267

``

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

`

455

490

`}

`

456

491

``

457

492

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

`

``

493

`+

// FIXME: I am probably not unsafe.

`

458

494

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

`

459

495

`let stackptr = get_stack_start()?;

`

460

496

`let stackaddr = stackptr.addr();

`

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

`

469

505

` target_os = "netbsd",

`

470

506

` target_os = "l4re"

`

471

507

`))]

`

``

508

`+

// FIXME: I am probably not unsafe.

`

472

509

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

`

473

510

`let mut ret = None;

`

474

511

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

`