CS50 Recover程序仍存在可访问内存问题,Valgrind无错误求助
调试CS50 recover程序的问题排查
我调试CS50的recover程序已经耗了好几个小时,还没找到问题所在。我认为所有文件都已关闭,且未使用malloc进行内存分配。恳请提供排查提示或指导,非常感谢!
Valgrind检测结果
==34245== Memcheck, a memory error detector ==34245== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==34245== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info ==34245== Command: ./recover card.raw ==34245== ==34245== ==34245== HEAP SUMMARY: ==34245== in use at exit: 944 bytes in 2 blocks ==34245== total heap usage: 104 allocs, 102 frees, 233,912 bytes allocated ==34245== ==34245== 944 bytes in 2 blocks are still reachable in loss record 1 of 1 ==34245== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==34245== by 0x4A076CD: __fopen_internal (iofopen.c:65) ==34245== by 0x4A076CD: fopen@@GLIBC_2.2.5 (iofopen.c:86) ==34245== by 0x1092A9: main (recover.c:48) ==34245== ==34245== LEAK SUMMARY: ==34245== definitely lost: 0 bytes in 0 blocks ==34245== indirectly lost: 0 bytes in 0 blocks ==34245== possibly lost: 0 bytes in 0 blocks ==34245== still reachable: 944 bytes in 2 blocks ==34245== suppressed: 0 bytes in 0 blocks ==34245== ==34245== For lists of detected and suppressed errors, rerun with: -s ==34245== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
我的代码
#include <stdio.h> #include <stdlib.h> #include <stdint.h> int main(int argc, char *argv[]) { // Ensure proper usage if (argc != 2) { printf("Usage: ./recover card\n"); return 1; } // If the forensic image cannot be opened for reading, your program should inform the user as much, and main should return 1. // Remember filenames char *infile = argv[1]; // Open input file FILE *inptr = fopen(infile, "r"); if (inptr == NULL) { printf("Could not open %s.\n", infile); fclose(inptr); return 1; } // block size is 512 bytes typedef uint8_t BYTE; int BLOCK_SIZE = sizeof(BYTE) * 512; BYTE buffer[BLOCK_SIZE]; int index = 0; FILE *img = NULL; // The files you generate should each be named ###.jpg, where ### is a three-digit decimal number, starting with 000 for the first image and counting up. while (fread(buffer, 1, BLOCK_SIZE, inptr) == BLOCK_SIZE) { char filename[8]; // is first pic. if (index == 0) { sprintf(filename, "%03i.jpg", index); img = fopen(filename, "w"); if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { if (img != NULL) { fwrite(buffer, 1, BLOCK_SIZE, img); } index++; } } else { //is not first pic if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { //is a new img //close prev img if (img != NULL) { fclose(img); } // open a new img sprintf(filename, "%03i.jpg", index); img = fopen(filename, "w"); fwrite(buffer, 1, BLOCK_SIZE, img); index++; } else { //keep writing fwrite(buffer, 1, BLOCK_SIZE, img); } } //Your program, if it uses malloc, must not leak any memory. } if (img != NULL) { fclose(img); } fclose(inptr); return (0); }
排查提示与问题修正
1. 错误的文件打开时机(导致文件句柄泄漏)
在index == 0的分支中,你先打开了000.jpg,再检查当前块是否是JPG签名。如果第一个块不是JPG起始签名,这个文件会被打开但不会写入内容,且后续循环会再次打开同一个文件,覆盖img指针,导致之前的文件句柄丢失——这正是Valgrind检测到的still reachable内存块的来源。
修正: 先检查当前块是否符合JPG签名,确认是之后再打开文件:
if (index == 0) { if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { sprintf(filename, "%03i.jpg", index); img = fopen(filename, "w"); if (img != NULL) { fwrite(buffer, 1, BLOCK_SIZE, img); } index++; } }
2. fclose(NULL)的无效操作
当inptr为NULL时,你调用了fclose(inptr),但NULL指针不需要关闭,这会引发未定义行为。
修正: 删除fclose(inptr);这一行:
if (inptr == NULL) { printf("Could not open %s.\n", infile); return 1; }
3. 未处理最后一个不足512字节的块
循环仅处理fread返回等于BLOCK_SIZE的情况,但文件末尾可能存在不足512字节的块,这部分属于最后一个JPG的内容,需要写入。
修正: 记录fread的返回值,循环退出后如果img不为空且读取到字节,就写入:
size_t bytes_read; while ((bytes_read = fread(buffer, 1, BLOCK_SIZE, inptr)) == BLOCK_SIZE) { // 原循环逻辑 } // 处理最后一个块 if (img != NULL && bytes_read > 0) { fwrite(buffer, 1, bytes_read, img); }
4. 潜在的空指针fwrite风险
在非第一个文件的分支中,如果还未找到第一个JPG(img仍为NULL),直接调用fwrite会导致错误。需要先判断img是否有效再写入:
修正:
} else { //keep writing if (img != NULL) { fwrite(buffer, 1, BLOCK_SIZE, img); } }
内容的提问来源于stack exchange,提问作者lgtits
相关产品推荐
相关产品推荐

