fix: Fix stack related errors (#1167)

* fix: Fix stack related errors

Increase kernel stack to 32k.
Add a stack overflow test.
Remove manual placement of guard pages

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* fix: update userstack comments

Signed-off-by: Godones <chenlinfeng25@outlook.com>

---------

Signed-off-by: Godones <chenlinfeng25@outlook.com>
This commit is contained in:
linfeng 2025-05-22 08:52:32 +08:00 committed by GitHub
parent 880720250e
commit ba734c8d6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 159 additions and 123 deletions

View File

@ -1,9 +1,8 @@
use alloc::sync::Arc;
use core::{
intrinsics::{likely, unlikely},
panic,
};
use alloc::sync::Arc;
use log::error;
use x86::{bits64::rflags::RFlags, controlregs::Cr4};
@ -229,27 +228,28 @@ impl X86_64MMArch {
flags |= FaultFlags::FAULT_FLAG_INSTRUCTION;
}
let send_segv = || {
let pid = ProcessManager::current_pid();
let mut info = SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid));
Signal::SIGSEGV
.send_signal_info(Some(&mut info), pid)
.expect("failed to send SIGSEGV to process");
};
let current_address_space: Arc<AddressSpace> = AddressSpace::current().unwrap();
let mut space_guard = current_address_space.write_irqsave();
let mut fault;
loop {
let vma = space_guard.mappings.find_nearest(address);
// let vma = space_guard.mappings.contains(address);
let vma = match vma {
Some(vma) => vma,
None => {
log::error!(
"can not find nearest vma, error_code: {:#b}, address: {:#x}",
"can not find nearest vma, error_code: {:?}, address: {:#x}",
error_code,
address.data(),
);
let pid = ProcessManager::current_pid();
let mut info =
SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid));
Signal::SIGSEGV
.send_signal_info(Some(&mut info), pid)
.expect("failed to send SIGSEGV to process");
send_segv();
return;
}
};
@ -260,40 +260,46 @@ impl X86_64MMArch {
if !region.contains(address) {
if vm_flags.contains(VmFlags::VM_GROWSDOWN) {
if !space_guard.can_extend_stack(region.start() - address) {
// exceeds stack limit
log::error!(
"stack limit exceeded, error_code: {:?}, address: {:#x}",
error_code,
address.data(),
);
send_segv();
return;
}
space_guard
.extend_stack(region.start() - address)
.unwrap_or_else(|_| {
panic!(
"user stack extend failed, error_code: {:#b}, address: {:#x}",
"user stack extend failed, error_code: {:?}, address: {:#x}",
error_code,
address.data(),
)
});
} else {
log::error!(
"No mapped vma, error_code: {:#b}, address: {:#x}, flags: {:?}",
"No mapped vma, error_code: {:?}, address: {:#x}, flags: {:?}",
error_code,
address.data(),
flags
);
log::error!("fault rip: {:#x}", regs.rip);
let pid = ProcessManager::current_pid();
let mut info =
SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid));
Signal::SIGSEGV
.send_signal_info(Some(&mut info), pid)
.expect("failed to send SIGSEGV to process");
send_segv();
return;
}
}
if unlikely(Self::vma_access_error(vma.clone(), error_code)) {
panic!(
"vma access error, error_code: {:#b}, address: {:#x}",
log::error!(
"vma access error, error_code: {:?}, address: {:#x}",
error_code,
address.data(),
);
send_segv();
}
let mapper = &mut space_guard.user_mapper.utable;
let message = PageFaultMessage::new(vma.clone(), address, flags, mapper);

View File

@ -206,21 +206,51 @@ impl InnerAddressSpace {
return Ok(new_addr_space);
}
/// Check if the stack can be extended
pub fn can_extend_stack(&self, bytes: usize) -> bool {
let bytes = page_align_up(bytes);
let stack = self.user_stack.as_ref().unwrap();
let new_size = stack.mapped_size + bytes;
if new_size > stack.max_limit {
// Don't exceed the maximum stack size
return false;
}
return true;
}
/// 拓展用户栈
/// ## 参数
///
/// - `bytes`: 拓展大小
#[allow(dead_code)]
pub fn extend_stack(&mut self, mut bytes: usize) -> Result<(), SystemError> {
// debug!("extend user stack");
// log::debug!("extend user stack");
// Layout
// -------------- high->sp
// | stack pages|
// |------------|
// | stack pages|
// |------------|
// | not mapped |
// -------------- low
let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC;
let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_GROWSDOWN;
let stack = self.user_stack.as_mut().unwrap();
bytes = page_align_up(bytes);
stack.mapped_size += bytes;
let len = stack.stack_bottom - stack.mapped_size;
self.map_anonymous(len, bytes, prot_flags, map_flags, false, false)?;
// map new stack pages
let extend_stack_start = stack.stack_bottom - stack.mapped_size;
self.map_anonymous(
extend_stack_start,
bytes,
prot_flags,
map_flags,
false,
false,
)?;
return Ok(());
}
@ -1734,6 +1764,8 @@ pub struct UserStack {
mapped_size: usize,
/// 栈顶地址(这个值需要仔细确定!因为它可能不会实时与用户栈的真实栈顶保持一致!要小心!)
current_sp: VirtAddr,
/// 用户自定义的栈大小限制
max_limit: usize,
}
impl UserStack {
@ -1753,117 +1785,43 @@ impl UserStack {
let stack_bottom = stack_bottom.unwrap_or(Self::DEFAULT_USER_STACK_BOTTOM);
assert!(stack_bottom.check_aligned(MMArch::PAGE_SIZE));
// 分配用户栈的保护页
let guard_size = Self::GUARD_PAGES_NUM * MMArch::PAGE_SIZE;
let actual_stack_bottom = stack_bottom - guard_size;
// Layout
// -------------- high->sp
// | stack pages|
// |------------|
// | not mapped |
// -------------- low
let mut prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE;
let map_flags = MapFlags::MAP_PRIVATE
| MapFlags::MAP_ANONYMOUS
| MapFlags::MAP_FIXED_NOREPLACE
| MapFlags::MAP_GROWSDOWN;
// debug!(
// "map anonymous stack: {:?} {}",
// actual_stack_bottom,
// guard_size
// );
vm.map_anonymous(
actual_stack_bottom,
guard_size,
prot_flags,
map_flags,
false,
false,
)?;
// test_buddy();
// 设置保护页只读
prot_flags.remove(ProtFlags::PROT_WRITE);
// debug!(
// "to mprotect stack guard pages: {:?} {}",
// actual_stack_bottom,
// guard_size
// );
vm.mprotect(
VirtPageFrame::new(actual_stack_bottom),
PageFrameCount::new(Self::GUARD_PAGES_NUM),
prot_flags,
)?;
// debug!(
// "mprotect stack guard pages done: {:?} {}",
// actual_stack_bottom,
// guard_size
// );
let mut user_stack = UserStack {
stack_bottom: actual_stack_bottom,
mapped_size: guard_size,
current_sp: actual_stack_bottom - guard_size,
};
// debug!("extend user stack: {:?} {}", stack_bottom, stack_size);
// 分配用户栈
user_stack.initial_extend(vm, stack_size)?;
// debug!("user stack created: {:?} {}", stack_bottom, stack_size);
return Ok(user_stack);
}
fn initial_extend(
&mut self,
vm: &mut InnerAddressSpace,
mut bytes: usize,
) -> Result<(), SystemError> {
let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC;
let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_GROWSDOWN;
bytes = page_align_up(bytes);
self.mapped_size += bytes;
let stack_size = page_align_up(stack_size);
// log::info!(
// "UserStack stack_range: {:#x} - {:#x}",
// stack_bottom.data() - stack_size,
// stack_bottom.data()
// );
vm.map_anonymous(
self.stack_bottom - self.mapped_size,
bytes,
stack_bottom - stack_size,
stack_size,
prot_flags,
map_flags,
false,
false,
)?;
return Ok(());
}
let max_limit = core::cmp::max(Self::DEFAULT_USER_STACK_SIZE, stack_size);
/// 扩展用户栈
///
/// ## 参数
///
/// - `vm` 用户地址空间结构体
/// - `bytes` 要扩展的字节数
///
/// ## 返回值
///
/// - **Ok(())** 扩展成功
/// - **Err(SystemError)** 扩展失败
#[allow(dead_code)]
pub fn extend(
&mut self,
vm: &mut InnerAddressSpace,
mut bytes: usize,
) -> Result<(), SystemError> {
let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC;
let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS;
let user_stack = UserStack {
stack_bottom,
mapped_size: stack_size,
current_sp: stack_bottom,
max_limit,
};
bytes = page_align_up(bytes);
self.mapped_size += bytes;
vm.map_anonymous(
self.stack_bottom - self.mapped_size,
bytes,
prot_flags,
map_flags,
false,
false,
)?;
return Ok(());
return Ok(user_stack);
}
/// 获取栈顶地址
@ -1883,11 +1841,17 @@ impl UserStack {
stack_bottom: self.stack_bottom,
mapped_size: self.mapped_size,
current_sp: self.current_sp,
max_limit: self.max_limit,
};
}
/// 获取当前用户栈的大小(不包括保护页)
pub fn stack_size(&self) -> usize {
return self.mapped_size - Self::GUARD_PAGES_NUM * MMArch::PAGE_SIZE;
return self.mapped_size;
}
/// 设置当前用户栈的最大大小
pub fn set_max_limit(&mut self, max_limit: usize) {
self.max_limit = max_limit;
}
}

