You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PintOS中全局数组内存加载问题:为何仅触发2次页错误?

PintOS VM开发中的页错误异常问题

问题说明

在PintOS VM模块开发过程中,编写了一个包含10页(4096*10)大小全局数组buf的用户程序,目的是通过对每个页首字节写入值来验证页错误处理逻辑。预期会触发10次页错误,但实际仅触发2次,且所有写入的值最终都存储在同一个物理页中。从程序输出可以看到,数组每个页的虚拟地址都对应不同的虚拟页,但物理页仅分配了1个。

代码片段

#define SIZE 10 * 4096
volatile char buf[SIZE] = {0}; 

int main (int argc, char**argv){
    int cnt = 0; 
    for(int i = 0; i < SIZE; i += 4096)
    {
        printf("%p", &buf[i]); 
        buf[i] = 'a' ;
    }

    for(int i = 0; i < SIZE; i += 4096)
    {
        printf("%d %c\n", cnt ++, buf[i]); 
    }
}

程序输出

hello from page fault.
hello from page fault.
0x804bce0
0x804cce0
0x804dce0
0x804ece0
0x804fce0
0x8050ce0
0x8051ce0
0x8052ce0
0x8053ce0
0x8054ce0
1 a
2 a
3 a
4 a
5 a
6 a
7 a
8 a
9 a

问题原因分析

1. 虚拟页分配符合预期

从输出的虚拟地址来看,&buf[i]依次相差0x1000(4096字节),说明全局数组确实占用了10个连续的虚拟页,虚拟地址空间的分配没有问题,问题出在物理页的映射逻辑上。

2. 页错误处理逻辑存在bug

核心问题是你的VM实现中,页错误处理函数没有为每个触发错误的虚拟页分配独立的物理页,而是重复将多个虚拟页映射到了同一个物理页:

  • 第一次写入buf[0]时触发页错误,此时你正确分配了一个物理页,并将对应的虚拟页映射到该物理页。
  • 第二次写入buf[4096]时再次触发页错误,但此时你的处理逻辑没有分配新的物理页,而是错误地将当前虚拟页也映射到了之前分配的那个物理页;或者你的逻辑在处理前两次页错误后,直接将数组对应的所有虚拟页都批量映射到了同一个物理页,导致后续写入不再触发页错误。
  • 由于所有虚拟页都指向同一个物理页,后续对任何虚拟页首字节的写入都会覆盖同一个物理地址,最终所有buf[i]读取到的都是同一个值。

3. 全局数组初始化的次要影响

你定义的buf是显式初始化为0的全局数组,这类数组在ELF文件中会被放入.data段(而非未初始化变量的.bss段)。如果你的VM实现对.data段采用了错误的批量映射策略,将整个10页的.data区域直接映射到单个物理页,也会导致后续写入都指向同一个物理页。

修复建议

  • 检查页错误处理函数:确保每次处理页错误时,只针对当前触发错误的虚拟页分配物理页,并更新对应的页表项,避免批量映射多个虚拟页到同一个物理页。
  • 验证虚拟页索引计算逻辑:确认在处理页错误时,正确提取了当前触发错误的虚拟地址对应的页索引,避免索引计算错误导致重复映射。
  • 检查.data段加载逻辑:确保加载.data段时,按照页粒度分配物理页,每个虚拟页对应独立的物理页(或在需要时通过写时复制分配新页)。

内容的提问来源于stack exchange,提问作者JungHwanPark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 16:01:48