首页 > 其他分享 >2024.12.26 os lab3

2024.12.26 os lab3

时间:2024-12-26 11:30:46浏览次数:3  
标签:2024.12 越界 26 cout int lab3 result 缓冲区 分配

2024.12.26 os lab3

原代码

地址:https://github.com/BUPT-OS/easy_lab/tree/lab3

运行未修改的代码,并且注释掉cout时发生错误:

malloc(): corrupted top size

如果不注释cout,可以正常运行

image-20241226105708712

1.不注释 cout 时堆内存的详细分析

1. 程序启动阶段

  • 在程序启动时,堆的初始状态为空,堆顶指针位于堆的起始位置。
  • 当程序第一次需要在堆上分配内存时,堆顶会向上增长(通常从低地址向高地址)。

2. 第一处堆分配:cout 调用

cout << "A magic print! If you comment this, the program will break." << endl;

cout被调用时,C++ 标准库会在堆上分配一个缓冲区,用于存储待输出的字符串内容。

缓冲区大小:在常见的实现中(如 GNU libstdc++),这个缓冲区的默认大小为 1024 字节

分配位置:此时缓冲区位于堆的最底部,是堆中的第一个分配块。

堆布局(堆顶向高地址增长)

+-------------------+<-- 堆底
| cout 缓冲区 (1024) |
+-------------------+

3. 第二处堆分配:double_array 函数调用

int **result = new int*[8];

在 double_array函数中,result 被分配在堆上。它是一个指针数组,用于存储指向 matrix 中行的指针。

分配大小8 * sizeof(int*),假设指针大小为 8 字节,则总大小为 64 字节

分配位置:由于堆是按顺序分配的,result 的内存块紧跟在 cout 缓冲区之后。

堆布局

+-------------------+<-- 堆底
| cout 缓冲区 (1024) |
+-------------------+
| result (64)        |
+-------------------+

4. 越界访问的堆内存情况

double_array 函数中,存在以下越界问题:

for (int i = 0; i < n; ++i) {
    result[i] = matrix[i];
}

result 仅分配了 8 个指针的空间(new int*[8]),但代码试图访问 result[0]result[63](共 64 个)。越界访问后,result的内容会覆盖 cout缓冲区的部分内存:result[8]result[63] 的内容会覆盖 cout 缓冲区中第 64 字节后的数据。因为 cout 缓冲区仍是已分配的内存,访问它不会触发段错误。


5. 第三处堆分配:在主函数中的 matrix 静态分配

int matrix[array_number][array_number];

matrix 是一个静态数组,分配在全局内存区域(通常位于数据段)。由于 matrix 的内存地址在堆之外,result[i] = matrix[i]; 操作不会触发段错误,即使 result 越界。


6. 输出数据阶段

在主函数中,遍历 result 并输出数据:

for (int i = 0; i < array_number; ++i) {
    cout << "print address of result[" << i << "] " << &result[i][0] << endl;
    for (int j = 0; j < array_number; j++) {
        result[i][j] = j;
        cout << "print content of result[" << i << "][" << j << "] " << result[i][j] << endl;
    }
}

cout 输出时,cout 缓冲区的内容可能已被越界的 result 写入所覆盖,但这不会立即引发错误。覆盖的内容可能只是错误输出,但不会导致程序崩溃。


堆内存最终布局(带越界覆盖的情况)

  1. 初始分配:cout 缓冲区

    +-------------------+  <-- 堆底
    | cout 缓冲区 (1024) |
    +-------------------+
    
  2. 分配 result 并发生越界覆盖

    +-------------------+  <-- 堆底
    | result (覆盖部分)  |
    | 未被访问部分       |  <-- result[8] 开始覆盖
    +-------------------+
    

由于越界覆盖未触及未分配的非法内存(仍在已分配的 cout 缓冲区范围内),程序避免了段错误。


2. 原代码中导致错误的原因

2.1 堆内存分配不足

int **result = new int*[8];

​ 分配的 result 指针数组大小仅为 8,但程序中访问了 result[0]result[63],显然越界。如果没有 cout 创建的缓冲区,result 的越界可能直接访问未分配或非法的内存区域,导致段错误或堆损坏。

2.2 注释掉 cout 导致未定义行为

cout 的第一处调用被注释掉后,堆上不再创建缓冲区,导致 result 的越界访问破坏了堆的关键结构。如果保留 cout,堆的分配顺序发生了变化,result 的越界行为可能恰好访问到 cout 的缓冲区或未使用的内存区域,从而掩盖了潜在的错误。


3. 解决问题的根本方法

原代码依赖 cout 来掩盖问题是极其不可靠的,正确的方法应当是修复代码中的根本性错误:

正确分配内存大小

int **result = new int*[n]; // n = 64

避免堆内存越界: 确保对指针数组的访问范围在合法区域内。

解决方案

