Buffer overflow char array

Buongiorno,

non riesco a capire come sia possibile che funzioni questo codice:

byte byteArray[4] = { 67, 73, 65, 79 };

char msg[1];

void setup() {
  Serial.begin(115200);

  for( int i = 0; i < 4; i++) {
    msg[i] = (char)byteArray[i];
  }
  msg[4] = '\0';

  Serial.println(msg);
}

void loop() {

}

Non capisco come sia possibile che il ciclo for() mi ridimensioni il mio char array che ho inizializzato con dimensione 1.

Inoltre se al mio codice aggiungo char msgb = “B” come segue:

byte byteArray[4] = { 67, 73, 65, 79 };

char msg[1];
char msgb[] = "B";

void setup() {
  Serial.begin(115200);

  for( int i = 0; i < 4; i++) {
    msg[i] = (char)byteArray[i];
  }
  msg[4] = '\0';

  Serial.println(msg);
  Serial.println(msgb);
}

void loop() {

}

Come risultato a monitor ottengo:

CIAO
B

Ciò è determinato dal fatto che i byte usati per l’array sono pescati casualmente e non sequenziali ? Mi sembra molto strano questo comportamento ::slight_smile:

Non riesco a capire… :confused:

Ti funziona per pura fortuna, nel senso che non vi è nessun controllo da parte del C che tu stia andando fuori dalla dimensione dell'array (avrai sicuramente dei warning se li attivi in compilazione) quindi tu "sporchi" le aree di memoria contigue all'array che per tua fortuna in questo caso non sono utilizzate.
Quando usi la funzione per stampare l'array di char questa continua finchè non trova il terminatore.
Non puoi aspettarti che il secondo array sia posizionato in memoria immediatamente dopo al primo array, se così fosse stato (ma per pura fortuna) avresti visto che il secondo array conteneva il contenuto (scusa il gioco di parole) che hai scritto andando oltre la dimensione dell'array.
In ogni caso è sempre un errore andare oltre alla dimensione dell'array perché finisci in un undefined behiavour quindi non si sa cosa può succedere, da niente come in questo caso alla terza guerra mondiale

Per verificare quanto sto dicendo puoi farti stampare la posizione in memoria dei due array stampando il loro riferimento

Te la faccio semplice :slight_smile:

Io dichiaro un array di x elementi, significa che riservo una parte di memoria solo per quello scopo.
Io uso più elementi di quelli dichiarati, vado ad usare della memoria non riservata, cosa può succedere?
Se nessun altro usa quella memoria tutto funziona come se avessi dichiarato più elementi, se qualcun altro usa quella memori i dati sono corrotti, o se la memoria contiene istruzioni il programma si blocca.

Grazie delle risposte,

fabpolli:
Ti funziona per pura fortuna

Infatti tutto è nato da un programma molto più complesso, dove per errore mio l'array andava in overflow e si corrompeva la stringa, poi per provare ho scritto il codice che ho riportato nel primo post e tutto funzionava correttamente; da qui sono nati i miei dubbi e considerazioni.

Io davo per scontato che l'allocazione degli array fosse sequenziale e non casuale, ma non è così, ho imparato qualcosa di nuovo. :smiley:

Resta un altro dubbio, come è possibile andare il overflow di un array ?
Ciò vuol dire che non c'è un controllo della dimensione allocata in memoria per quel array prima di andarlo a scrivere. Corretto ?

Moce993:
Io davo per scontato che l'allocazione degli array fosse sequenziale e non casuale, ma non è così, ho imparato qualcosa di nuovo. :smiley:

Resta un altro dubbio, come è possibile andare il overflow di un array ?
Ciò vuol dire che non c'è un controllo della dimensione allocata in memoria per quel array prima di andarlo a scrivere. Corretto ?

L'allocazione della memoria per i vari elementi dell'array è sequenziale, l'allocazione delle variabili non è detto sia sequenziale.
Andare in overflow dell'array ci riesci semplicemente quando scrivi oltre l'indice con cui l'hai dichiarato (Es. dichiari lungo 10 (quindi indici da zero a nove) e scrivi in posizione 10 o 11 o 200) e no non vi è nessun controllo che tu non stia andando oltre la dimensione dichiarata

Moce993:
Ciò vuol dire che non c'è un controllo della dimensione allocata in memoria per quel array prima di andarlo a scrivere. Corretto ?

Per spiegare un poco meglio il perché, sappi che definire un array ad esempio come "char msg;" equivale di fatto (è proprio così) a definire "msg" come un puntatore al primo byte di un'area di memoria che contiene dati di tipo "char" ossia caratteri, ma NON alloca nessuno spazio in memoria, cosa che invece fa con "char msg[10];" (allochi 10 byte).

Quando usi l'indice di un array di fatto stai calcolando un indirizzo a partire da quello base, ad esempio "msg[3]" equivale a puntare a "(msg+3)" ossia 3 byte oltre quello iniziale.

Quindi si, come ti hanno già spiegato, se usi un indice maggiore del valore massimo allocato, in C non hai alcun avviso preventivo (es. un errore "index out of bounds") per cui TU devi sempre fare attenzione ad allocare lo spazio necessario per contenere tutti i dati che potresti inserire nell'array (nel caso delle stringhe fare "char msg[20]" significa poter mettere stringhe di dimensione massima 19, visto che deve sempre esserci il terminatore 0x00), e quindi anche a non uscire dall'area di memoria allocata, pena malfunzionamenti imprevisti ed apparentemente inspiegabili.

PS: Più genericamente, sappi che se "tipo" è il tipo di dato dell'array "tipo nome", richiamare "nome[10]" equivale a calcolare l'indirizzo "(nome + 10*sizeof(tipo))" dove "sizeof(tipo)" rappresenta la dimensione in byte occupata da un elemento del tipo di variabile "tipo".
Nel caso di "char" ad esempio "sizeof(char)" vale 1, su Arduino "int" vale 2, "long" vale 4, ecc.