Fprintf写入结构体成员时出现数据冗余与越界问题排查
问题原因
你的程序出现额外写入、hash内容重复且超长的问题,核心原因是用%s格式化输出二进制数据:
hash和salt是二进制数组(并非以\0结尾的C字符串),而fprintf的%s格式符会持续读取内存,直到遇到第一个\0才停止。- 结构体
user中hash字段紧邻salt字段,输出users[0].hash时,%s会把32字节的hash全部输出后,继续读取后续的salt内容(甚至更多内存数据),最终导致输出内容超长、重复。
解决方案
针对二进制数据的写入,有两种可靠的处理方式:
方式1:用fwrite直接写入指定长度的字节
fwrite可以精确控制写入的字节数,彻底避免越界读取:
FILE *fp = fopen(argv[1], "w+"); // 确保用户名以\0结尾(strncpy可能不会自动添加终止符) users[0].uName[31] = '\0'; // 写入用户名 fputs(users[0].uName, fp); fputc(' ', fp); // 写入32字节的hash fwrite(users[0].hash, 1, 32, fp); fputc(' ', fp); // 写入16字节的salt fwrite(users[0].salt, 1, 16, fp); fputc('\n', fp); fclose(fp);
方式2:将二进制数据转为十六进制字符串输出
把二进制数据转成十六进制字符串后,可安全用%s输出(字符串自带\0终止符),还能提升内容可读性:
// 定义足够长度的十六进制字符串缓冲区 char hash_hex[65]; // 32字节*2 + 1(存储终止符) char salt_hex[33]; // 16字节*2 + 1(存储终止符) // 使用libsodium工具函数转换为十六进制 sodium_bin2hex(hash_hex, sizeof(hash_hex), users[0].hash, 32); sodium_bin2hex(salt_hex, sizeof(salt_hex), users[0].salt, 16); // 安全输出内容 FILE *fp = fopen(argv[1], "w+"); users[0].uName[31] = '\0'; fprintf(fp, "%s %s %s\n", users[0].uName, hash_hex, salt_hex); fclose(fp);
额外优化点
- 原代码中
strcpy(passSalt, argv[3]);是多余操作,后续strncpy会覆盖passSalt的前16字节,且sha256_process仅处理前16字节,可直接删除该行。 - 所有
strncpy操作后,建议手动添加\0终止符,避免字符串处理时出现越界问题。
内容的提问来源于stack exchange,提问作者gent9
相关产品推荐
相关产品推荐

