Forum: Compiler & IDEs STM32 - Stack overflow?!


von Martin K. (dschadu)


Lesenswert?

Hi.

ich habe aktuell ein sehr merkwürdiges Problem. Ich bin aktuell ein 
einfaches CAN-Protokoll am basteln.
Neben dem Hardwarepuffer habe ich noch einen Softwarepuffer 
eingerichtet, ein simpler FiFo.

Zum Ablauf:
Jeden Zyklus wird CAN_Main() aufgerufen. Innerhalb davon wird 
CAN_ReceiveSequenceData() augerufen.
1
#define MAX_DATA_RECEIVE_SEQUENCES 6
2
3
volatile int CanRX_Head = 0;
4
volatile int CanRX_Tail = 0;
5
6
ReceiveSequenceStruct ReceiveSequence[MAX_DATA_RECEIVE_SEQUENCES];
7
8
void CAN_ReceiveSequenceData()
9
{
10
  //If there is data to read...
11
  if (CanRX_Head != CanRX_Tail)
12
  {
13
    //uint8_t Temp_CanRX_Head = CanRX_Head;
14
    uint8_t Status = 0;
15
16
    //First test if the received ID is within the data-ID range
17
    if (CanRxMessage[CanRX_Head].StdId >= CAN_DATATYPE_LOWEST_ID && CanRxMessage[CanRX_Head].StdId <= CAN_DATATYPE_HIGHEST_ID)
18
    {
19
      [...]
20
    }
21
    else
22
    {
23
      for (int i = 0; i < ReceiveSequenceIDsCount; i++)
24
      {
25
        if (CanRxMessage[CanRX_Head].StdId == ReceiveSequenceIDs[i])
26
        {
27
          Status = 1;    //Mark as valid sequence ID
28
29
          //Reset data if header is received again
30
          int BufferID = 0;
31
          BufferID = CAN_ReceiveSequence_SearchBuffer(ReceiveSequenceIDs[i]);
32
33
          if (BufferID >= 0)
34
          {
35
            CAN_ReceiveSequence_Reset(BufferID);
36
          }
37
        }
38
      }
39
    }
40
  }
41
}
42
43
//Search the buffer that is used  
44
int CAN_ReceiveSequence_SearchBuffer(uint8_t CAN_StartID)
45
{
46
  for (int i = 0; i < MAX_DATA_RECEIVE_SEQUENCES; i++)
47
  {
48
    if (ReceiveSequence[i].CAN_StartID == CAN_StartID)
49
    {
50
      return i;
51
    }
52
  }
53
54
  return -1;
55
}

Zum Problem: Nehmen wir an CanRX_Head ist 0 und CanRX_Tail ist 1, dann 
ist die erste if-Bedingung erfüllt. Nehmen wir weiterhin an dass die 
zweite if Bedingung nicht erfüllt wird, also springt das Programm in den 
else-Zweig.
Spring das Programm nun in die Funktion 
CAN_ReceiveSequence_SearchBuffer() ändert sich CanRX_Head zu 135. Und 
das sobald er auf die for() schleife springt. Kopiere ich den kram aus 
der Funktion raus, gehts. Dann passiert das gleiche (selber Wert von 
CanRX_Head) in der nächsten Funktion in die er springt.
Daher gehe ich davon aus dass der Speicher überläuft - warum auch immer. 
Ich bin bei 4% RAM-Auslastung.

Jetzt habe ich mir den Spaß gemacht und die beiden Variablen in der 
Initialisierung gedreht
1
volatile int CanRX_Tail = 0;
2
volatile int CanRX_Head = 0;
Und siehe da, es geht. Ohne dass jetzt CanRX_Tail betroffen ist. Zuvor 
habe ich mal ein uin8_t draus gemacht aus beiden Variablen, selbes 
Problem. Nur das drehen der Reihenfolge brachte jetzt "Besserung".

Warum? Was ist da passiert? Kann mir das jemand erklären?

IC ist ein STM32F103RB auf einem Olimex Board.
Programmiert mit VisualGDB (GCC 7.2.0 / GDB 8.0.1)

Edit: Okay, das Problem bleibt, nur anders rum. CanRX_Tail wird jetzt 
immer auf 0 gesetzt. Selbe stelle, selber Sprung in die Funktion

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wenn die erste der beiden Variablen versehentlich überschrieben wird:

Welches Array wird vor der Definition
1
volatile int CanRX_Tail = 0;

definiert? Dieses läuft wohl aufgrund mangelnder Prüfung über.

EDIT:

Die Situation ist etwas verworren beschrieben: Wenn es die zweite 
Variable ist, die verbotenerweise verändert wird, dann liegts wohl eher 
an dem Array

ReceiveSequenceStruct ReceiveSequence[MAX_DATA_RECEIVE_SEQUENCES];

Dieses wird dann mit dem Index -1 beschrieben.

Bitte nochmal genau beschreiben, welche Variable versehentlich 
überschrieben wird. Die obere oder die untere?

: Bearbeitet durch Moderator
von Martin K. (dschadu)


Lesenswert?

Es wird die erste Variable überschrieben:
1
#define CAN_BUFFERCOUNT        10    
2
3
CanRxMsg CanRxMessage[CAN_BUFFERCOUNT];
4
5
volatile int CanRX_Tail = 0;
6
volatile int CanRX_Head = 0;

Hier wird CanRxMessage geschrieben:
1
extern "C" void USB_LP_CAN1_RX0_IRQHandler(void)
2
{
3
  CAN_Receive(CAN1, CAN_FIFO0, &CanRxMessage[CanRX_Tail]);
4
5
  if (CanRX_Tail >= CAN_BUFFERCOUNT)
6
  {
7
    CanRX_Tail = 0;
8
  }
9
  else
10
  {
11
    CanRX_Tail++;
12
  }
13
}


Und jetzt wo ich mir das ansehe, sehe ich den Fehler. Wenn er mit 
CanRX_Tail = 9 in den interrupt springt, geht er mit 10 raus - springt 
wieder rein und landet mit [10] im Array out of bounds...

Was nen hinterhältiger Fehler.


Danke für den Schubs in die richtige Richtung

Edit:
Ich kapier aber nicht warum bei einem Sprung in eine andere Funktion? 
Müsste das nicht sofort passieren sobald der Überlauf stattfindet, also 
beim Empfangen der Nachricht?

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.