venerdì 3 febbraio 2012

Segmentation fault

Segmentation fault


English
Easy challenge for C programmers (see the picture below).
Why program "zed" gives this result? Is there something wrong in the code? If yes, what? If you can't get the solution just watching the picture, remember that you have at least 4 ways to figure out what's going on without either changing the code or using a debugger. Can you find at least 4 different ways? (There are more)


Italiano
Sfida facile per programmatori C (guarda l'immagine sotto).
Perché il programma "zed" dà questo risultato? C'è qualcosa di sbagliato nel codice? Se sì, che cosa? Se non riesci a dare la soluzione solo guardando la figura, ricorda che ci sono almeno quattro modi per capire che cosa sta succedendo nel programma senza né cambiare il codice né usare un debugger. Riesci a trovare almeno quattro modi diversi? (Ce ne sono di più)


Indizi - Hints - Indizi - Hints - Indizi - Hints - Indizi

(2012-05-02)
English.
Hint #1. This could not be as useful as you hope. However it is:
$ gcc -s -Wall zed.c -o zed
$ ./zed
Segmentation fault
$ echo $?
139

$ _ 
This means that the return value of the execution is effectively different from 0, or in other words, in general but not always, it means that an error in runtime has occurred. Is this such a case? if yes, where is the error?

(2012-06-02)
Hint #2. With the previous hint you should be able to solve the quiz... however, here a new hint: the same code in a PowerPC G3 740/750 gives Segmentation fault.
In a MIPS Malta CPU the error is Bus error, which is very similar to Segmentation fault, regarding memory alignment instead of memory bounds. This error could only be returned because MIPS Malta CPUs organize memory in a different (old) way.
Here the problem seems to be an "out of bound" error, but the question is: is it as it seems to be? Is the same case for a x86 machine?

(2012-07-02)
Hint #3. Not yet? let's analyze the code:
  1. #include <stdio.h> is mandatory to use "printf"
  2. int main(void) { is the declaration of the main witout parameters... typical
  3. union my_union { is the definition of union my_union
  4. long long i; is the first field of the union, a long long. How much is the size of a long long? does it depend on the architecture? (it is signed)
  5. char c[8]; it is the second and last field of the union, how much is the size of a char? does it depend on the architecture? (it is signed)
  6. }; ...
  7. const union my_union a[3] = { is the declaration of variable a, as a stack array of 3 elements of type "union my_union" and it is defined as constant. Does it create some problem the fact it is constant?
  8. {7022359100883690835LL}, is a natural number stored in a[0]
  9. {8458153864656284020LL}, is a natural number stored in a[1]
  10. {01203272154LL}, is a natural number stored in a[2]. It starts with 0. What does it mean?
  11. }; ...
  12. printf("%5s", (a + a[2].c[7]*a[1].i)->c); asks the system to print, with at least 5 characters eventually replaced with spaces ' ', of what? In order to figure out what is happening, let's remind the reader, taken i as an integer, that a[i] and (a + i) are the same and both are syntactically correct; moreover, notice that a[1].i has been declared to be 8458153864656284020LL. But it's a signed long long, is it negative? is it important?
  13. return a[2].c[1] % (10LL + a[2].c[2]); returns his right part after having evaulated it. è il valore di ritorno. Casts for so small numbers like 10LL are automatically computed end the compiler doesn't print a "warning". "%" is simply the rest of integer division.
  14. } ... THE END
Don't say you are still not able to answer questions! They are just 14 rows of code anyway...
(2012-02-06)
Italiano.
Indizio 1. Potrebbe non essere tanto utile quanto sperate. Tuttavia eccolo:
$ gcc -s -Wall zed.c -o zed
$ ./zed
Segmentation fault
$ echo $?
139

$ _ 
Che significa che il valore di ritorno dell'esecuzione è effettivamente diverso da 0, ovvero, in generale anche se non sempre, significa che è avvenuto un errore a runtime. È questo il caso? Sapete dire eventualmente dove sia l'errore?

(2012-02-06)
Indizio 2. Col precedente indizio avreste dovuto poter risolvere il quiz... comunque, ecco un nuovo indizio: lo stesso codice in un processore PowerPC G3 740/750 restituisce Segmentation fault.
In un processore MIPS Malta l'errore è Bus error, che è molto simile a Segmentation fault, riguardando l'allineamento della memoria anziché i limiti della memoria. Questo errore potrebbe essere restituito solamente perché il MIPS Malta (che è un po' vecchietto) organizza in modo diverso la memoria.
Ora sembra che il problema sia un errore "fuori dai limiti", ma la domanda è: è così come sembra che sia? È lo stesso il caso in una macchina x86?

(2012-02-07)
Indizio 3. Non ancora? Analizziamo il codice.
  1. #include <stdio.h> è necessario per usare "printf"
  2. int main(void) { è la dichiarazione del main senza argomenti... tipico
  3. union my_union { è la definizione della union my_union
  4. long long i; è il primo campo della union, un long long. Quanto è grande un long long? dipende dall'architettura? (è col segno)
  5. char c[8]; è il secondo e ultimo campo della union, quanto è grande un char? dipende dall'architettura? (è col segno)
  6. }; ...
  7. const union my_union a[3] = { è la dichiarazione della variabile a, come vettore in stack di 3 elementi di tipo "union my_union" ed è definita costante. Crea problemi che sia costante?
  8. {7022359100883690835LL}, è un numero naturale salvato in a[0]
  9. {8458153864656284020LL}, è un numero naturale salvato in a[1]
  10. {01203272154LL}, è un numero naturale salvato in a[2]. Comincia con lo 0. Che cosa significa?
  11. }; ...
  12. printf("%5s", (a + a[2].c[7]*a[1].i)->c); richiede la stampa, con almeno 5 caratteri eventualmente rimpiazzati da spazi ' ', di che cosa? Per comprendere cosa succede, ricordiamo che, preso i un intero a caso, allora a[i] è come scrivere (a + i); inoltre facciamo notare che a[1].i è dichiarato essere 8458153864656284020LL. Ma è un long long con segno, è quindi negativo? è importante?
  13. return a[2].c[1] % (10LL + a[2].c[2]); restituisce il valore alla sua destra dopo averlo valutato. I cast per numeri così piccoli come il 10LL sono automatici e non generano "warning" sul compilatore. "%" è semplicemente il resto della divisione intera.
  14. } ... FINE
Non dite che non riuscite a rispondere alle domande nemmeno ora! Sono 14 righe di codice dopo tutto...
----

Nessun commento:

Posta un commento