C program outputs to stdout just fine on Linux, but won’t output anything for Windows

I wrote a pair of programs to allow someone to send arbitrary binary files over a specific radio mode with a restricted character set, where each character is represented with some Huffman code. One program is an encoder, the other is a decoder.

The programs work fine on Linux. It operates exclusively over stdin and stdout. I fuzzed them using 1 GiB random files. However, when I try to compile it for Windows (using either cl.exe or x86_64-w64-mingw32-gcc (on WSL), the programs refuses to output anything to any output stream.

I tried removing all outputs to stderr, tried to do two putchar() calls with 'r' 'n' (thinking it was an issue with LF vs CRLF), fflush() every time I putchar(), but it still won’t work. The only thing that worked was completely commenting out the main while loop in the encoder program, in which I managed to get the initial printed string FILE:.

With the loop not commented out, I won’t even get the first printf() with an immediate fflush(stdout) afterwards. The program, however, will halt. Below is one of the programs, which I want to debug first.

For sanity checking, I tried to compile a simple Hello World! program that uses both printf() and putchar(), and it works fine on Windows, but my specific program does not. I’m at a loss as to where to check first.

js8file_enc.c

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#include "js8file_enc.h"
// From stdin
bool fill_buffer(bool * bitbuf, size_t * buf_size, bool ** bitbuf_read_head_ptr){
// Justify remaining buffer back to the beginning
if(*buf_size > 0){
memmove(bitbuf, *bitbuf_read_head_ptr, *buf_size);
}
// Read from stdin (indeterminate length), keep track of buffer size
char buf[BUF_SIZE];
// The max bytes here is sizeof(buf) - ceil(*buf_size/8) expressed in a roundabout way.
// This will fill our byte buffer as much as possible for the bit buffer to be near-full in the next step.
size_t increase = fread(buf, 1, sizeof(buf) - ((*buf_size+8-1)/8), stdin);
// Extract bits from byte buffer
for(size_t i = 0; i < increase; i++){
for(int j = 0; j < 8; j++){
bitbuf[*buf_size] = (buf[i] >> (7 - j)) & 1;
(*buf_size)++;
}
}
*bitbuf_read_head_ptr = bitbuf;
return increase > 0;
}
int main(){
printf("FILE:");
bool bitbuf[BUF_SIZE*8];
bool * bitbuf_read_head = bitbuf;
size_t buf_size = 0; // In bits
while(true){
if(buf_size < 8){ // 8 bits, length of longest key
if(!fill_buffer(bitbuf, &buf_size, &bitbuf_read_head)){
// There may still be bits remaining (<8), encode the rest
while(buf_size > 0){
for(int i = buf_size; i > 0; i--){
if(LUT[i] == NULL){
continue;
}
uint8_t key = 0;
for(int j = 0; j < i; j++){
key |= bitbuf_read_head[j] << (i - j - 1);
}
if(LUT[i][key] != 0){
putchar(LUT[i][key]);
bitbuf_read_head += i;
buf_size -= i;
break;
}
}
}
break;
}
}
int max_key_size = (buf_size < 8) ? buf_size : 8;
// Produce keys in descending order, check for first match, write to stdout, then move buffer head.
// If there are no codewords of length n (that is, LUT[n] is NULL), then we skip to the next length.
for(int i = max_key_size; i > 0; i--){
if(LUT[i] == NULL){
continue;
}
uint8_t key = 0;
for(int j = 0; j < i; j++){
key |= bitbuf_read_head[j] << (i - j - 1);
}
if(LUT[i][key] != 0){
putchar(LUT[i][key]);
bitbuf_read_head += i;
buf_size -= i;
break;
}
}
}
fflush(stdout);
fprintf(stderr, "<EOF>n");
fflush(stderr);
return 0;
}
</code>
<code>#include "js8file_enc.h" // From stdin bool fill_buffer(bool * bitbuf, size_t * buf_size, bool ** bitbuf_read_head_ptr){ // Justify remaining buffer back to the beginning if(*buf_size > 0){ memmove(bitbuf, *bitbuf_read_head_ptr, *buf_size); } // Read from stdin (indeterminate length), keep track of buffer size char buf[BUF_SIZE]; // The max bytes here is sizeof(buf) - ceil(*buf_size/8) expressed in a roundabout way. // This will fill our byte buffer as much as possible for the bit buffer to be near-full in the next step. size_t increase = fread(buf, 1, sizeof(buf) - ((*buf_size+8-1)/8), stdin); // Extract bits from byte buffer for(size_t i = 0; i < increase; i++){ for(int j = 0; j < 8; j++){ bitbuf[*buf_size] = (buf[i] >> (7 - j)) & 1; (*buf_size)++; } } *bitbuf_read_head_ptr = bitbuf; return increase > 0; } int main(){ printf("FILE:"); bool bitbuf[BUF_SIZE*8]; bool * bitbuf_read_head = bitbuf; size_t buf_size = 0; // In bits while(true){ if(buf_size < 8){ // 8 bits, length of longest key if(!fill_buffer(bitbuf, &buf_size, &bitbuf_read_head)){ // There may still be bits remaining (<8), encode the rest while(buf_size > 0){ for(int i = buf_size; i > 0; i--){ if(LUT[i] == NULL){ continue; } uint8_t key = 0; for(int j = 0; j < i; j++){ key |= bitbuf_read_head[j] << (i - j - 1); } if(LUT[i][key] != 0){ putchar(LUT[i][key]); bitbuf_read_head += i; buf_size -= i; break; } } } break; } } int max_key_size = (buf_size < 8) ? buf_size : 8; // Produce keys in descending order, check for first match, write to stdout, then move buffer head. // If there are no codewords of length n (that is, LUT[n] is NULL), then we skip to the next length. for(int i = max_key_size; i > 0; i--){ if(LUT[i] == NULL){ continue; } uint8_t key = 0; for(int j = 0; j < i; j++){ key |= bitbuf_read_head[j] << (i - j - 1); } if(LUT[i][key] != 0){ putchar(LUT[i][key]); bitbuf_read_head += i; buf_size -= i; break; } } } fflush(stdout); fprintf(stderr, "<EOF>n"); fflush(stderr); return 0; } </code>
#include "js8file_enc.h"

// From stdin
bool fill_buffer(bool * bitbuf, size_t * buf_size, bool ** bitbuf_read_head_ptr){
    // Justify remaining buffer back to the beginning
    if(*buf_size > 0){
        memmove(bitbuf, *bitbuf_read_head_ptr, *buf_size);
    }
    // Read from stdin (indeterminate length), keep track of buffer size
    char buf[BUF_SIZE];
    // The max bytes here is sizeof(buf) - ceil(*buf_size/8) expressed in a roundabout way.
    // This will fill our byte buffer as much as possible for the bit buffer to be near-full in the next step.
    size_t increase = fread(buf, 1, sizeof(buf) - ((*buf_size+8-1)/8), stdin);
    // Extract bits from byte buffer
    for(size_t i = 0; i < increase; i++){
        for(int j = 0; j < 8; j++){
            bitbuf[*buf_size] = (buf[i] >> (7 - j)) & 1;
            (*buf_size)++;
        }
    }
    *bitbuf_read_head_ptr = bitbuf;
    return increase > 0;
}

int main(){
    printf("FILE:");
    bool bitbuf[BUF_SIZE*8];
    bool * bitbuf_read_head = bitbuf;
    size_t buf_size = 0; // In bits
    while(true){
        if(buf_size < 8){ // 8 bits, length of longest key
            if(!fill_buffer(bitbuf, &buf_size, &bitbuf_read_head)){
                // There may still be bits remaining (<8), encode the rest
                while(buf_size > 0){
                    for(int i = buf_size; i > 0; i--){
                        if(LUT[i] == NULL){
                            continue;
                        }
                        uint8_t key = 0;
                        for(int j = 0; j < i; j++){
                            key |= bitbuf_read_head[j] << (i - j - 1);
                        }
                        if(LUT[i][key] != 0){
                            putchar(LUT[i][key]);
                            bitbuf_read_head += i;
                            buf_size -= i;
                            break;
                        }
                    }
                }
                break;
            }
        }
        int max_key_size = (buf_size < 8) ? buf_size : 8;
        // Produce keys in descending order, check for first match, write to stdout, then move buffer head.
        // If there are no codewords of length n (that is, LUT[n] is NULL), then we skip to the next length.
        for(int i = max_key_size; i > 0; i--){
            if(LUT[i] == NULL){
                continue;
            }
            uint8_t key = 0;
            for(int j = 0; j < i; j++){
                key |= bitbuf_read_head[j] << (i - j - 1);
            }
            if(LUT[i][key] != 0){
                putchar(LUT[i][key]);
                bitbuf_read_head += i;
                buf_size -= i;
                break;
            }
        }
    }
    fflush(stdout);
    fprintf(stderr, "<EOF>n");
    fflush(stderr);
    return 0;
}

js8file_enc.h

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#include "ref.h"
// Indexed by codeword length (.bits)
const unsigned char * LUT[9] = {
[0] = NULL,
[1] = (unsigned char[0b10]){
[0b0] = ' ',
[0b1] = 'E'
},
[2] = NULL,
[3] = NULL,
[4] = (unsigned char[0b10000]){
[0b1101] = 'T',
[0b0011] = 'A'
},
[5] = (unsigned char[0b100000]){
[0b11111] = 'O',
[0b11100] = 'I',
[0b10111] = 'N',
[0b10100] = 'S',
[0b00011] = 'H',
[0b00000] = 'R'
},
[6] = (unsigned char[0b1000000]){
[0b111011] = 'D',
[0b110011] = 'L',
[0b110001] = 'C',
[0b101101] = 'U',
[0b101011] = 'M',
[0b001011] = 'W',
[0b001001] = 'F',
[0b000101] = 'G',
[0b000011] = 'Y'
},
[7] = (unsigned char[0b10000000]){
[0b1111011] = 'P',
[0b1111001] = 'B',
[0b1110100] = '.',
[0b1100101] = 'V',
[0b1100100] = 'K',
[0b1100001] = '-',
[0b1100000] = '+',
[0b1011001] = '?',
[0b1011000] = '!',
[0b1010101] = '"',
[0b1010100] = 'X',
[0b0010101] = '0',
[0b0010100] = 'J',
[0b0010001] = '1',
[0b0010000] = 'Q',
[0b0001001] = '2',
[0b0001000] = 'Z',
[0b0000101] = '3',
[0b0000100] = '5'
},
[8] = (unsigned char[0b100000000]){
[0b11110101] = '4',
[0b11110100] = '9',
[0b11110001] = '8',
[0b11110000] = '6',
[0b11101011] = '7',
[0b11101010] = '/'
}
};
</code>
<code>#include "ref.h" // Indexed by codeword length (.bits) const unsigned char * LUT[9] = { [0] = NULL, [1] = (unsigned char[0b10]){ [0b0] = ' ', [0b1] = 'E' }, [2] = NULL, [3] = NULL, [4] = (unsigned char[0b10000]){ [0b1101] = 'T', [0b0011] = 'A' }, [5] = (unsigned char[0b100000]){ [0b11111] = 'O', [0b11100] = 'I', [0b10111] = 'N', [0b10100] = 'S', [0b00011] = 'H', [0b00000] = 'R' }, [6] = (unsigned char[0b1000000]){ [0b111011] = 'D', [0b110011] = 'L', [0b110001] = 'C', [0b101101] = 'U', [0b101011] = 'M', [0b001011] = 'W', [0b001001] = 'F', [0b000101] = 'G', [0b000011] = 'Y' }, [7] = (unsigned char[0b10000000]){ [0b1111011] = 'P', [0b1111001] = 'B', [0b1110100] = '.', [0b1100101] = 'V', [0b1100100] = 'K', [0b1100001] = '-', [0b1100000] = '+', [0b1011001] = '?', [0b1011000] = '!', [0b1010101] = '"', [0b1010100] = 'X', [0b0010101] = '0', [0b0010100] = 'J', [0b0010001] = '1', [0b0010000] = 'Q', [0b0001001] = '2', [0b0001000] = 'Z', [0b0000101] = '3', [0b0000100] = '5' }, [8] = (unsigned char[0b100000000]){ [0b11110101] = '4', [0b11110100] = '9', [0b11110001] = '8', [0b11110000] = '6', [0b11101011] = '7', [0b11101010] = '/' } }; </code>
#include "ref.h"

// Indexed by codeword length (.bits)
const unsigned char * LUT[9] = {
    [0] = NULL,
    [1] = (unsigned char[0b10]){
        [0b0] = ' ',
        [0b1] = 'E'
    },
    [2] = NULL,
    [3] = NULL,
    [4] = (unsigned char[0b10000]){
        [0b1101] = 'T',
        [0b0011] = 'A'
    },
    [5] = (unsigned char[0b100000]){
        [0b11111] = 'O',
        [0b11100] = 'I',
        [0b10111] = 'N',
        [0b10100] = 'S',
        [0b00011] = 'H',
        [0b00000] = 'R'
    },
    [6] = (unsigned char[0b1000000]){
        [0b111011] = 'D',
        [0b110011] = 'L',
        [0b110001] = 'C',
        [0b101101] = 'U',
        [0b101011] = 'M',
        [0b001011] = 'W',
        [0b001001] = 'F',
        [0b000101] = 'G',
        [0b000011] = 'Y'
    },
    [7] = (unsigned char[0b10000000]){
        [0b1111011] = 'P',
        [0b1111001] = 'B',
        [0b1110100] = '.',
        [0b1100101] = 'V',
        [0b1100100] = 'K',
        [0b1100001] = '-',
        [0b1100000] = '+',
        [0b1011001] = '?',
        [0b1011000] = '!',
        [0b1010101] = '"',
        [0b1010100] = 'X',
        [0b0010101] = '0',
        [0b0010100] = 'J',
        [0b0010001] = '1',
        [0b0010000] = 'Q',
        [0b0001001] = '2',
        [0b0001000] = 'Z',
        [0b0000101] = '3',
        [0b0000100] = '5'
    },
    [8] = (unsigned char[0b100000000]){
        [0b11110101] = '4',
        [0b11110100] = '9',
        [0b11110001] = '8',
        [0b11110000] = '6',
        [0b11101011] = '7',
        [0b11101010] = '/'
    }
};

ref.h

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
// DEFAULT SETTING: 524288
// 512 KiB, packed (bytes read from stdin)
// 4 MiB, unpacked (512 KiB worth of bits stored in bitbuf)
// Changed for debugging purposes
#define BUF_SIZE 524288
typedef const struct codeword{
const uint8_t key;
const uint8_t bits;
} codeword;
</code>
<code>#include <stdio.h> #include <stdbool.h> #include <string.h> #include <stdlib.h> #include <stdint.h> #include <sys/types.h> // DEFAULT SETTING: 524288 // 512 KiB, packed (bytes read from stdin) // 4 MiB, unpacked (512 KiB worth of bits stored in bitbuf) // Changed for debugging purposes #define BUF_SIZE 524288 typedef const struct codeword{ const uint8_t key; const uint8_t bits; } codeword; </code>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
// DEFAULT SETTING: 524288
// 512 KiB, packed (bytes read from stdin)
// 4 MiB, unpacked (512 KiB worth of bits stored in bitbuf)
// Changed for debugging purposes
#define BUF_SIZE 524288

typedef const struct codeword{
    const uint8_t key;
    const uint8_t bits;
} codeword;

EDIT: The first answer states that the default Windows stack size is 1 MB. I did not know this, and I’ll test out this fix.

3

This line in main():

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>bool bitbuf[BUF_SIZE * 8];
</code>
<code>bool bitbuf[BUF_SIZE * 8]; </code>
bool bitbuf[BUF_SIZE * 8];

Where BUF_SIZE is defined in ref.h as 524288. That’s going to allocate 4 megabytes off the stack on startup. That crashes your program before it can even get to the printf("FILE:") statement.

By default, the VC compiler only allows 1MB of stack size.

Solutions:

  • Change the above line to be:

    bool* bitbuf = malloc(BUF_SIZE*8);

    (Don’t forget to free it when done)

OR

  • Use the compiler and linker flags for increasing stack size (I can look this up if you want), but the above solution of using a dynamic memory allocation is better.

Similarly, the char buf[BUF_SIZE]; in fill_buffer is taking up 512KB of stack.

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật