|
|
View previous topic :: View next topic |
Author |
Message |
ye
Joined: 11 May 2005 Posts: 57 Location: london
|
Array overflow? How can it happen? |
Posted: Thu Oct 27, 2005 5:15 am |
|
|
Hi all,
When I was coding my system, I found a pretty strange thing happened. An array initialized as length 5 extended to a length of 10 after some tricks. This was definitely overflow but I couldn't see how it happend and how to avoid it.
Now I put down a similar code that describes the circumstance:
Code: | char test[5]="abcd";
char test2[10];
int i;
for(i=0;test[i]!='\0';i++) // Copy the content of test[] to test2[]
test2[i] = test[i];
for(i=4;i<10;i++) // Fill the rest of test2[] with character 'g'
test2[i] = 'g';
test2[i] = '\0'; // Finish test2[] by ending with NUL CHARACTER
for(i=0;test2[i] != '\0';i++) // Copy the content of test2[] back to test[]
test[i] = test2[i];
test[i] = '\0'; // Finish test[] by ending with NUL CHARACTER
// Print the final content of test[] on to Hyperterminal and it's 'abcdggggg'!!!
// The length's become 10
fprintf(COM_B,"\nThe test string = %s\n", test);
|
By which process has test[] been extended?
This is definitely overflow but I've looked at the SYMBOL file and none of the adjacent variables to test[] have been affected by the overflow.
Please help! |
|
|
Foppie
Joined: 16 Sep 2005 Posts: 138 Location: The Netherlands
|
|
Posted: Thu Oct 27, 2005 5:38 am |
|
|
I think this code is the problem:
Code: | for(i=0;test2[i] != '\0';i++) // Copy the content of test2[] back to test[]
test[i] = test2[i]; |
You copy all 10 characters of test2 to test. So I think the compiler will enlarge test to let it fit the 10 characters.
I am not experienced with this so I could be wrong...
Jos |
|
|
ye
Joined: 11 May 2005 Posts: 57 Location: london
|
|
Posted: Thu Oct 27, 2005 6:09 am |
|
|
Thanks for replying.
I am pretty sure it's that statement that causes trouble.
However, I would rather the compiler report an error message than ignore this overflow.
Or can there be other causes? |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Oct 27, 2005 6:21 am |
|
|
Code: |
char test[5]="abcd";
char test2[10];
int i;
for(i=0;i<sizeof(test);i++) // Copy the content of test[] to test2[]
{
if (test[i] == 0)
break;
test2[i] = test[i];
}
for(;i<sizeof(test2)-1;i++) // Fill the rest of test2[] with character 'g'
test2[i] = 'g';
test2[i] = '\0'; // Finish test2[] by ending with NUL CHARACTER
/* The next statement can't be done since the size of test is less than the size of test2
for(i=0;test2[i] != '\0';i++) // Copy the content of test2[] back to test[]
test[i] = test2[i];
test[i] = '\0'; // Finish test[] by ending with NUL CHARACTER
*/
// Print the final content of test[] on to Hyperterminal and it's 'abcdggggg'!!!
// The length's become 10
fprintf(COM_B,"\nThe test string = %s\n", test);
|
The error is not a compiler bug but rather lack of experience in programming. The compiler should give an error or warning if you did something like:
since it knows that it is outside the bounds of the array. However,
will not give an error and you shouldn't expect it to. |
|
|
neil
Joined: 08 Sep 2003 Posts: 128
|
|
Posted: Thu Oct 27, 2005 6:27 am |
|
|
Is this code just an experiment? If not, why not use 'strcpy()' in <string.h> to copy one string to another? |
|
|
ye
Joined: 11 May 2005 Posts: 57 Location: london
|
|
Posted: Thu Oct 27, 2005 7:03 am |
|
|
Mark wrote: | Code: |
char test[5]="abcd";
char test2[10];
int i;
for(i=0;i<sizeof(test);i++) // Copy the content of test[] to test2[]
{
if (test[i] == 0)
break;
test2[i] = test[i];
}
for(;i<sizeof(test2)-1;i++) // Fill the rest of test2[] with character 'g'
test2[i] = 'g';
test2[i] = '\0'; // Finish test2[] by ending with NUL CHARACTER
/* The next statement can't be done since the size of test is less than the size of test2
for(i=0;test2[i] != '\0';i++) // Copy the content of test2[] back to test[]
test[i] = test2[i];
test[i] = '\0'; // Finish test[] by ending with NUL CHARACTER
*/
// Print the final content of test[] on to Hyperterminal and it's 'abcdggggg'!!!
// The length's become 10
fprintf(COM_B,"\nThe test string = %s\n", test);
|
The error is not a compiler bug but rather lack of experience in programming. The compiler should give an error or warning if you did something like:
since it knows that it is outside the bounds of the array. However,
will not give an error and you shouldn't expect it to. |
Yes, this is an experiment.
Mark, thanks for the reply. Yes, I am rather lack of experience in programming so I am still a bit confused.
Quote: | /* The next statement can't be done since the size of test is less than the size of test2
for(i=0;test2[i] != '\0';i++) // Copy the content of test2[] back to test[]
test[i] = test2[i];
test[i] = '\0'; // Finish test[] by ending with NUL CHARACTER
*/ |
1.
Certainly I can't do the statement above here, but this is just an simple model. In the real code, there's no way to foresee whethere the final length of test2[] is bigger than that of test[]. Therefore, I won't get rid of this statement in my code but find some way around it.
2.
Quote: | Code:
i=34;
test[i] = 0;
will not give an error and you shouldn't expect it to. |
I don't know why you think it normal and acceptable for the complier not to give an error on this issue but from my point of view, the complier is certainly not clever enough. But I will accept this fact here.
Now I am talking about the array as a string. Then do you not think it strange that when the code tries to poise '\0' to the end of test[] the compiler fails to realize the index for '\0' is beyond the allowed range??? |
|
|
d00dajo
Joined: 20 Jul 2004 Posts: 34
|
Windows programming vs Microcontrollers. |
Posted: Thu Oct 27, 2005 7:32 am |
|
|
Quote: |
I don't know why you think it normal and acceptable for the complier not to give an error on this issue but from my point of view, the complier is certainly not clever enough. But I will accept this fact here.
Now I am talking about the array as a string. Then do you not think it strange that when the code tries to poise '\0' to the end of test[] the compiler fails to realize the index for '\0' is beyond the allowed range??? |
You are thinking in a "Windows programmer fashion". In applications on PCs, the memory used - allocated - for a programs variable can be dynamic. That is, the space needed is allocated automatically. This is done automatically in the background by the Operating System.
In a microcontroller you normally dont have a OS in the base (because of the limitations). The rammemory in itself is a linear memoryspace, 0x0000 - 0x????.There is no such thing as a "string" in the memory. A string is mearely a datatype that we normally interpret in a certain way. the '\0' (end of string) is a character saved in the last memory location, which YOUR PROGRAM interprets as "end of string".
The compiler can only make a STATIC assignment of the memory, not dynamically, since it is not running on the uC. (Windows is actually running on the PC so it can determine in run-time the actual size needed for the string. Normally even windowsprogramming requires the programmer to set up the compiler for generating code that requests automatic resizing of strings.)
However, if you write an mini-OS that allocates memory-space dynamically you can "extend" the string. This is with EXTREMELY high probability NOT something you want to do.
Best Regards,
Daniel Johansson,
Sr. Application Engineer, EmpirBus AB |
|
|
ye
Joined: 11 May 2005 Posts: 57 Location: london
|
|
Posted: Thu Oct 27, 2005 8:46 am |
|
|
Hi, Daniel, thanks!
So do you mean, when copying test2[] to test[] which is shorter than test2[], the compiler simply lines up the elements of test2[] in a static way at the address of test[] without realizing the initialised length of test[].
This is actually overflow, innit? But why didn't I see the adjacent variables of test[] got corrupted due to overflow?
Please note that in my real code test[] and the adjacent variables from the SYMBOL file are all global variables.
Best Regards |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Oct 27, 2005 9:03 am |
|
|
Quote: | I don't know why you think it normal and acceptable for the complier not to give an error on this issue | Cause I am experienced
You as a programmer are responsible for checking the bounds.
Code: |
for(i=0;i<sizeof(test)-1;i++) // Copy the content of test2[] back to test[]
{
if (test2[i] == 0)
break;
test[i] = test2[i];
}
test[i] = '\0'; // Finish test[] by ending with NUL CHARACTER
|
Quote: | So do you mean, when copying test2[] to test[] which is shorter than test2[], the compiler simply lines up the elements of test2[] in a static way at the address of test[] without realizing the initialised length of test[].
|
The compiler does what you tell it to do. So yeah, it keeps on writing and trashes the contents of the variable adjacent to test.
Quote: | This is actually overflow | Yep, but there is nothing checking for the overflow. It is up to you to do that. |
|
|
Ttelmah Guest
|
|
Posted: Thu Oct 27, 2005 9:14 am |
|
|
The 'killer' bt of the code, starts here:
Code: |
for(i=4;i<10;i++) // Fill the rest of test2[] with character 'g'
test2[i] = 'g';
test2[i] = '\0'; // Finish test2[] by ending with NUL CHARACTER
|
'i', will be _10_ when the loop finishes. So the null gets written into address '11'. The string is then oversized, and may indeed never be terminated (if for instance 'i' is in this address, then it'll not be zero on the next test).
Protection of such accesses is a multi stage process. In a PC, not only is memory dynamically allocated from a 'virtual' pool, but there is hardware, which will give an error if you try to access outside the bounds of an allocated area. You can code to do this yourself (for instance):
Code: |
int1 mem_error;
int read_array(int * ptr,int addr,int lim) {
if (addr<lim) then {
error=false;
return (*(ptr + addr));
}
error=true;
return(0);
}
|
If then on the locations where you read from the array, you call this function instead, with the address of the array, the number of the element you want to read, and the number of elements in the arra, you will get back the character in the array, or the 'mem_error' bit will get set if you try to access outside it's size. Now with some careful use of 'sizeof', ad a similar function for the 'write' operations, you could implement basic memory protection. The 'downside', is how much more work is involved. Generally PIC code is built to be small, and for the size of processor involved fairly 'nimble', and this sort of overhead is not really acceptable, so instead it becomes a case of ensuring that where such things might happen, you trap them yourself...
Best Wishes |
|
|
d00dajo
Joined: 20 Jul 2004 Posts: 34
|
|
Posted: Thu Oct 27, 2005 9:18 am |
|
|
ye wrote: | Hi, Daniel, thanks!
So do you mean, when copying test2[] to test[] which is shorter than test2[], the compiler simply lines up the elements of test2[] in a static way at the address of test[] without realizing the initialised length of test[].
This is actually overflow, innit? But why didn't I see the adjacent variables of test[] got corrupted due to overflow?
Please note that in my real code test[] and the adjacent variables from the SYMBOL file are all global variables.
Best Regards |
Yes! The program will just copy byte for byte into the ram area starting at position 0 of test.
Yes, it is overflow in the sense that you are overwriting other variables that you didnt intend to. The compiler has no idea that you think of the char[5] type as a string. You have declared an array of characters of size 5, nothing more nothing less.
The variables at position char[4]+1 will be overwritten. I GUARANTEE IT! That you didnt see it might be that you DONT have a variable at memory location char[5]+1, I would need to see the symbol list. Maybe you "rewrite" your variables in the rest of your code or something, but they are certainly overwritten!
//Daniel |
|
|
Guest
|
|
Posted: Thu Oct 27, 2005 10:26 am |
|
|
Many thanks for all of you spam!
I am pretty clear now! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|