Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Stack Underflow When the Number of an Array is Increased

Status
Not open for further replies.
Look at the first few lines of the 'mainsta.txt' file you have provided. It tells you that you are using 30% of the RAM (31% at worst) and so that should not be a problem.
It also says that it is allocating a stack size of '31' (whatever units) but the compiler's analysis shows you only use 11 of them, so again that should not be a problem.
What all this points to is what we have been saying all along - it is in your code. At a guess you have not set your pointers properly and they are therefore writing into areas they should not.
Susan
 

You did not give any information on how ShiftToRecords() function is instantiated ( I mean, it arguments ), but the function is implemented in such a manner that is prone to the pointer make an access violation, as mentioned.

In the line 4 below, you defined a constant value for blankShiftNumber variable, perhaps assuming it is the length of the array messagePriorityLevels[]. Seems like you should replace the constant '24' by sizeof(messagePriorityLevels[]) instead, otherwise in line 15 the evaluation while(blankShiftNumber != 0) will underflow pointer if decremented more than its size.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void ShiftToRecords(int8 *ptr, int8 iterNum, int1 comType)
{
    iterNum++;
    blankShiftNumber = 24 - iterNum;
 
    while(iterNum != 0)
    {
        shiftBit = shift_right(inputRecordsStable, 3, 0);   
        shift_right(ptr, 3, shiftBit);
        iterNum--;
    }
 
    while(blankShiftNumber != 0)
    {
        shift_right(ptr, 3, 0);       /* **** The reset evet happens in this line **** */
        blankShiftNumber--;
    }

 

Thanks for the answers.
@susan: yes,the problems isn't really a stack under flow. As I see in the debug process, in the second shift_right function, the function shifts the stack pointer. At the first shift process, it is shifting the right address, but in the second it is shifting the stack pointer. Only possible branching is the timer interrupt. So I don't know which part of the code should I look? No function calls in that part, is defined by me. I can check the first shift_right to be sure.
@andre: the '24' is three bytes. The shift_right function parameters are; first the starting address that the shifting will be done, second is how many bytes starting from the ptr address will be shifted, third is the bit to be shifted. The second parameter is 3 because the parameter that is assigned to ptr pointer is an array sized three elements. Also the blankshiftnumber parameter doesn't cause problem because it only has the value of shifting number, not the number of the bytes to be shifted.

I will recheck the first shift_right function to see if it also changes the stack pointer value.(in fact it effects the stack value, not sure about the stack pointer directly.) But I don't think it does, because I have overcome the problem by defining a global pointer, and assigning the ptr value to global pointer at the beginning of ShiftToRecords function. If the passing value to the ptr is not correct, i wouldn't have overcome the problem.
 

Nice reporting, but mostly useless without the shift_right() source code. One more try, then I'll cancel my thread subscription.
 

As I informed earlier, shift_right is compiler's function, and I can't see the c source code. I can attach the function prototype and assembly source code of it.
The prototype of shift_right:
Code:
_bif int1 shift_right(unsigned int8* address, unsigned int8 bytes, int1 value);

The shift_right function assembly source:
Code:
.................... 		shift_right(ptr, 3, 0); 
07D5C:  MOVFF  441,FEA
07D60:  MOVFF  440,FE9
07D64:  MOVLW  02
07D66:  ADDWF  FE9,F
07D68:  BCF    FD8.0
07D6A:  RRCF   FED,F
07D6C:  RRCF   FED,F
07D6E:  RRCF   FED,F

Maybe this one will be useful, the assembly source of ShiftToRecords function complete:
Code:
.................... void ShiftToRecords(int8 *ptr, int8 iterNum, int1 comType) 
.................... { 
.................... 	iterNum++; 
*
07D10:  MOVLB  4
07D12:  INCF   x42,F
.................... 	blankShiftNumber = 24 - iterNum;
07D14:  MOVLW  18
07D16:  BSF    FD8.0
07D18:  SUBFWB x42,W
07D1A:  MOVLB  0
07D1C:  MOVWF  xFB
....................  
.................... 	while(iterNum != 0) 
07D1E:  MOVLB  4
07D20:  MOVF   x42,F
07D22:  BZ    7D56
.................... 	{ 
.................... 		shiftBit = shift_right(inputRecordsStable, 3, 0);
07D24:  BCF    51.7
07D26:  BCF    FD8.0
07D28:  MOVLB  0
07D2A:  RRCF   xCA,F
07D2C:  RRCF   xC9,F
07D2E:  RRCF   xC8,F
07D30:  BNC   7D34
07D32:  BSF    51.7
.................... 		shift_right(ptr, 3, shiftBit);
07D34:  BTFSC  51.7
07D36:  BRA    7D3C
07D38:  BCF    FD8.0
07D3A:  BRA    7D3E
07D3C:  BSF    FD8.0
07D3E:  MOVFF  441,FEA
07D42:  MOVFF  440,FE9
07D46:  MOVF   FEC,F
07D48:  MOVF   FEC,F
07D4A:  RRCF   FED,F
07D4C:  RRCF   FED,F
07D4E:  RRCF   FED,F
.................... 																		// kaydırılmasında kullan. 
.................... 		iterNum--; 
07D50:  MOVLB  4
07D52:  DECF   x42,F
07D54:  BRA    7D20
.................... 	} 
....................  
.................... 	while(blankShiftNumber != 0) 
07D56:  MOVLB  0
07D58:  MOVF   xFB,F
07D5A:  BZ    7D74
.................... 	{ 
.................... 		shift_right(ptr, 3, 0); 
07D5C:  MOVFF  441,FEA
07D60:  MOVFF  440,FE9
07D64:  MOVLW  02
07D66:  ADDWF  FE9,F
07D68:  BCF    FD8.0
07D6A:  RRCF   FED,F
07D6C:  RRCF   FED,F
07D6E:  RRCF   FED,F
.................... 		blankShiftNumber--; 
07D70:  DECF   xFB,F
07D72:  BRA    7D58
.................... 	} 
.................... 	 
.................... 	inputRecordsStable[0] = 0; 
07D74:  CLRF   xC8
.................... 	inputRecordsStable[1] = 0; 
07D76:  CLRF   xC9
.................... 	inputRecordsStable[2] = 0; 
07D78:  CLRF   xCA
....................  
.................... 	return; 
07D7A:  RETURN 0
.................... }
 

As I informed earlier, shift_right is compiler's function, and I can't see the c source code.
I apologize for overlooking the point. I see you are using CCS C. Which version, exactly?
 

Maybe this one will be useful, the assembly source of ShiftToRecords function complete:

At least there we can see that no CALL instruction were used, so this reveal the possibility that you are perhaps instantiating the function with arguments that leads variables beyond the array limits. Considering that you're using about just 1/3 of the total RAM resources, I would recommend you consider using closed array instead of pointers, which accepts any argument. As a friend said, "pointers are not for kids" :wink:.
 

I think you have to use

Code:
shift_right(&ptr, 3, 0);

Edit: Your code is correct. ptr contains the address of some array and you are passing that address to shift_right();
 

Although the usage of function shift_right() may appear correct, it is being used within the function ShiftToRecords() for which @apsua did not inform so far how it is instantiated in program ( what arguments ).
 

I can basically understand the code function. Question is what goes wrong.

but in the second it is shifting the stack pointer. Only possible branching is the timer interrupt. So I don't know which part of the code should I look?
Index register FSR0 is loaded with ptr value. So either ptr is corrupted or FSR0 is changed in an interrupt function.

Did you check ptr and FSR0 values while tracing code execution?
You can also try to set a data memory breakpoint on stack pointer accesses (hopefully it doesn't break the debug monitor).
 
  • Like
Reactions: apsua

    apsua

    Points: 2
    Helpful Answer Positive Rating
@FvM: I am using 5.015 version of CCS C. Thanks, I will make a debug and check the points you say tonight, will write the results.

@Andre: Yes, I also think and also see in debug process that, there is no problem about the call and return numbers to cause the stack underflow error. It seems to shift the stack value, and changes it to for eg. 0x0060 which causes the program to start from the beginning. For the ShiftToRecords function, the information are as below:
The function prototype:
Code:
void ShiftToRecords(int8*, int8, int1);

A sample function call and the parameters which are defined before calling the function:
Code:
int	recordsMix[3];
int maxFloor; // this value is read from the eeprom, it doesn't effect our case even if unexpectedly high
Code:
ShiftToRecords(recordsMix, maxFloor, PARALLEL_DATA);

And the function:
Code:
void ShiftToRecords(int8 *ptr, int8 iterNum, int1 comType)
{
	pointer0 = ptr;
	iterNum++;
	blankShiftNumber = 24 - iterNum;

	while(iterNum != 0)
	{
		shiftBit = shift_right(inputRecordsStable, 3, 0);	
		shift_right(pointer0, 3, shiftBit);
		iterNum--;
	}

	while(blankShiftNumber != 0)
	{
		shift_right(pointer0, 3, 0);
		blankShiftNumber--;
	}
	
	inputRecordsStable[0] = 0;
	inputRecordsStable[1] = 0;
	inputRecordsStable[2] = 0;

	return;
}
 

A sample function call and the parameters which are defined before calling the function:

This adds a lot, but it is still not clear which numerical values specifically make trouble.

Code:
int maxFloor; // this value is read from the eeprom, it doesn't effect our case even if unexpectedly high

You're probably neglecting the affect that a wrong value to this variable could make in your program.
Note that for some values this could result in a negative argument to the shift function.
 

As you are using Proteus, load the .cof file in Proteus and debug and see where exactly stack underflow occurs.
 

@andre: the maxFloor variable indicates how many times the shifting will be done, if it is an unexpected value of it, only an unwanted value will be seen for the result value. The address shouldn't change I think. Anyway, after the debug this night, I will write the results.

@Okada: Yes, I am using the .cof file. In the second shift_right function, it changes the high byte of the first stack value until 0, so the stack address becomes around 0x0060. After quiting the while function, it comes to the end of the function and wants to return. The stack address should be a value like for eg. 0x7560, but because it is changed by shift_right to 0x0060, it approximately shows the beginning of the code. So the program restarts. This is what happens. I will check again this night with paying attention to the what @FvM say.
 

Proteus can do source and assembly level debugging with *.cof files, but I would prefer MPLAB SIM or real hardware debugging.
 

If you can post the latest .cof file then I will debug it in Proteus and see.
 

Hello again,
The problem seems to happen because the array 'recordsMix[3]' address(which is passed to ptr) is 0x0FE. We are shifting 3 bytes, so we are shifting 0xFE, 0xFF and 0x100. Please see the assembly code of ShiftToRecords again below:
Code:
.................... void ShiftToRecords(int8 *ptr, int8 iterNum, int1 comType) 
.................... { 
.................... 	iterNum++; 
*
07D10:  MOVLB  4
07D12:  INCF   x42,F
.................... 	blankShiftNumber = 24 - iterNum;
07D14:  MOVLW  18
07D16:  BSF    FD8.0
07D18:  SUBFWB x42,W
07D1A:  MOVLB  0
07D1C:  MOVWF  xFB
....................  
.................... 	while(iterNum != 0) 
07D1E:  MOVLB  4
07D20:  MOVF   x42,F
07D22:  BZ    7D56
.................... 	{ 
.................... 		shiftBit = shift_right(inputRecordsStable, 3, 0);
07D24:  BCF    51.7
07D26:  BCF    FD8.0
07D28:  MOVLB  0
07D2A:  RRCF   xCA,F
07D2C:  RRCF   xC9,F
07D2E:  RRCF   xC8,F
07D30:  BNC   7D34
07D32:  BSF    51.7
.................... 		shift_right(ptr, 3, shiftBit);
07D34:  BTFSC  51.7
07D36:  BRA    7D3C
07D38:  BCF    FD8.0
07D3A:  BRA    7D3E
07D3C:  BSF    FD8.0
07D3E:  MOVFF  441,FEA
07D42:  MOVFF  440,FE9
07D46:  MOVF   FEC,F
07D48:  MOVF   FEC,F
07D4A:  RRCF   FED,F
07D4C:  RRCF   FED,F
07D4E:  RRCF   FED,F
.................... 																		// kaydırılmasında kullan. 
.................... 		iterNum--; 
07D50:  MOVLB  4
07D52:  DECF   x42,F
07D54:  BRA    7D20
.................... 	} 
....................  
.................... 	while(blankShiftNumber != 0) 
07D56:  MOVLB  0
07D58:  MOVF   xFB,F
07D5A:  BZ    7D74
.................... 	{ 
.................... 		shift_right(ptr, 3, 0); 
07D5C:  MOVFF  441,FEA
07D60:  MOVFF  440,FE9
07D64:  MOVLW  02
07D66:  ADDWF  FE9,F
07D68:  BCF    FD8.0
07D6A:  RRCF   FED,F
07D6C:  RRCF   FED,F
07D6E:  RRCF   FED,F
.................... 		blankShiftNumber--; 
07D70:  DECF   xFB,F
07D72:  BRA    7D58
.................... 	} 
.................... 	 
.................... 	inputRecordsStable[0] = 0; 
07D74:  CLRF   xC8
.................... 	inputRecordsStable[1] = 0; 
07D76:  CLRF   xC9
.................... 	inputRecordsStable[2] = 0; 
07D78:  CLRF   xCA
....................  
.................... 	return; 
07D7A:  RETURN 0
.................... }

Here FD8.0 is STATUS, carry bit. At the "shift_right(ptr, 3, 0);" lines assembly codes:
Code:
.................... 		shift_right(ptr, 3, 0); 
07D5C:  MOVFF  441,FEA
07D60:  MOVFF  440,FE9
07D64:  MOVLW  02
07D66:  ADDWF  FE9,F
07D68:  BCF    FD8.0
07D6A:  RRCF   FED,F
07D6C:  RRCF   FED,F
07D6E:  RRCF   FED,F
the ptr(0x440 & 0x441) contains the recordsMix address which is 0x00FE. These are copied to 0XFE9 and 0xFEA addresses. Then the assembly code wants to add 2 to 0xFE9 address' content, to decide the boundry of the shifting(which is three bytes, two more than starting address). 0xFE9's content is 0xFE, added two, it becomes 0x00, but the 0xFEA(the high byte) doesn't become 1. Maybe because the carry bit clear in the next line. Instead the 0xFEA becomes 0x0F in proteus (this, I didn't understand why it becomes 0x0F).
Now, the address 0xFEA contains the high byte of the pointer's address: 0x0F
The address of 0xFE9 contains the low byte of the pointer's address: 0x0FE
So the address turns into 0x0FFE which is the "Top-of-Stack" register's address. In proteus simulation, this address content is being shifted, but this is not a CALL command, the stack depth stays at the same number, '1'. So we are seeing the address in the stack being changed while shifting.

To make a crosscheck; I made some tests;
1.I changed the address of recordsMix to 0x100-0x102 instead of 0x0FE-0x100, worked correct.
2.There is another shift_right function in ShiftToRecords function, but it works correct, as below:
Code:
shift_right(ptr, 3, shiftBit);
I changed the third function parameter, shiftBit, to 0, just like the second function. This time the problem happened in this line before the second one.
3.This one was my temporary solution to walk around the problem. I had defined global pointer which has a smaller address. I copied the ptr to this global pointer, and used this global pointer for the shift_right operations, again no problem happened.

I think this is a compiler bug. What do you think?
I hope I could have told the issue understandable.
 
  • Like
Reactions: FvM

    FvM

    Points: 2
    Helpful Answer Positive Rating
Code:
void ShiftToRecords(int8*, int8, int1);

The first argument is a pointer to char type (int8 or byte).

so we are shifting 0xFE, 0xFF and 0x100

0x100 is a two byte.

If ptr can only point to a byte.
 

I think this is a compiler bug. What do you think?
Yes, shift_right() doesn't work if the data entity crosses a page boundary.

Code:
  006C    0E02     MOVLW 0x2
  006E    26E9     ADDWF 0xfe9, F, ACCESS
  0070    90D8     BCF 0xfd8, 0, ACCESS
  0072    32ED     RRCF 0xfed, F, ACCESS
  0074    32ED     RRCF 0xfed, F, ACCESS
  0076    32ED     RRCF 0xfed, F, ACCESS

Instead of a single ADDWF 0xfe9, F, ACCESS, there must be a handling of overflow to FSR0H.

You can make your own shift_right() function.

I'm also using CCS C for some projects, I had a hard time starting PIC24 development with PCD V4 eight years ago, found about a dozen of compiler bugs during the first years.


0x100 is a two byte.

If ptr can only point to a byte.
Not right. A PIC18 pointer is a 16 bit entity, no matter what data size it points to. Similarly the index registers FSR0, FSR1 and FSR2 have a low and high byte. If you read the disassembly listing thoroughly, you'll see.

Must confess that I don't like PIC18 assembly code that much, but debugging compiler errors (or some nasty self-elaborated coding faults) is hardly possible without it.

- - - Updated - - -

Forgot to mention that the bug is still present in most recent CCS C V5.064, so it was apparently not yet reported to CCS.
 
  • Like
Reactions: apsua

    apsua

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top