|
|
View previous topic :: View next topic |
Author |
Message |
allenhuffman
Joined: 17 Jun 2019 Posts: 562 Location: Des Moines, Iowa, USA
|
5.092 extern MyStruct foo[]; miscalculates size, corruption. |
Posted: Wed Jan 22, 2020 1:01 pm |
|
|
EDIT to add this summary:
---
If you have an array of items, such as a custom structure, if the compiler sees an extern like "extern MyStruct foo[];" without the size, it will miscalculate offsets when you reference it as foo[1], foo[3], etc. Instead of calculating reach one as the sizeof(MyStruct) it uses the entire array size, and ends up pointing past that data and updating those values corrupts that memory. The workaround is to make sure the extern specifies the size, but if the memory is dynamic like "structPtr = calloc(10, sizeof(MyStruct));" that cannot be done, but I think the compiler may generate different code in the case of using a pointer declaration like "MyStruct *data;" versus "MyStruct data[];" but I did not test that.
CCS has a ticket number about this, and I will update with the results if they have an update or workaround.
---
Another interesting observation that chewed up a few hours of our time today until we tracked it down...
An array (I'll use an array of characters, for simplicity, but our case was an array of a structure) can be defined and works fine if in the same file:
Code: | char buffer[10];
main()
{
printf ("sizeof(buffer) = %d\n", sizeof(buffer));
while (1);
} |
You would use "extern char buffer[10];" to get access to that in another file. This works fine.
We discovered that if you have something like this in the same file:
Code: | char buffer[10];
extern char buffer[10]; |
...it fails to build, as it should.
But, when the extern lives in a header file, the behavior changes:
Code: |
#include "header.h"
char buffer[10];
main()
{
printf ("sizeof(buffer) = %d\n", sizeof(buffer));
while (1);
} |
If inside header.h you had:
Code: | extern char buffer[11]; |
That will complain. It's a different size. But if you had:
Code: | extern char buffer[]; |
...that silently compiles, and anything using that and trying to get the sizeof() will get 1, though in the file that can see the declaration it will be 10 (for this stupid simple example).
This created our problem where we had a structure array declared globally in main.c, but it wasn't using it -- it was using the incorrect extern from a header file, without notice or warning.
The code parser changes behavior when it's in an include file.
Just an FYI. As always, "write correct code and results will be better." _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Last edited by allenhuffman on Thu Jan 30, 2020 3:08 pm; edited 2 times in total |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 562 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Jan 22, 2020 1:56 pm |
|
|
We passed this along to CCS. Here's a sample that shows the different behavior based on if it sees extern or not. If it can't, it should still be able to get the address if array elements just fine since it knows the size of the structure, but it uses the entire size instead (in our case, 16 bytes apart but it goes 160 --- 10 of those 16 bytes) for each index. Oops!
main.c
Code: | #include <main.h>
#include "structure.h" // Get the 16-byte structure.
TestStruct foo[10]; // 10 of them, 160 bytes total.
void main()
{
printf ("sizeof(TestStruct) = %d\r\n", sizeof(TestStruct));
// Each one of these should be 16 bytes apart.
for (int idx = 0; idx<10; idx++)
{
printf ("&foo[%d] = 0x%x\r\n", idx, (unsigned int)&foo[idx]);
}
while(TRUE)
{
//TODO: User Code
}
}
// End of main.c |
main.h
Code: | #include <24FJ256GA106.h>
#device ICSP=1
#use delay(crystal=8MHz,clock=32MHz)
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
#use rs232(ICD)
// End of main.h |
structure.h
Code: | #ifndef STRUCTURE_H_INCLUDED
#define STRUCTURE_H_INCLUDED
#include <stdint.h>
typedef struct
{
uint32_t a,b,c,d;
} TestStruct;
extern TestStruct foo[];
#endif // STRUCTURE_H_INCLUDED
// End of structure.h
|
In structure.h, comment out the extern and it works like it should. With that there, the index is miscalculated. Works fine in other compilers I tested with so just a simple bug - using the wrong value somewhere. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 562 Location: Des Moines, Iowa, USA
|
|
Posted: Thu Jan 30, 2020 2:01 pm |
|
|
CCS sent me a DLL to test, and it seems to resolve this issue and also fix the other one I posted about. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 562 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Feb 12, 2020 9:49 am |
|
|
CCS expects this issue to be resolved in the next release of the compiler. Hopefully it also addresses some other memory corruption issues that may be related to structures and arrays. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 562 Location: Des Moines, Iowa, USA
|
|
Posted: Mon Feb 24, 2020 11:49 am |
|
|
5.093 has been released. It does not fix this issue.
Quote: | 5.093 Corrected a problem with extern arrays when one of the array sizes is [] |
The address of each element of the array now get reported correctly, but elements after [0] are stored past the array, corrupting whatever is there.
I had a globals.c that declared two items -- an array of ten 16-byte structures, and a buffer directly after it:
Code: | TestStruct foo[FOO_MAX];
char buffer[BUF_MAX]; |
In a header file, I extern the structure like this:
Code: | // This will corrupt bytes in the "buffer".
extern TestStruct foo[];
// This will work:
//extern TestStruct foo[FOO_MAX]; |
Inside main, I clear the buffer to 0xAA's and then fill elements of the foo structure:
Code: | for (int idx=0; idx<FOO_MAX; idx++)
{
printf ("foo[%d].a = %d;\r\n", idx, idx);
foo[idx].a = idx;
} |
When I output the address of each structure element, it looks correct:
Code: | sizeof(TestStruct) = 16
&foo[0] = 0x800
&foo[1] = 0x810
&foo[2] = 0x820
&foo[3] = 0x830
&foo[4] = 0x840
&foo[5] = 0x850
&foo[6] = 0x860
&foo[7] = 0x870
&foo[8] = 0x880
&foo[9] = 0x890
|
Each is 16 bytes apart, so I thought it was fixed (the previous DLL would report each to be 160 -- using the whole size of the 10 array instead of size of a single element).
But, when I check the buffer after I set the values, I see it's corrupted:
Code: | --- Memory after the array:
01 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
02 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
03 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
04 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
05 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
06 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
07 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
08 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
09 00 00 00 aa aa aa aa aa aa aa aa aa aa aa aa
aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
|
It looks like [0] was in the proper place, but then 1-9 started after the array. Odd results, but know that extern of a structure without hard-coding the structure element size is still broken.
This has been reported. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
|
|
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
|