fwrite触发段错误排查:简易文件系统实现问题咨询
问题描述
我正在按照一份指南实现简易文件系统,采用文件读写接口。代码尚未重构,但执行super block的fwrite语句时触发段错误,注释该行后程序可正常运行,请指出可能的错误。
相关代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define TOTAL_FILE_SIZE 4227104 #define TOTAL_DIR_ENTRIES 1024 #define NUM_FAT_ENTRIES 8192 typedef struct super_block { unsigned short total_sectors; /* max value 8192 */ unsigned short bytes_per_sector; /* max value 512 */ unsigned short available_sectors; /* max value 8192 */ unsigned short total_dir_entries; /* fixing it to 1024 */ unsigned short available_dir_entries; /* max value 1024 */ unsigned char label[8]; /* label for the filesystem */ /* These are not used */ unsigned short sectors_per_cluster; /* We always set it to 1*/ unsigned char reserved[12]; /* Just making it 32 bytes */ } super_block; /* Each dir entry is 16 bytes */ typedef struct dir_entry { unsigned char file_name[10]; unsigned short fat_entry; unsigned int size; } dir_entry; /* Each FAT entry is 2 bytes; times 8192 entries => 16 KiB * size of data block (sector) can be varied * number of dir_entries can be varied * the number of fat entries is same as the number of data blocks * the number of data blocks can be varied total_sectors * * the total size of our filesystem is => + * size of super block = 32 bytes * size of dir entry = 16 KiB * size of fat = 16 KiB * total size of data block = 8192 * 512 bytes => 4 MiB * Total bytes = 4227104 * End: sFAT.c */ /* mkfs.c * */ /* Later: integrate label of FS to argument */ void mkfs(const char *filename) { /* Write super block, dir entries and fat table and data blocks to the file */ super_block sb = { .total_sectors = 8192, .bytes_per_sector = 512, .available_sectors = 512, .total_dir_entries = 1024, .available_dir_entries = 1024, .sectors_per_cluster = 1, .label = "Demo FS", .reserved = "" }; dir_entry default_dir_entry = { .file_name = "", .fat_entry = 0, .size = 0, }; unsigned short default_fat_entry = 0; /* Write sb, 1024 dir_entry and 8192 default_fat_entry and 4 MiB data to create our filesystem */ FILE *f = fopen(filename, "wb"); if (f == NULL) { fprintf(stderr, "Error opening file: %s\n", filename); } /* Write super block */ /* I seem to encounter SEGMENTATION FAULT in this line */ fwrite(&sb, sizeof (super_block), 1, f); /* Write dir entries */ fwrite(&default_dir_entry, sizeof(dir_entry), TOTAL_DIR_ENTRIES, f); fwrite(&default_fat_entry, sizeof(unsigned short), NUM_FAT_ENTRIES, f); char *data; data = malloc(TOTAL_FILE_SIZE - ftell(f)); fwrite(data, TOTAL_FILE_SIZE - ftell(f), 1, f); free(data); fclose(f); fprintf(stdout, "Filesystem created successfully!\n"); } /* End: mkfs.c */ /* main.c * */ void display_help(char *program_name) { fprintf(stdout, "Usage: %s [function name]\n", program_name); fprintf(stdout, "Functions:\n"); fprintf(stdout," mkfs <filename>\n"); } int main(int argc, char *argv[]) { if (argc < 2) { display_help(argv[0]); return 1; } if (strcmp(argv[1], "mkfs") == 0) { if (argc < 3) { fprintf(stderr, "mkfs requires a filename argument\n"); display_help(argv[0]); return 1; } mkfs(argv[2]); } else { display_help(argv[0]); return 1; } return 0; } /* * * End: main.c */
错误分析与修复方案
1. 结构体字符数组初始化错误
C语言中不能直接用字符串常量给字符数组赋值,你在初始化super_block和dir_entry时犯了这个错误:
.label = "Demo FS":试图把字符串指针赋值给unsigned char[8]类型的数组,会破坏结构体内存布局,导致fwrite访问非法内存。.reserved = "":reserved是unsigned char[12],同样不能直接用空字符串赋值。.file_name = "":dir_entry的file_name是unsigned char[10],该赋值方式同样非法。
修复方法:
使用strcpy或memset初始化字符数组,或用初始化列表逐个赋值:
// 初始化super_block super_block sb = { .total_sectors = 8192, .bytes_per_sector = 512, .available_sectors = 512, .total_dir_entries = 1024, .available_dir_entries = 1024, .sectors_per_cluster = 1 }; strcpy((char*)sb.label, "Demo FS"); // 强制类型转换适配unsigned char数组 memset(sb.reserved, 0, sizeof(sb.reserved)); // 清零reserved数组 // 初始化dir_entry dir_entry default_dir_entry = { .fat_entry = 0, .size = 0 }; memset(default_dir_entry.file_name, 0, sizeof(default_dir_entry.file_name));
2. 文件打开失败后未终止函数
当fopen失败时,f的值为NULL,但你没有退出mkfs函数,后续fwrite(&sb, ..., f)会对NULL指针操作,直接触发段错误。
修复方法:
打开文件失败后立即返回,避免后续非法操作:
FILE *f = fopen(filename, "wb"); if (f == NULL) { fprintf(stderr, "Error opening file: %s\n", filename); return; // 终止函数,避免后续操作空指针 }
3. main函数参数检查缺失
执行mkfs时需要传入文件名(即argv[2]),但原代码未检查argc >= 3,若用户只输入./program mkfs,argv[2]会是NULL,传给mkfs后fopen(NULL)失败,进而触发段错误。
修复方法:
在main函数中添加参数检查:
if (strcmp(argv[1], "mkfs") == 0) { if (argc < 3) { fprintf(stderr, "Error: mkfs requires a filename argument\n"); display_help(argv[0]); return 1; } mkfs(argv[2]); }
4. 额外优化:malloc内存未初始化
malloc分配的内存是未初始化的垃圾数据,虽不影响段错误,但如果需要数据块全为0,建议用calloc或memset清零:
data = calloc(TOTAL_FILE_SIZE - ftell(f), 1); // 分配并自动清零内存 // 或 data = malloc(TOTAL_FILE_SIZE - ftell(f)); if (data != NULL) { memset(data, 0, TOTAL_FILE_SIZE - ftell(f)); }
内容的提问来源于stack exchange,提问作者Udeshya D.
相关产品推荐
相关产品推荐

