Probleme bei Pointer in C. Code crasht

Gast #6413075
Lesenswert?

Hallo,
ich habe hier einen Code, welcher immer abstürzt
1
static uint32 table_p[64];
2
static table_T *resp_table;
3

4
typedef struct
5
{
6
  uint8 inUse;
7
  uint8 status;
8
  ...
9
} table_T, *table_t;
10

11
typedef struct
12
{
13
...
14
uint32 *table;
15
uint32 size;
16
...
17
}init_ts
18

19

20
void init(void)
21
{
22

23
  init_ts init_s;
24
...
25
  init_s.table = table_p;
26
  init_s.size= 64;
27
...
28
}
29

30

31
static void install_tab(init_ts *init_s)
32
{
33
  resp_table = (table_t)(init_s->table);
34
  for(uint32 n=0; n<init_s->size; n++)
35
  {
36
    resp_table[n].inUse = 0;  // hier crasht es. Im Debugger (qt-creator) sehe ich aber, dass die Adresse von resp_table = die Adresse von table_p ist 
37
    resp_table[n].status = 0;
38
  }
39
}

Im Debugger steht
table_p    @0x6ae0e0       [uint32]64
resp_table 0x6ae0e00000000 table_T*

resp_table liegt an der Adresse 0x6a21d0, beinhaltet aber den oben 
beschriebenen Wert.

Als Fehler bekomme ich segmentation fault. Was ja heißt, dass in einem 
falschen Bereich geschrieben wurde.

Woran kann das liegen?
#6413098
Lesenswert?

Jup du versuchst eine Struktur auf einen uint32 Pointer zu drücken. 
Deine Struktur ist im Stack aber nicht zusammenhängend angelegt. Du 
greifst unerlaubt in den Speicher..

Dein Cast ist falsch und das ganze macht so gesehen auch keinen Sinn.... 
Der Code ist unübersichtlich und was eigentlich passieren soll ist 
unklar.
#6413104
Lesenswert?

B. W. schrieb:
> Hmm... das compiliert nicht...

Der ziemlich zusammengestückelte und fehlerhafte Code lässt auch darauf 
schießen, dass das nicht der Code ist, der das beobachtete Problem 
verursacht hat. So kann man damit wenig anfangen. Besser wäre ein 
minimales, aber vollständiges Programm, das du genau so ausgeführt 
hast und das den Fehler zeigt.

Marco H. schrieb:
> Dein Cast ist falsch und das ganze macht so gesehen auch keinen Sinn....

Dachte ich zuerst auch, aber ist er nicht. Man achte beim typedef 
darauf, dass die Struktur selbst table_T mit großem T heißt, während 
table_t einen Zeiger darauf bezeichnet. Ziemlich heimtückische Falle.
Meine Glaskugel meint, es könnte sein, dass ein table_T größer ist als 
ein uint32, und daher in ein Array aus 64 uint32 keine 64 table_T 
reinpassen.
Gast #6413121
Lesenswert?

Rolf M. schrieb:
> Dachte ich zuerst auch, aber ist er nicht. Man achte beim typedef
> darauf, dass die Struktur selbst table_T mit großem T heißt, während
> table_t einen Zeiger darauf bezeichnet. Ziemlich heimtückische Falle.
> Meine Glaskugel meint, es könnte sein, dass ein table_T größer ist als
> ein uint32, und daher in ein Array aus 64 uint32 keine 64 table_T
> reinpassen.

Das ist relativ egal, da es eh undefined behavior ist (verstößt gegen 
die "strict aliasing" Regeln)
Moderator #6413123
Lesenswert?

Wie schon geschrieben wurde, gibt es einen Array-Überlauf, wenn
sizeof(table_T) > sizeof(uint32) ist.

Die Zeile

1
  resp_table = (table_t)(init_s->table);

verstößt gegen die strict aliasing Rule, d.h. selbst wenn es keinen
Array-Überlauf gibt, ist das Verhalten dennoch undefiniert.

Es ist nicht klar, ob init_s in dieser Zeile überhaupt initialisiert
ist. Es gibt zwar die Funktion init(), die evtl. auch irgendwo
aufgerufen wird, aber darin wird sinnloserweise nur eine lokale Variable
initialisiert.
Gast #6413133
Lesenswert?

Yalu X. schrieb:
> Die Zeile
>
>   resp_table = (table_t)(init_s->table);
>
> verstößt gegen die strict aliasing Rule, d.h. selbst wenn es keinen
> Array-Überlauf gibt, ist das Verhalten dennoch undefiniert.

