Compiler Bug?

This is peculiar.... I wrote a dead-simple program, that simply would not behave rationally. I eventually narrowed the problem down to use of an array of pointers to char arrays. I created the attached minimum case to demonstrate the problem.

All this does is define, then print, several arrays of char *. If I add a single additional pointer to any of the arrays, the printing gets massively hosed. It is only reporting 68% memory usage, so it does not seem to me that should be a problem but apparently it is! Any usage over 68% causes Serial.print output to get whacked.

I am running on a 168-based Nano, using IDE 1.8.4.

enum cmds
{
	CMD_TBL,		// TBL=OFF/ON/UP/DOWN/PUSH
	CMD_HEAT,		// HEAT=ON/OFF
	CMD_RES,		// RES=ON/OFF
	CMD_VAC,		// VAC=OFF/1/2/BOTH/
	CMD_START,
	CMD_STOP,
	CMD_TUP,
	CMD_TDOWN,
	CMD_TPUSH,
	CMD_THEAT,
	CMD_TPULL,
	CMD_TFAST,
	CMD_SHOW,
	CMD_NCMDS
};

char *keys[] =
{
	"TBL",
	"HEAT",
	"RES",
	"VAC",
	"START",
	"STOP",
	"TUP",
	"TDOWN",
	"TPUSH",
	"THEAT",
	"TPULL",
	"TFAST",
	"SHOW",
};

char *crap[] =
{
	"11111",
	"22222",
	"33333",
	"44444",
	"55555",
	"66666",
	"77777",
	"88888",
	"99999",
	"AAAAA",
	"BBBBB",
	"CCCCC",
	"DDDDD",
	"EEEEE",
	"FFFFF",
	"GGGGG",
	"HHHHH",
	"IIIII",
	"JJJJJ",
	"KKKKK",
	"LLLLL",
	"MMMMM",
	"NNNNN",
	"OOOOO",
	"PPPPP",
	"QQQQQ",
	"RRRRR",
	"SSSSS",
	"TTTTT",
	"UUUUU",
	"VVVVV",
	"WWWWW",
	"YYYYY",
	"ZZZZZ",
	"011111",
	"022222",
	"033333",
	"044444",
	"055555",
	"066666",
	"077777",
	"088888",
	"099999",
	"0AAAAA",
	"0BBBBB",
	"0CCCCC",
	"0DDDDD",
	"0EEEEE",
	"0FFFFF",
	"0GGGGG",
	"0HHHHH",
	"0IIIII",
	"0JJJJJ",
	"0KKKKK",
	"0LLLLL",
	"0MMMMM",
	"0NNNNN",
	"0OOOOO",
	"0PPPPP",
	"0QQQQQ",
	"0RRRRR",
	"0SSSSS",
	"0TTTTT",
	"0UUUUU",
	"0VVVVV",
	"0WWWWW",
	"0XXXXX",
	"0YYYYY",
	"0ZZZZZ",
	"1AAAAA",
};

void setup()
{
	while (!Serial)
		;
	Serial.begin(115200);
	Serial.printf("Vacuum Former Starting...\n");

	for (int i = 0; i < cmds::CMD_NCMDS; i++)
	{
		//delay(100);
		Serial.printf("%s\n", keys[i]);
	}

	for (int i = 0; i < sizeof(crap)/sizeof(char *); i++)
	{
		//delay(100);
		Serial.printf("%s\n", crap[i]);
	}
}


void loop()
{}

Regards,
Ray L.

Does the same problem occur if you run the program on a 1284 or 0256 processor, which have a lot more RAM ?

Just a suggestion as a troubleshooting step.

srnet:
Does the same problem occur if you run the program on a 1284 or 0256 processor, which have a lot more RAM ?

Just a suggestion as a troubleshooting step.

As I indicated, adding a single additional member to either array causes the problem. Anything that pushes RAM use above 68%.
I can't see anything in the code that should be using over 300 bytes of RAM, beyond the static Serial buffers, which would be included in the 68%.
Regards,
Ray L.

What's the printf you are using?

You've modified the Print.h header in order to avail your self of Serial.printf. Try replacing those statements with Serial.println,

enum cmds
{
    CMD_TBL,        // TBL=OFF/ON/UP/DOWN/PUSH
    CMD_HEAT,       // HEAT=ON/OFF
    CMD_RES,        // RES=ON/OFF
    CMD_VAC,        // VAC=OFF/1/2/BOTH/
    CMD_START,
    CMD_STOP,
    CMD_TUP,
    CMD_TDOWN,
    CMD_TPUSH,
    CMD_THEAT,
    CMD_TPULL,
    CMD_TFAST,
    CMD_SHOW,
    CMD_NCMDS
};

char *keys[] =
{
    "TBL",
    "HEAT",
    "RES",
    "VAC",
    "START",
    "STOP",
    "TUP",
    "TDOWN",
    "TPUSH",
    "THEAT",
    "TPULL",
    "TFAST",
    "SHOW",
};

char *crap[] =
{
    "11111",
    "22222",
    "33333",
    "44444",
    "55555",
    "66666",
    "77777",
    "88888",
    "99999",
    "AAAAA",
    "BBBBB",
    "CCCCC",
    "DDDDD",
    "EEEEE",
    "FFFFF",
    "GGGGG",
    "HHHHH",
    "IIIII",
    "JJJJJ",
    "KKKKK",
    "LLLLL",
    "MMMMM",
    "NNNNN",
    "OOOOO",
    "PPPPP",
    "QQQQQ",
    "RRRRR",
    "SSSSS",
    "TTTTT",
    "UUUUU",
    "VVVVV",
    "WWWWW",
    "YYYYY",
    "ZZZZZ",
    "011111",
    "022222",
    "033333",
    "044444",
    "055555",
    "066666",
    "077777",
    "088888",
    "099999",
    "0AAAAA",
    "0BBBBB",
    "0CCCCC",
    "0DDDDD",
    "0EEEEE",
    "0FFFFF",
    "0GGGGG",
    "0HHHHH",
    "0IIIII",
    "0JJJJJ",
    "0KKKKK",
    "0LLLLL",
    "0MMMMM",
    "0NNNNN",
    "0OOOOO",
    "0PPPPP",
    "0QQQQQ",
    "0RRRRR",
    "0SSSSS",
    "0TTTTT",
    "0UUUUU",
    "0VVVVV",
    "0WWWWW",
    "0XXXXX",
    "0YYYYY",
    "0ZZZZZ",
    "1AAAAA",
};

void setup()
{
    while (!Serial)
        ;
    Serial.begin(115200);
    //Serial.printf("Vacuum Former Starting...\n");
    Serial.println("Vacuum Former Starting...\n");

    for (int i = 0; i < cmds::CMD_NCMDS; i++)
    {
        //delay(100);
        //Serial.printf("%s\n", keys[i]);
        Serial.println(keys[i]);
    }

    for (int i = 0; i < sizeof(crap)/sizeof(char *); i++)
    {
        //delay(100);
        //Serial.printf("%s\n", crap[i]);
        Serial.println(crap[i]);
    }
}


void loop()
{}

I just ran on 328 and 2560. No problem. Will hook up a 168 if your test doesn't work.

arduarn:
What's the printf you are using?

What do you mean "what's the printf"? It's standard printf. Nothing special or unusual.
Regards,
Ray L.

arduarn:
What's the printf you are using?

Your Google is obviously broken so here's a direct link for you.

RayLivingston:
What do you mean "what's the printf"? It's standard printf. Nothing special or unusual.

I thought the default hardware serial had no printf ? BTW, doesn't compile for me because of that reason.

DKWatson:
Your Google is obviously broken so here's a direct link for you.

Google doesn't tell me what Ray is using.

No Ray, printf is not standard. It was left out on purpose. sprintf is standard, but to use printf you must modify the board-specific headers for the Print class.

arduarn:
Google doesn't tell me what Ray is using.

Oh yes it does.

OK, it does appear to be the buffer in printf that's causing the problem. I reduced the size, and can now toss more strings into the arrays. I had been under the impression printf had a single global buffer, which would have it included in the RAM usage estimate. But the buffer is local to printf, so is not included. That IS the problem.

Thanks!

Regards,
Ray L.

RayLivingston:

enum cmds

{
CMD_TBL, // TBL=OFF/ON/UP/DOWN/PUSH
CMD_HEAT, // HEAT=ON/OFF
CMD_RES, // RES=ON/OFF
  ....
{

as a side note, enum defaults to an int, so 2 bytes. Since C++11 you can now add a type for the enumerators

defining asenum cmds : uint8_t { CMD_TBL , CMD_HEAT, ... };will save you a 14 bytes! :slight_smile:

J-M-L:
as a side note, enum defaults to an int, so 2 bytes. Since C++11 you can now add a type for the enumerators

defining asenum cmds : uint8_t { CMD_TBL , CMD_HEAT, ... };will save you a 14 bytes! :slight_smile:

You always had the attribute ((packed)) option as well.

DKWatson:
You always had the attribute ((packed)) option as well.

Indeed or Compile with -fshort-enums flag if you don't want to change all the code :slight_smile: