zlib inflateReset causes memory leak (not) - c

I am currently working on the below requirement.
Here is the requirement: On the server side a large file is divided into 4000-byte blocks (frames). Each block is in turn compressed (using zlib) and sent to client process. For instance, if a file is 12000 bytes in size then it is divided into 3 blocks.
Above file will have 3 blocks => Block-0, Block-1, Block-2
On receipt, client decompresses each block (or frame) and writes to buffer allocated on the heap.When all the blocks corresponding to the entire file is received by the client, then the uncompressed version of the resultant file is written to the disk.
I have written a routine inflateData that does the following based on the block # received:
When the first block is received,
- inflateInit
- inflate
- inflateReset
When the intermediate blocks are received,
- inflate
- inflateReset
When the last block is received,
- inflate
- inflateEnd
With the above routine, Decompression of blocks happens as expected. But the issue that I face is it consumes lots of memory and at some point entire system slows down. When checked with valgrind, memory leak is reported with inflateInit2_. This causes the system resources to be exhausted.
==30359== 57,312 bytes in 6 blocks are possibly lost in loss record 64 of 67
==30359== at 0x4A069EE: malloc (vg_replace_malloc.c:270)
==30359== by 0x3E57808F1E: inflateInit2_ (in /lib64/libz.so.1.2.3)
==30359== by 0x40C220: inflateData (productMaker.c:1668)
Below is the routine inflateData.
int inflateData(
char* const inBuf,
unsigned long inLen,
unsigned int isFirstBlk,
unsigned int isLastBlk,
const char* outBuf,
unsigned long* outLen)
{
int have;
int readsz;
int bsize;
static z_stream zstrm;
int zerr;
int flush;
char out[CHUNK_SZ];
char in[CHUNK_SZ];
int ret,nwrite,idx = -1;
int savedByteCntr=0;
unsigned char *dstBuf;
int firstCall = 1;
int totalBytesIn=0;
int inflatedBytes=0;
int decompByteCounter = 0;
int num=0;
ret = Z_OK;
readsz = 0;
bsize = CHUNK_SZ;
dstBuf = (unsigned char *) outBuf;
if(isFirstBlk){
memset(&zstrm, '\0', sizeof(z_stream));
zstrm.zalloc = Z_NULL;
zstrm.zfree = Z_NULL;
zstrm.opaque = Z_NULL;
if ((zerr = inflateInit(&zstrm)) != Z_OK) {
uerror("ERROR %d inflateInit (%s)",
zerr, decode_zlib_err(zerr));
return -1;
}
}
while(totalBytesIn < inLen ) {
int compChunkSize = ((inLen - totalBytesIn) > 5120) ? 5120 :
(inLen - totalBytesIn);
memcpy(in, inBuf + totalBytesIn, compChunkSize);
zstrm.avail_in = inLen - totalBytesIn;
zstrm.next_in = in ;
zstrm.avail_out = CHUNK_SZ;
zstrm.next_out = out;
inflatedBytes = 0;
while(ret != Z_STREAM_END) {
ret = inflate(&zstrm, Z_NO_FLUSH);
if(ret < 0) {
uerror(" Error %d inflate (%s)", ret, decode_zlib_err(ret));
(void)inflateEnd(&zstrm);
return ret;
}
inflatedBytes = CHUNK_SZ - zstrm.avail_out;
if(inflatedBytes == 0) {
unotice("\n Unable to decompress data - truncated");
break;
}
totalBytesIn += zstrm.total_in;
decompByteCounter += inflatedBytes;
memcpy(dstBuf + savedByteCntr, out, inflatedBytes);
savedByteCntr = decompByteCounter;
}
// Reset inflater for additional input
ret = inflateReset(&zstrm);
if(ret == Z_STREAM_ERROR){
uerror(" Error %d inflateReset (%s)", ret, decode_zlib_err(ret));
(void)inflateEnd(&zstrm);
return ret;
}
}
if(isLastBlk){
ret = inflateEnd(&zstrm);
if(ret < 0) {
uerror("Fail inflateEnd %d [%s] ", ret, decode_zlib_err(ret));
return (ret);
}
}
*outLen = decompByteCounter;
return 0;
}
Thanks in advance for the support.
Thanks,
Sathya.