Genau genommen sorgt erst die Zeile
1
resp_table[n].inUse = 0;
für ub ;-) Die Konvertierung des Pointers ist erlaubt, der Zugriff 
nicht.
Gast #6413774
Lesenswert?

Frank M. schrieb:
> leo schrieb:
>> Du initialisierst hier eine lokale Variable, die dann wieder
>> verschwindet.
>
> Korrekt.
>
>> Dann verwendest du einen Pointer auf diese.
>
> Nein, es wird ein Pointer auf eine globale Variable sein, die
> zufälligerweise genauso heisst. Sonst würde das gar nicht durch den
> Compiler gehen.

Ich verstehe nicht so ganz worauf ihr euch bezieht. In init gibt es eine 
lokale Variable init_s. Die Funktion install_tab hat einen Parameter 
init_s. Da sehe ich keine Probleme. Ok es ist unklar, wann welche 
Funktion aufgerufen wird, wann das Programm abstürzt und welchen Zustand 
die debug-Ausgabe abbildet. Aber so wie es aussieht gehe ich von 
folgendem Ablauf aus:
init erzeugt ein init_ts mit Namen init_s und "initialisiert" es mit 
einem Pointer auf das globale table_p. Weiterhin in init wird dann 
install_tab mit einem Pointer auf das lokale init_s aufgerufen. 
install_tab schreibt dann über den Pointer im init_s Parameter in das 
globale table_p.
Das sollte funktionieren, wenn man das undefined behavior beseitigt.
Moderator Persönliche Seite #6413791
Lesenswert?

mh schrieb:
> Ich verstehe nicht so ganz worauf ihr euch bezieht. In init gibt es eine
> lokale Variable init_s. Die Funktion install_tab hat einen Parameter
> init_s.

Die eine Variable init_s hat aber mit der anderen init_s - wo auch immer 
die herkommt - nichts zu tun. An die lokale Variable kommt man von 
außerhalb nicht dran, darum kümmert sich der Compiler. Oder TO hat 
seinen Code soweit zurechtgestutzt, dass der präsentierte Code nichts 
mehr mit dem tatsächlichen Code zu tun hat.
Gast #6413803
Lesenswert?

Frank M. schrieb:
> mh schrieb:
>> Ich verstehe nicht so ganz worauf ihr euch bezieht. In init gibt es eine
>> lokale Variable init_s. Die Funktion install_tab hat einen Parameter
>> init_s.
>
> Die eine Variable init_s hat aber mit der anderen init_s - wo auch immer
> die herkommt - nichts zu tun. An die lokale Variable kommt man von
> außerhalb nicht dran, darum kümmert sich der Compiler. Oder TO hat
> seinen Code soweit zurechtgestutzt, dass der präsentierte Code nichts
> mehr mit dem tatsächlichen Code zu tun hat.

Natürlich hat er ihn zusammengestutzt. Deswegen die ganzen "...". 
Ansonsten würde es ja auch keine Probleme geben, weil init und 
install_tab nicht aufgerufen werden. install_tab wird IN init 
aufgerufen.
#6413810
Lesenswert?

Lothar schrieb:
> Marco H. schrieb:
>> Deine Struktur ist im Stack aber nicht zusammenhängend angelegt
>
> PC oder uC?
>
> __packed struct
>
> https://www.keil.com/support/man/docs/armcc/armcc_chr1359124968737.htm

Klar kann man den Compiler anweisen die Struktur so auf dem Stack zu 
packen. Sehr beliebt bei AVRs weil es so schön einfach ist, mit OS 
sollte man dies aber vermeiden.

Gerade Anfängern ist die Tragweite nicht bewusst und dann schlägt man so 
etwas erstmal nicht vor. Da es das eigentliche Problem nicht behebt.
Gast #6413925
Lesenswert?

Marco H. schrieb:
> Compiler anweisen die Struktur so auf dem Stack

Mit OS sollte es doch mit union gehen. Habe hier einen Message Block mit 
256 Byte der als Byte Pointer übergeben werden muss, aber auch Variablen 
enthält, auf die direkt zugegriffen werden kann.

> Sehr beliebt bei AVR

Bei AVR sind eher nicht-aligned struct beliebt z.B. bei Ethernet oder SD 
Treiber. Portierung auf Cortex-M gibt dann erst mal Hardfault.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren