mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
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:
parent
880720250e
commit
ba734c8d6b
@ -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);
|
||||
|
@ -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
1
user/apps/test_stack/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test_stack
|
20
user/apps/test_stack/Makefile
Normal file
20
user/apps/test_stack/Makefile
Normal 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:
|
13
user/apps/test_stack/main.c
Normal file
13
user/apps/test_stack/main.c
Normal 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;
|
||||
}
|
32
user/dadk/config/test_stack_0_1_0.toml
Normal file
32
user/dadk/config/test_stack_0_1_0.toml
Normal 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"
|
Loading…
x
Reference in New Issue
Block a user