You are making an error in your use of your inflateData() routine.
First off, using a static variable in this way is a horrible idea. If you call your inflateData() twice with isFirstBlk true without an intermediate call with isLastBlk true, then you will wipe out the reference to the first set of allocations, resulting in a memory leak.
To avoid this sort of error, you should keep track of whether zstrm is initialized or not, and reject any attempt to initialize an already initialized stream. Better still would be to not even have an isFirstBlk, and simply initialize zstrm on the first call and on any call that immediately follows a call with isLastBlk true.
So you are either doing the above, calling twice with isFirstBlk true, or failing to call with isLastBlk true.

Related

getting data from server in cycle

my task is get from server data of an file with HTTP protocol
but problem is that i dont know the size of the content so i iterate through read func to get data from socked but it iterates every time only once i dont know really why
int res, len, total, boolk = 0, p=0;
while ((res = read(client_socket,bufferOut,4095)) > 0)
{
bufferOut[res]= '\0';
if(p==0)
{
buffer = calloc(strlen(bufferOut)+1,sizeof(char));
}
else
{
buffer = realloc(buffer,strlen(buffer)*sizeof(char)+strlen(bufferOut)+1*sizeof(char));
}
strcat(buffer,bufferOut);
if(isEnough(bufferOut)!=0 && boolk == 0)
{
index = getIndex(buffer);
kk = getCode(buffer);
len = getLen(buffer);
boolk = 1;
}
if(strlen(bufferOut)>=len+index && boolk == 1)
{
break;
}
p++;
}
function isEnough only looks if full http header arrived getIndex get lenght of header and getLen get length of that file so i wanted to iterate until buffer is same lenght as header file which should be
You're working much too hard.
int
read_until_enough(int client_socket, char **buf_out, size_t *buflen_out)
{
char *rdbuf = xmalloc(INITIAL_BUFFER_SIZE);
size_t buflen = 0, bufalloc = INITIAL_BUFFER_SIZE;
for (;;) {
ssize_t n = recv(client_socket, rdbuf + buflen, bufalloc - buflen);
if (n <= 0) goto recv_failure;
if (is_enough(rdbuf, buflen)) break;
buflen += n;
if (buflen == bufalloc) {
bufalloc *= 2;
rdbuf = xrealloc(rdbuf, bufalloc);
}
}
*rdbuf_out = rdbuf;
*buflen_out = buflen;
return 0;
recv_failure:;
int save_errno = errno;
free(rdbuf);
errno = save_errno;
*rdbuf_out = 0;
*buflen_out = 0;
return -1;
}
Please note that is_enough now takes the size of the received data as an argument, caller gets both the received data and its size, and the buffer is NOT nul-terminated. HTTP is a binary-transparent protocol; you MUST NOTrfc2119 assume that you never receive nul bytes.
Please also note that is_enough is stateless and is expected to do all of the parsing. This is better separation of concerns. Worry about the performance cost of re-parsing the HTTP headers each time around the loop only after you have everything working.
Finally, the functions xmalloc and xrealloc are wrappers around malloc and realloc that either succeed or crash the program. I am using them here to avoid cluttering up the example with error-recovery logic for memory allocation. You will have to decide whether they are appropriate for whatever you're doing.

How correctly read/write from/to mtdblock into linux kernel space?

