fwrite()将垃圾数据添加到输出(WINE&Windows 7,mingw&MSVC; NOT linux/gcc)

use*_*954 6 c windows stdio fwrite

在某些情况下,fwrite写入额外数据(比请求的字节多).简短演示的输出是最简单的解释方式.该演示尝试创建两个2048字节的文件,并在每次fwrite调用后检查偏移量,以确定写入的字节数.第一个fwrite调用写入两个额外的字节:

len: 2048
current offset = 0
wrote 1024 bytes
current offset = 1026
EXITING:
offset % BLOCKSIZE = 2

len: 2048
current offset = 0
wrote 1024 bytes
current offset = 1024
wrote 1024 bytes
SUCCESS
Run Code Online (Sandbox Code Playgroud)

当编译为ELF(unix二进制文件)时,程序成功运行(写入2048字节到两个文件),但在编译为PE(Windows二进制文件/可执行文件)时失败(如上所示).我尝试过编译和测试:

Ubuntu 14.04 and gcc 4.8.2 - SUCCESS
WINE 1.6.2 and mingw 4.8.2 - FAIL
Windows 7 and mingw 4.8.2 - FAIL
Windows 7 and Visual Studio 2013 - FAIL
Run Code Online (Sandbox Code Playgroud)

传递的缓冲区中的实际数据fwrite会影响写入的额外字节数,但实际上每次都会发生这种情况(除非您写入NULL字节).

main.c中:

#include <stdio.h>

#include "stub.h"
#include "stub2.h"

size_t min(size_t a, size_t b)
{
    return a<b?a:b;
}

#define BLOCKSIZE 1024

void test(char buf[], size_t len)
{
    FILE *f = fopen("out", "w");

    printf("len: %lu\n", len);
    for(size_t i=0;i<len;i+=BLOCKSIZE)
    {
        printf("current offset = %lu\n", ftell(f));
        if(ftell(f) % BLOCKSIZE)
        {
            printf("EXITING:\noffset %% BLOCKSIZE = %d\n\n", ftell(f) % BLOCKSIZE);
            return;
        }
        size_t wrote = fwrite(buf + i, 1, min(len - i, BLOCKSIZE), f);
        printf("wrote %lu bytes\n", wrote);
    }

    printf("SUCCESS\n\n");

    fclose(f);
}

int main()
{
    test(stub_exe, stub_exe_len);
    test(stub2_exe, stub2_exe_len);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

stub.h并且stub2.h从/ dev/urandom的2048个字节和/ dev/zero(分别)的2048个字节生成xxd.例如:

dd if=/dev/urandom of=stub2.exe bs=2048 count=1
xxd -i stub.exe stub.h
dd if=/dev/zero of=stub2.exe bs=2048 count=1
xxd -i stub2.exe stub2.h
Run Code Online (Sandbox Code Playgroud)

use*_*954 5

免责声明:已经过去 5 天了,没有人发布“官方”答案,所以我做出这个答案并接受它。功劳在于Christophe实际Retired Ninja回答了这个问题。

简单的答案是您需要以二进制模式打开二进制文件(通过在fopen第二个参数中添加“b”)。

默认情况下,fopen以文本模式而不是二进制模式打开文件。在文本模式下,写入文件时换行符 ( \n) 会被操作系统的换行序列替换,读取时反之亦然。与使用单个字符 ( \n) 作为换行符的 POSIX 系统(Linux、OSX、BSD 等)不同,Windows 使用\r\n换行符序列。