mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
std.debug: remove @frameAddress() "UAF"
We can't call `@frameAddress()` and then immediately `return`! That invalidates the frame. This *usually* isn't a problem, because the stack walk `next` call will *probably* have a stack frame and it will *probably* be at the exact same address, but neither of those is a guarantee. On powerpc, presumably some unfortunate inlining was going on, so this frame was indeed invalidated when we started walking frames. We need to explicitly pass `@frameAddress` into any function which will return before we actually walk the stack. Pretty simple patch. Resolves: #24970
This commit is contained in:
parent
151c7dc74b
commit
a31950aa57
@ -440,7 +440,7 @@ pub fn dumpStackTraceFromBase(context: *ThreadContext, stderr: *Writer) void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var it = StackIterator.initWithContext(null, debug_info, context) catch return;
|
var it = StackIterator.initWithContext(null, debug_info, context, @frameAddress()) catch return;
|
||||||
defer it.deinit();
|
defer it.deinit();
|
||||||
|
|
||||||
// DWARF unwinding on aarch64-macos is not complete so we need to get pc address from mcontext
|
// DWARF unwinding on aarch64-macos is not complete so we need to get pc address from mcontext
|
||||||
@ -499,12 +499,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT
|
|||||||
// TODO: This should use the DWARF unwinder if .eh_frame_hdr is available (so that full debug info parsing isn't required).
|
// TODO: This should use the DWARF unwinder if .eh_frame_hdr is available (so that full debug info parsing isn't required).
|
||||||
// A new path for loading SelfInfo needs to be created which will only attempt to parse in-memory sections, because
|
// A new path for loading SelfInfo needs to be created which will only attempt to parse in-memory sections, because
|
||||||
// stopping to load other debug info (ie. source line info) from disk here is not required for unwinding.
|
// stopping to load other debug info (ie. source line info) from disk here is not required for unwinding.
|
||||||
if (builtin.cpu.arch == .powerpc64) {
|
var it = StackIterator.init(first_address, @frameAddress());
|
||||||
// https://github.com/ziglang/zig/issues/24970
|
|
||||||
stack_trace.index = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var it = StackIterator.init(first_address, null);
|
|
||||||
defer it.deinit();
|
defer it.deinit();
|
||||||
for (stack_trace.instruction_addresses, 0..) |*addr, i| {
|
for (stack_trace.instruction_addresses, 0..) |*addr, i| {
|
||||||
addr.* = it.next() orelse {
|
addr.* = it.next() orelse {
|
||||||
@ -787,7 +782,7 @@ pub const StackIterator = struct {
|
|||||||
failed: bool = false,
|
failed: bool = false,
|
||||||
} else void = if (have_ucontext) null else {},
|
} else void = if (have_ucontext) null else {},
|
||||||
|
|
||||||
pub fn init(first_address: ?usize, fp: ?usize) StackIterator {
|
pub fn init(first_address: ?usize, fp: usize) StackIterator {
|
||||||
if (native_arch.isSPARC()) {
|
if (native_arch.isSPARC()) {
|
||||||
// Flush all the register windows on stack.
|
// Flush all the register windows on stack.
|
||||||
asm volatile (if (builtin.cpu.has(.sparc, .v9))
|
asm volatile (if (builtin.cpu.has(.sparc, .v9))
|
||||||
@ -799,23 +794,18 @@ pub const StackIterator = struct {
|
|||||||
|
|
||||||
return .{
|
return .{
|
||||||
.first_address = first_address,
|
.first_address = first_address,
|
||||||
// TODO: this is a workaround for #16876
|
.fp = fp,
|
||||||
//.fp = fp orelse @frameAddress(),
|
|
||||||
.fp = fp orelse blk: {
|
|
||||||
const fa = @frameAddress();
|
|
||||||
break :blk fa;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initWithContext(first_address: ?usize, debug_info: *SelfInfo, context: *posix.ucontext_t) !StackIterator {
|
pub fn initWithContext(first_address: ?usize, debug_info: *SelfInfo, context: *posix.ucontext_t, fp: usize) !StackIterator {
|
||||||
// The implementation of DWARF unwinding on aarch64-macos is not complete. However, Apple mandates that
|
// The implementation of DWARF unwinding on aarch64-macos is not complete. However, Apple mandates that
|
||||||
// the frame pointer register is always used, so on this platform we can safely use the FP-based unwinder.
|
// the frame pointer register is always used, so on this platform we can safely use the FP-based unwinder.
|
||||||
if (builtin.target.os.tag.isDarwin() and native_arch == .aarch64)
|
if (builtin.target.os.tag.isDarwin() and native_arch == .aarch64)
|
||||||
return init(first_address, @truncate(context.mcontext.ss.fp));
|
return init(first_address, @truncate(context.mcontext.ss.fp));
|
||||||
|
|
||||||
if (SelfInfo.supports_unwinding) {
|
if (SelfInfo.supports_unwinding) {
|
||||||
var iterator = init(first_address, null);
|
var iterator = init(first_address, fp);
|
||||||
iterator.unwind_state = .{
|
iterator.unwind_state = .{
|
||||||
.debug_info = debug_info,
|
.debug_info = debug_info,
|
||||||
.dwarf_context = try SelfInfo.UnwindContext.init(debug_info.allocator, context),
|
.dwarf_context = try SelfInfo.UnwindContext.init(debug_info.allocator, context),
|
||||||
@ -823,7 +813,7 @@ pub const StackIterator = struct {
|
|||||||
return iterator;
|
return iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
return init(first_address, null);
|
return init(first_address, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(it: *StackIterator) void {
|
pub fn deinit(it: *StackIterator) void {
|
||||||
@ -981,8 +971,8 @@ pub fn writeCurrentStackTrace(
|
|||||||
const has_context = getContext(&context);
|
const has_context = getContext(&context);
|
||||||
|
|
||||||
var it = (if (has_context) blk: {
|
var it = (if (has_context) blk: {
|
||||||
break :blk StackIterator.initWithContext(start_addr, debug_info, &context) catch null;
|
break :blk StackIterator.initWithContext(start_addr, debug_info, &context, @frameAddress()) catch null;
|
||||||
} else null) orelse StackIterator.init(start_addr, null);
|
} else null) orelse StackIterator.init(start_addr, @frameAddress());
|
||||||
defer it.deinit();
|
defer it.deinit();
|
||||||
|
|
||||||
while (it.next()) |return_address| {
|
while (it.next()) |return_address| {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ noinline fn frame3(expected: *[4]usize, unwound: *[4]usize) void {
|
|||||||
testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
|
testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
|
||||||
|
|
||||||
const debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");
|
const debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");
|
||||||
var it = debug.StackIterator.initWithContext(expected[0], debug_info, &context) catch @panic("failed to initWithContext");
|
var it = debug.StackIterator.initWithContext(expected[0], debug_info, &context, @frameAddress()) catch @panic("failed to initWithContext");
|
||||||
defer it.deinit();
|
defer it.deinit();
|
||||||
|
|
||||||
for (unwound) |*addr| {
|
for (unwound) |*addr| {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user