I am have code:
static unsigned char buffer[512];
static struct mtd_info *mtd_ptr = NULL;
static unsigned int *counter = NULL;
static void mtdblock_read(void)
{
int readed = 0;
int ret = 0;
const unsigned int mtd_device_num = 12;
counter = (unsigned int *)buffer;
mtd_ptr = get_mtd_device(NULL, mtd_device_num);
if(IS_ERR(mtd_ptr)){
printk("Can't get mtd partition...");
mtd_ptr = NULL;
return;
}
printk("Found partition '%s'\n", mtd_ptr->name);
if(mtd_ptr->read)
{
ret = mtd_ptr->read(mtd_ptr, 0, sizeof(buffer), &readed, buffer);
printk("%s:%d - %d, readed: %d\n", __func__, __LINE__, ret, readed);
}
else
printk("Not have 'read' ops\n");
printk("current counter = 0x%08X\n", *counter);
}
static void mtdblock_write(void)
{
int writed = 0;
int ret = 0;
(*counter) = 111;
printk("Write counter (%d) to mtd\n", *counter);
if(mtd_ptr && mtd_ptr->write)
{
ret = mtd_ptr->write(mtd_ptr, 0, sizeof(buffer), &writed, buffer);
printk("%s:%d - %d, writed: %d\n", __func__, __LINE__, ret, writed);
if(mtd_ptr->sync)
mtd_ptr->sync(mtd_ptr);
}
else
printk("Not have 'write' ops or mtd is not available\n");
}
void test()
{
mtdblock_read();
mtdblock_write();
mtdblock_read();
}
mtdblock_read must read 512 bytes from mtdblock and display int value placed into first 4 bytes of buffer.
mtdblock_write puts 4-byte value at start of 512-byte buffer and write it to mtdblock.
test() executes test sequence:
1st mtdblock_read() - for read current value from mtdblock.
mtdblock_write() - for write new value
2nd mtdblock_read() - for re-read writed value.
Problem in mtdblock_read (as my opinion) because I have trace output:
Found 13 partition 'dying_gasp'
mtdblock_read:303 - 0, readed: 512
current counter = 0x00000000
Write counter (1953719668) to mtd
mtdblock_write:322 - 0, writed: 512
Found 13 partition 'dying_gasp'
mtdblock_read:303 - 0, readed: 512
current counter = 0x00000000
From this I can see that mtd_ptr->read() have return value -74, but reports into readed that it have 512 bytes readed from mtdblock. But really it is not read data from mtdblock.
Additionally I am check mtd_ptr->write() but it correctly report 512 bytes writed and have zero return value.
Can you help me for solve this problem?
It is internal mtdblock driver error or I am skip major operations at read or write from/to mtdlock?
This is a little late for the person asking the question, but perhaps someone else can benefit.
Found out that you cannot read into a buffer declared static if your mtd device is backed by the SPI driver. There is a section of code in spi_map_buf() in spi.c that checks for this:
if (vmalloced_buf || kmap_buf) {
desc_len = min_t(int, max_seg_size, PAGE_SIZE);
sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len);
} else if (virt_addr_valid(buf)) {
desc_len = min_t(int, max_seg_size, ctlr->max_dma_len);
sgs = DIV_ROUND_UP(len, desc_len);
} else {
dev_err(&ctlr->dev,"Not vmalloced, not kmap, va not valid\n");
return -EINVAL;
}
So, if you go ahead and kmalloc the buffer, everything goes fine. Found this while trying to create a kernel mod that uses the MTD SPI SRAM on the i.MX6UL chip, and calling mtd_read directly.

Inconsistent malloc memory corruption