1
user/apps/test_stack/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
test_stack

View File

@ -0,0 +1,20 @@
ifeq ($(ARCH), x86_64)
CROSS_COMPILE=x86_64-linux-musl-
else ifeq ($(ARCH), riscv64)
CROSS_COMPILE=riscv64-linux-musl-
endif
CC=$(CROSS_COMPILE)gcc
.PHONY: all
all: main.c
$(CC) -static -o test_stack main.c
.PHONY: install clean
install: all
mv test_stack $(DADK_CURRENT_BUILD_DIR)/test_stack
clean:
rm test_stack *.o
fmt:

View File

@ -0,0 +1,13 @@
#include <stdio.h>
void overflow(int depth) {
char buffer[1024 * 1024]; // 占用一些栈空间
printf("Recursion depth: %d\n", depth);
overflow(depth + 1); // 递归调用
}
int main() {
overflow(1);
printf("This line will not be printed due to stack overflow.\n");
return 0;
}

View File

@ -0,0 +1,32 @@
# 用户程序名称
name = "test_stack"
# 版本号
version = "0.1.0"
# 用户程序描述信息
description = "test_stack"
# 目标架构
target-arch = ["x86_64"]
# 任务源
[task-source]
# 构建类型
type = "build-from-source"
# 构建来源
source = "local"
# 路径或URL
source-path = "user/apps/test_stack"
# 构建相关信息
[build]
# (可选)构建命令
build-command = "make install"
# 安装相关信息
[install]
# 可选安装到DragonOS的路径
in-dragonos-path = "/bin"
# 清除相关信息
[clean]
# (可选)清除命令
clean-command = "make clean"