CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

5.092 extern MyStruct foo[]; miscalculates size, corruption.

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
allenhuffman



Joined: 17 Jun 2019
Posts: 537
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

5.092 extern MyStruct foo[]; miscalculates size, corruption.
PostPosted: Wed Jan 22, 2020 1:01 pm     Reply with quote

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. Smile

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: 537
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Jan 22, 2020 1:56 pm     Reply with quote

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! Smile

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: 537
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Thu Jan 30, 2020 2:01 pm     Reply with quote

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: 537
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 12, 2020 9:49 am     Reply with quote

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: 537
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Feb 24, 2020 11:49 am     Reply with quote

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 ?
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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