Hi,
I have been going over the 'tinywebserver' source making it compliant to 1.0 and making it significantly more robust,
During a 'cold boot' the TWS sometimes hangs after sending the first page (nope , its not the ethernet bug)
The code appears to be hanging in malloc() !!
first a 'good result' printed via various debug statments
New request: GET /jquery.js HTTP/1.1
entering get_field:Buffer=GET /jquery.js HTTP/1.1
,Size=24,Which=0
Identify start of field
Identify end of field
extract field: i=0j=3
returned from malloc_check
returned from memcopy
return from get_field:GET
the bad result
New request: GET /jquery.js HTTP/1.1
entering get_field:Buffer=GET /jquery.js HTTP/1.1
,Size=24,Which=0
Identify start of field
Identify end of field
extract field: i=0j=3
we can see that the ardunio hangs 'dead'
now the code
void *malloc_check(size_t size) {
void* r = malloc(size);
if (!r) {
Serial << F("No space for malloc: " ); Serial.println(size, DEC);
}
return r;
}
and the calling routine
<Snip>
Serial << F("extract field: i=")<<i<<"j="<<j<<("\n");
field = (char*) malloc_check(j - i + 1);
Serial << F("returned from malloc_check\n");
int p = 0;
memcpy(field, buffer + i, j - i);
Serial << F("returned from memcopy\n");
field[j - i] = 0;
}
Serial << F("return from get_field:")<<field<<("\n");
return field;
}
The hang is between "extract field: i=0j=3" and the return from the memory allocation, we are not appearing to run out of memory because no error is printed plus there is over 6k of memory 'free' at this point.
I cannot see why it should hang in the memory allocation, and cannot seem to find a way to debug it further.
Serial << F("extract field: i=")<<i<<"j="<<j<<("\n");
field = (char*) malloc_check(j - i + 1); // Malloc return NULL when it failed allocate the memory
Serial << F("returned from malloc_check\n");
int p = 0;
//if(field!=NULL) //<---------------------------------PUT this condition here
memcpy(field, buffer + i, j - i); //<-----------------Problem is here
// <----------------There is a chance to copy the data to location NULL is equivalent if 0x0000 of SRAM
Serial << F("returned from memcopy\n");
field[j - i] = 0;
}
Serial << F("return from get_field:")<<field<<("\n");
return field;
}
------------Your output--------------------------------------------
New request: GET /jquery.js HTTP/1.1
entering get_field:Buffer=GET /jquery.js HTTP/1.1
,Size=24,Which=0
Identify start of field
Identify end of field
extract field: i=0j=3
Is this happening in first time calling to malloc function.
Malloc not only returns the address but also returns the Address of next free block, size of returned block,
------------Your output--------------------------------------------
New request: GET /jquery.js HTTP/1.1
entering get_field:Buffer=GET /jquery.js HTTP/1.1
,Size=24,Which=0
Identify start of field
Identify end of field
extract field: i=0j=3
Is this happening in first time calling to malloc function.
Malloc not only returns the address but also returns the Address of next free block, size of returned block,
//Modify your malloc_check function
//Add parameter funcName for tracking the caller:
void *malloc_check(size_t size,char funcName) { //<----------------Add funcName for debug purpose
void r = testMalloc(size); //<---------------Modify here
if (!r) {
Serial << F("No space for malloc: " ); Serial.println(size, DEC);
}
Serial.println(funcName); //<----------------Add This line for debug purpose
return r;
}
void *testMalloc(size_t size)
{
void *tmp;
unsigned int addr;
unsigned int *sizePtr;
tmp=malloc(size);
if(tmp!=NULL)
{
Track Addr: 0x226 the allocated adreess it must be increase when malloc failled to allocate memory
if your SRAM size is 6K then address should not be larger than ~ 0x1800
hardcore:
Yep I'm well aware that the code has the potential to return a 'null' if the allocation fails, BUT if it is failing THEN it should be printing
"No space for malloc:" ,
You said you are running this on version 1.0. The hardware serial version that comes with that just puts stuff in a buffer, and then an interrupt pulls it out and prints it, byte by byte.
So if you print something, and crash immediately afterwards, no you won't see the print.
New request: GET /style.css HTTP/1.1
entering get_field:Buffer=GET /style.css HTTP/1.1
,Size=24,Which=0
Identify start of field
Identify end of field
extract field: i=0j=3
Free RAM: 6039
and the malloc(), where I now print the free ram BEFORE I run the allocation
void *malloc_check(size_t size) {
Serial << F("Free RAM: ") << FreeRam() << "\n";
void* r = malloc(size);
if (!r) {
Serial << F("No space for malloc: " ); Serial.println(size, DEC);
}
return r;
}
So it would appear that the problem is inside of Malloc() and since there are hundreds of thousands of Megas out there that do not seem to have problems with memory allocation, it must be something specific about mine.
Use the code posted by pravas to check allocation.
Disable interrupts during the allocation, just incase there is some sort of funky interaction, that has been introduced by the 1.0 libraries
Run a continual memory test, just incase some bad ram is messing the malloc pointers.
Put the exit(1) in after the allocation fails, just to be sure.
My guess is you are corrupting memory. "Bad RAM" is a bit fanciful. If you corrupt memory then when malloc "walks" the pointer tree to find a block of the correct size it goes into a loop.
There are lots of ways of corrupting memory, doing something simple like this will do it:
It occurs after the 'powerup' initial startup of the platform, I should have done this at the start , instead of messing about.
Good run
Setting up the Ethernet card...
Web server starting...
Ready to accept HTTP requests.
New request: GET / HTTP/1.1
Debug Malloc:Addr: 0xA1A Size allocated: 4 Size Requested: 4
Debug Malloc:Addr: 0xA20 Size allocated: 2 Size Requested: 2
Host: 192.168.5.177
<snip>
Bad run
Setting up the Ethernet card...
Web server starting...
Ready to accept HTTP requests.
New request: GET / HTTP/1.1
Debug Malloc:Addr: 0xA1A Size allocated: 4 Size Requested: 4
Debug Malloc:Addr: 0xA20 Size allocated: 2 Size Requested: 2
Debug Free:Addr: 0x9666 Size deallocate: 65278
Host: 192.168.5.177
<snip>
It appears I have suddenly *found 64k of free ram, which would put the new allocation pointer outside of ram, This is the problem with using other peoples libraries. Just need to find out why it only does this sometimes.............
Yep you are correct, i'd been careful to check the code, that's why I had initially focused on string lengths and positions.
The "bad ram" Is something I have seen before in a manufacturing environment, it's not as rare as it should be, especially with China made boards.
It appears there is an errant call to Free() in the library code, that is due to a logic error in the Tinywebserver library.
The free() uses a pointer that is initialized (but the location the pointer points to is not, the table is built later ).
On a warm start the location contains the value from the previous run of the code (null), when the "reset" button is pressed.
But on a cold start (powerup) the location contains random data, since that is how the ram comes up.
So when the routine gets called, sometimes it tries to free NULL and other times it tries to free (0xFFFF), without allocating anything.