Today one of my fellow encountered a bug. He was working on a server/client app, the server and client use zlib to compress telegram before sending and after receiving. The programs work fine in debug build, however they failed to send and receive in release build.
As a few minutes' investigation, I relized the programs work fine before he introduces the compression, so I looked into his compression module. He implemented a pretty module to accept data pieces and pack them, and compress, like this:
class data_packer{public: data_packer(); void add(const char* buf, int len); void pack(); int compressed_size() const; const char* compressed_data() const;private: char _data[100000]; char _compressed[100000]; int _size; int _compressed_size;};
other parts are not related to this bug, so i just show the functions caused the problem:
data_packer::data_packer() : _size(0){}void data_packer::pack(){ // use zlib's compress function compress(_compressed, &_compressed_size, _data, _size);}
As you can see, the _compressed_size is not initialized. However many prople may say it's OK because the compress function asks for a pointer, so that it wants to send out the compressed size. Yes it's true, but that's only half of it. In fact, the compress function uses 2nd argument as in/out parameter. It uses the 2nd argument to determine whether the provided buffer (1st argument) is big enough. And here is the fact that, my fellow is only lucky enough in debug build because the uninitialized _compressed_size member is larger than the truely required byte count, while in release build it's not. OK, case is closed, modify the pack method like this and the problem is resolved.
void data_packer::pack(){ _compressed_size = 1000000; compress(...);}
Actually this is not the best practise. In production code, a call to compressBound() to determine the safe buffer size is recommended. Also, this bug shows us, when you send a pointer to a function, you'd better check whether the function uses the value!