I'm currently writing a method that reads from an allocated block of memory and prints out its contents from a certain offset and up to a specified size, both of which are passed as parameters. I'm using char pointers to accomplish this, but keep getting a malloc error around line
char *content = (char *)malloc(size+1);
Code for the method:
int file_read(char *name, int offset, int size)
{
//First find file and its inode, if existing
int nodeNum = search_cur_dir(name);
if(nodeNum < 0) {
printf("File read error: file does not exist\n");
return -1;
}
//Size check, to avoid overflows/overreads
if(offset > inode[nodeNum].size || size > inode[nodeNum].size || (offset+size) > inode[nodeNum].size) {
printf("File read error: offset and/or size is too large\n");
return -1;
}
int i, read_size, track_size = size, content_offset = 0;
int target_block = offset / BLOCK_SIZE; //Defined as constant 512
int target_index = offset % BLOCK_SIZE;
char *raw_content = (char *)malloc(inode[nodeNum].size+1);
printf("check1\n"); //Debug statment
for(i = target_block; i < (inode[nodeNum].blockCount-(size/BLOCK_SIZE)); i++) {
disk_read(inode[nodeNum].directBlock[i], raw_content+content_offset);
content_offset += BLOCK_SIZE;
}
printf("check2\n"); //Debug statment
char *content = (char *)malloc(size+1);
memcpy(content, raw_content+target_index, size);
printf("%s\n", content);
free(raw_content);
free(content);
return 0;
}
and code for disk_read:
char disk[MAX_BLOCK][BLOCK_SIZE]; //Defined as 4096 and 512, respectively
int disk_read(int block, char *buf)
{
if(block < 0 || block >= MAX_BLOCK) {
printf("disk_read error\n");
return -1;
}
memcpy(buf, disk[block], BLOCK_SIZE);
return 0;
}
structure for node
typedef struct {
TYPE type;
int owner;
int group;
struct timeval lastAccess;
struct timeval created;
int size;
int blockCount;
int directBlock[10];
int indirectBlock;
char padding[24];
} Inode; // 128 byte
The error I get when using this method is one of memory corruption
*** glibc detected *** ./fs_sim: malloc(): memory corruption (fast): 0x00000000009f1030 ***
Now the strange part is, firstly this only occurs after I have used the method a few times - for the first two or three attempts it will work and then the error occurs. For instance, here is an example test run:
% read new 0 5
z12qY
% read new 0 4
z12q
% read new 0 3
*** glibc detected *** ./fs_sim: malloc(): memory corruption (fast): 0x00000000009f1030 ***
Even stranger still, this error disappears completely when I comment out
free(raw_content);
free(content);
Even through this would tie up the memory. I've read through previous posts regarding malloc memory corruption and understand this usually results from overwriting memory bounds or under allocating space, but I can't see where I could be doing this. I've attempted other sizes for malloc as well and these produced the best results when I commented out the lines freeing both pointers. Does anyone see what I could be missing? And why does this occur so inconsistently?
Code allocates space for characters and a null character, but does not insure the array is terminated with a null character before printing as a string.
char *content = (char *)malloc(size+1);
memcpy(content, raw_content+target_index, size);
// add
content[size] = '\0';
printf("%s\n", content);
Likely other issues too.
[Edit]
OP code is prone to mis-coding and dependent on inode[] to have coherent values (.blockCount . size). Clarify and simplify by determining the loop count and allocating per that count.
int loop_count = (inode[nodeNum].blockCount-(size/BLOCK_SIZE)) - target_block;
char *raw_content = malloc(sizeof *raw_content * loop_count * BLOCK_SIZE);
assert(raw_count);
for (loop = 0; loop < loop_count; loop++) {
i = target_block + loop;
disk_read(inode[nodeNum].directBlock[i], raw_content + content_offset);
content_offset += BLOCK_SIZE;
}
Also recommend checking the success of disk_read()

glibc corrupted double linked list error while running a C code on 64 bit machine

I have a large C code that works fine on 32 bit machine but fails on 64 bit machines with
*** glibc detected *** ./XXX.exe: corrupted double-linked list: error.
I have run Valgrind and have used print statements to exactly pinpoint where the error is coming from but am clueless about the fix.
The actual code is very big but I am giving the relevant portions here. Hoping someone can help me troubleshoot it.
The actual error is coming from the Buf_Close() module where it tries to free Buf_elm_p p as if (p != NULL) free(p);
These are functions that the main code calls and I am only giving this here as the error is somewhere here. The calling sequence from the main code is:
1. Buf_Init
2. Buf_New_p
3. Buf_Close
Buf_bf_p
Buf_Init( size_t elm_size,
int nelm_buf,
long nbuf )
/*******************************************************************************
!C
!Description: Buf_Init (buffer initialize) initializes buffer data structures
and buffers.
!Input Parameters:
elm_size element size (bytes)
nelm_buf number of elements per buffer
nbuf number of buffers
!Output Parameters:
(returns) pointer to the buffer data structure
or NULL for an error return
*****************************************************************************/
{
Buf_bf_p bf;
long buf_size;
long ibuf;
/* Calculate buffer size and check */
buf_size = ((long) elm_size) * nelm_buf;
/*Allocate the buffer data structure */
if ((bf = (Buf_bf_p) malloc(sizeof(Buf_bf_t))) == NULL)
{Buf_Error(&BUF_NOMEMORY, "Init"); return NULL;}
bf->key = BUF_KEY;
bf->elm_size = elm_size;
bf->nelm_buf = nelm_buf;
bf->nbuf = nbuf;
bf->buf_size = buf_size;
bf->fp = NULL;
bf->access = NO_FILE;
bf->nbuf_alloc = 1;
bf->ibuf_end = 0;
bf->ibuf_newest = 0;
bf->ibuf_oldest = 0;
bf->nelm = 0;
/* Allocate the buffer status data structure */
bf->nbstat = max(NBSTAT_START, bf->nbuf + 1);
if ((bf->bstat = (Buf_bstat_t *)
malloc(bf->nbstat * sizeof(Buf_bstat_t))) == NULL)
{Buf_Error(&BUF_NOMEMORY, "Init"); return NULL;}
/* Allocate the first buffer */
bf->bstat[0].loc = MEM_ONLY;
if( (bf->bstat[0].buf_p = (Buf_elm_p) malloc(bf->buf_size)) == NULL)
{ Buf_Error(&BUF_NOMEMORY, "Init");
return NULL;
}
else
{
/* initialize */
memset( bf->bstat[0].buf_p, '\0', bf->buf_size );
}
bf->bstat[0].newer = -1;
bf->bstat[0].older = -1;
/* Initialize the rest of the buffer status array */
printf("bf->nbstat %d\n", bf->nbstat);
for (ibuf = 1; ibuf < bf->nbstat; ibuf++) {
bf->bstat[ibuf].loc = NOT_ALLOC;
bf->bstat[ibuf].buf_p = NULL;
bf->bstat[ibuf].newer = -1;
bf->bstat[ibuf].older = -1;
bf->bstat[ibuf].initialized = 1;
}
return bf;
}
Buf_elm_p
Buf_New_p( Buf_bf_p bf,
long *ielm )
/*******************************************************************************
!C
!Description: Buf_New_p (new buffer element pointer) returns a memory
location and element number of a new element; elements are number
sequentially as they are allocated.
!Input Parameters:
bf pointer to the buffer data structure
!Output Parameters:
ielm new element number
(returns) pointer to memory location of new element
or NULL for error
!Notes:
1. 'Buf_Init' must be called before this routine to initialize
the buffer data structure.
2. If there is no more space in memory and disk write access is allowed,
the oldest buffer is written to disk and the memory is re-used.
3. If the file is opened with 'read only' access this routine will return
an error.
!END
******************************************************************************/
{
long ibuf, jelm, jbuf, kbuf;
long nbuf_cmplt;
Buf_elm_p p;
long dsk_loc, eof_loc;
/* New element number/location */
*ielm = bf->nelm++;
ibuf = *ielm / bf->nelm_buf;
jelm = *ielm % bf->nelm_buf;
/* Are we at the past the end of the last buffer? */
if (ibuf > bf->ibuf_end) {
if (ibuf != (bf->ibuf_end + 1))
{Buf_Error(&BUF_BADBUF, "New_p"); return NULL;}
/* Re-allocate buffer status data structure if not large enough */
if( ibuf >= bf->nbstat )
{
bf->nbstat += min(bf->nbstat, MAX_NEW_NBSTAT);
if( (bf->bstat = realloc(bf->bstat, bf->nbstat * sizeof(Buf_bstat_t)))
== NULL)
{ Buf_Error(&BUF_NOMEMORY, "New_p");
return NULL;
}
}
if (bf->nbuf_alloc < bf->nbuf || bf->access == NO_FILE) {
/* Allocate a new buffer */
if( (p = (Buf_elm_p) malloc(bf->buf_size)) == NULL)
{ Buf_Error(&BUF_NOMEMORY, "New_p");
return NULL;
}
else
{
/* initialize */
memset( p, '\0', bf->buf_size );
}
bf->nbuf_alloc++;
if (bf->nbuf < bf->nbuf_alloc) bf->nbuf = bf->nbuf_alloc;
} else {
/* Re-use an existing buffer */
/* Get the oldest buffer */
jbuf = bf->ibuf_oldest;
/* Delete oldest buffer from old/new pointer list */
p = bf->bstat[jbuf].buf_p;
bf->ibuf_oldest = bf->bstat[jbuf].newer;
bf->bstat[bf->ibuf_oldest].older = -1;
bf->bstat[jbuf].buf_p = NULL;
bf->bstat[jbuf].older = -1;
bf->bstat[jbuf].newer = -1;
bf->bstat[jbuf].initialized = 1;
}
/* Put current buffer in old/new pointer list */
bf->bstat[ibuf].loc = MEM_ONLY;
bf->bstat[ibuf].buf_p = p;
bf->bstat[ibuf].older = bf->ibuf_newest;
bf->bstat[ibuf].newer = -1;
bf->bstat[ibuf].initialized = 1;
bf->ibuf_end = ibuf;
bf->bstat[bf->ibuf_newest].newer = ibuf;
bf->ibuf_newest = ibuf;
}
/* Calculate pointer to memory location of element */
p = (unsigned char *) bf->bstat[ibuf].buf_p + (jelm * bf->elm_size);
return p;
}
int
Buf_Close( Buf_bf_p bf )
/*******************************************************************************
!C
!Description: Buf_Close (buffer cache file close) writes the remainder of the
cache to the disk cache file and closes the file and frees memory of the
buffer data structure and buffers.
!Input Parameters:
bf pointer to the buffer data structure
Notes:
1. 'Buf_Create' or 'Buf_Open' must be called before this routine to open
the file.
!END
*****************************************************************************/
{
int i;
long dsk_loc;
logical_t cmplt_flag;
/* int b; */
Buf_elm_p p;
long ibuf, nelm_wrt;
int nb;
unsigned char header[HEADER_SIZE];
/* Write remaining buffers which are still only in memory */
for (ibuf = 0; ibuf < (bf->ibuf_end + 1); ibuf++)
/* for (ibuf = 0; ibuf < (bf->ibuf_end); ibuf++)*/{
p = bf->bstat[ibuf].buf_p;
/* Free the buffer memory */
**THIS FOLLOWING LINE IS WHERE THE ERROR IS COMING FROM**
**VALGRIND SHOWS `Conditional jump or move depends on uninitialised value(s)` ERROR**
**BUT AM NOT SURE HOW `p` is coming out to be uninitialized`**
if (p != NULL) free(p);
}
/* Free the buffer status memory */
free(bf->bstat);
/* Free the buffer cache data structure */
bf->fp = (FILE *)NULL;
bf->key = 0;
free(bf);
printf("buf here 5\n");
return BUF_NORMAL;
}
I work on a project that has a lot of questionable practices (currently working toward cleaning them up). I ran into this error and went through everything I could imagine to ferret out where the problem was including clang sanitizers, a variety of valgrind tools, and a variety of other tricks.
The problem: exit() was being called in one thread about the same time as main() returned, so all the global/static constructors were being kicked off in two separate threads simultaneously. I'm actually kind of annoyed I didn't make the connection sooner.
This error also manifests as:
double free or corruption
... which may also be caused by another problem
segfault/sig11 inside exit()
Crashes inside malloc_consolidate with a call stack that looks like:
I guess you can't add code examples after a bullet item
#0 0xabcdabcd in malloc_consolidate () from /lib/libc.so.6
#1 0xabcdabcd in _int_free () from /lib/libc.so.6
#2 0xabcdabcd in operator delete (...)
#3 0xabcdabcd in operator delete[] (...)
(...)
Furthermore, I couldn't get it to exhibit this problem while running under valgrind -- whether it was a timing issue, or some artifact of how valgrind works that hid the problem I may never know.
It bit difficult to understand your program logic by static analysis. However Valgrind print "Conditional jump or move depends on uninitialized value" under the scenario
where program attempts to make use of uninitialized data in a way that might affect your program's externally-visible behaviour.
Sources of uninitialised data tend to be:
Local variables in procedures which have not been initialized.
The contents of heap blocks (allocated with malloc, new, or a similar function) before you (or a constructor) write something there.
To see information on the sources of uninitialised data in your program, you may use
the option --track-origins=yes. So You can run the program(./a.out) as follows:
valgrind --tool=memcheck --track-origins=yes ./a.out
This might be helpful and provide more useful information closer to your actual source of your problem.You can find more detailed information about it from the location:
http://valgrind.org/docs/manual/mc-manual.html

Determining amount of bytes read with recv

I am having an issue with recv. I wrote a function that fills a structure with data, and the length (in bytes) of that data which is read from a socket.
For testing I am just printing the data to stdout byte by byte based on the total amount of bytes read by recv. For some reason the number of bytes being read seems to be correct sometimes and incorrect other times depending on what site I am querying. For example the following code works as intended on some sites:
data->data_sz = 0;
while((i = recv(sock, data->data + data->data_sz, CHUNKSIZE, 0)) > 0)
{
data->data_sz += i;
if(databff - data->data_sz < CHUNKSIZE)
{
databff *= 2;
if(!(tmp = realloc(data->data, databff)))
{
free(data->data);
(void) WSACleanup();
return 0;
}
data->data = tmp;
}
}
i = strsbstr(data->data, "\r\n\r\n") + 4; //i = the position of the first char after header info
if(i >= 0)
{
data->data_sz = data->data_sz - i; //data->data_sz = number of bytes without header info
memmove(data->data, data->data + i, data->data_sz);
if(!(tmp = realloc(data->data, data->data_sz)))
{
free(data->data);
(void)WSACleanup();
return 0;
}
data->data = tmp;
}
else
{
free(data->data);
(void) WSACleanup();
return 0;
}
return 1;
}
To print the data to stdout I just use a for loop:
//t_html->data_sz points to my data->data_sz structure
//t_html->data points to my data->data structure
for(i = 0; i <= t_html->data_sz; i++) (void)fputc((int)t_html->data[i], stdout);
The above code works for some sites but fails on others (for example when querying http://www.google.com I expect the final characters to be </html> but I get </html>l).
Basically my problem is that data->data_sz (the amount of bytes received) is not being calculated correctly, which makes it impossible to correctly use gathered data. I am really at a loss of what to do right now.
EDIT:
here is the strsbstr function which is called in the above code:
int strsbstr(const char *str, const char *sbstr)
{
char *sbstrlc;
if(!(strcmp(str, sbstr))) return 0;
if(!(sbstrlc = strstr(str, sbstr))) return -1;
return (int) (sbstrlc - str);
}
recv(sock, data->data + data->data_sz, CHUNKSIZE, 0) is potentially a problem. Why? Because you may not have CHUNKSIZE room left in your buffer. You have databff - data->data_sz left, actually (assuming data is allocated to a size of databff). It all depends on the initial values of databff and CHUNKSIZE, which I can't see and figure I'd point this out just in case.
Data is not guaranteed to be NULL-character terminated. Your printing loop says i <= t_html->data_sz; which is wrong. It should be i < t_html->data_sz;. If you use <=, you're accessing one past your buffer, which is likely why you get a weird character sometimes, and sometimes not.

Resources