调整内存分配大小: 确保 result 指针数组的大小与实际访问范围一致:

int **result = new int*[n];
#include <iostream>

using namespace std;

#define array_number 64

int matrix[array_number][array_number];

int **double_array(size_t n) {
    // 修复: 确保分配大小为 n
    int **result = new int*[n]; 

    for (int i = 0; i < n; ++i) {
        result[i] = matrix[i]; // 浅拷贝,指向 matrix[i]
        for (int j = 0; j < n; ++j) {
            result[i][j] = j; // 初始化 matrix[i][j]
        }
    }

    return result;
}

int main() {
    // 修复: 注释掉 cout 语句不再影响执行
    // cout << "A magic print! If you comment this, the program will break." << endl;
    int **result = double_array(array_number);

    for (int i = 0; i < array_number; ++i) {
        cout << "print address of result[" << i << "] " << result[i] << endl;
        for (int j = 0; j < array_number; ++j) {
            cout << "print content of result[" << i << "][" << j << "] " << result[i][j] << endl;
        }
    }

    // 修复: 仅释放动态分配的 result 数组
    delete[] result;

    return 0;
}

代码说明

  1. 动态内存分配调整

    int **result = new int*[n];
    

    分配大小为 n,避免越界访问。


结果与总结

修复后程序正常运行,解决了以下问题:避免越界访问:通过正确分配内存,确保访问合法。通过此次修复,理解了内存管理的重要性。

标签:2024.12,越界,26,cout,int,lab3,result,缓冲区,分配
From: https://www.cnblogs.com/vastjoy/p/18632354

相关文章

  • 2024.12.25 周三
    2024.12.25周三Q1.1100Asubarrayisacontinuouspartofarray.Yarikrecentlyfoundanarray$a$of$n$elementsandbecameveryinterestedinfindingthemaximumsumofanonemptysubarray.However,Yarikdoesn'tlikeconsecutiveintegerswitht......
  • 2024.12.25 周三
    2024.12.25周三Q1.1100Asubarrayisacontinuouspartofarray.Yarikrecentlyfoundanarrayaaaofn......
  • 2024.12.23 周一
    2024.12.23周一Q1.1100AliceandBobareplayingagame.Theyhaveanarraya1,a......
  • 【数据集】【YOLO】【目标检测】灭火器识别数据集 3261 张,YOLO灭火器识别算法实战训练
     一、数据集介绍【数据集】灭火器识别数据集3261张,目标检测,包含YOLO/VOC格式标注。数据集中包含1种分类:names:['extinguisher'],表示"灭火器"。数据集图片来自国内外网站、网络爬虫、监控采集等;可用于监控和移动设备灭火器识别。检测场景为工业园区、办公大楼、居民楼......
  • 2024.12.25
    鼻子在吸气时感觉疼痛可能由以下几种原因引起:鼻腔干燥:干燥的环境可能导致鼻腔黏膜变得敏感,呼吸时气体直接刺激黏膜,引发疼痛。增加室内湿度或使用生理盐水喷鼻可以缓解这种不适。感染:上呼吸道感染、急性鼻炎等病症可能引起鼻腔黏膜充血水肿,导致呼吸时鼻部出现疼痛。这类病症......
  • Diary - 2024.12.24
    今天作业有点多了,oi时间约等于0。不懂阿,这个数学作业有点太难了,感觉是给mo同学做的。学oi的大家拼尽全力仍无法战胜其中一道,太难了。今天语文课内知识又考炸了,咳咳。放乐观点(。感觉这个学期的语文老师也是有点抽象的。一周只需要考试写作文,评讲就能用掉三四天,然后剩下......
  • abb机械臂3HAC036260-001驱动器缺相维修
    要判断ABB机器人3HAC036260-001驱动器是否存在缺相问题,可以通过以下几种方法:1、检查驱动器的状态指示灯:通常,驱动器会有状态指示灯来显示其工作状态。如果存在缺相问题,可能会有相应的指示灯亮起或闪烁,提示用户存在故障。2、使用专业的测试设备:例如,可以使用万用表来检测驱动器的输入......
  • ssm考研助手v26k3(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、项目背景与意义随着社会竞争的加剧,越来越多的学生选择考研以提升学术层次和就业竞争力。然而,考研过程中,信息收集、资料整理、复习计划制定等问......
  • 2024.12.24 周四
    2024.12.24周四Q1.1100Youaregivenanarray$a$of$n$positiveintegersandascore.Ifyourscoreisgreaterthanorequalto$a_i$,thenyoucanincreaseyourscoreby$a_i$andremove$a_i$fromthearray.Foreachindex$i$,outputthemaximumnum......
  • 2024.12.16(周一)
    namespaceDatabase.MainForm{partialclassChangePassword{///<summary>///Requireddesignervariable.///</summary>privateSystem.ComponentModel.IContainercomponents=null;///<summary&......