Τι εκτυπώνει το πρόγραμμα;

#include <stdio.h>

int calculate(void);

int calculate(void)
{
int i;
int p[9];

for ( i = 0; i <= 3; i++ ) if (!(sizeof(int)%4))p[i*6+2]+=15; else p[i*3+2]+=16;
}

int main(int argc, char** argv)
{
calculate();
printf(“Hello, World!\n”);

return 0;
}

Τι εκτυπώνει το παραπάνω πρόγραμμα;
Δουλεύει τουλάχιστον σε Linux/i386.

Ενημέρωση: Λειτουργεί και για x86_64.

11 comments

  • Δημήτρης Καμενόπουλος

    Εντάξει δε χάθηκε και ο κόσμος για 2-3 θέσεις εκτός ορίου 🙂

    Το πιο πιθανό είναι ότι ο compiler δεσμεύει χώρο στη μνήμη σε τίποτα πολλαπλάσια του 2, ή κάτι ανάλογο. Για να κάνει segfault πρέπει να διαμαρτυρηθεί το λειτουργικό, δηλαδή να πειραχθεί χώρος της μνήμης που δεν ανήκει στο πρόγραμμα.

  • Simos

    Αν έχεις Linux/i386, δοκίμασε να το εκτελέσεις και ανέφερε το αποτέλεσμα.

    Για να βοηθήσω, τυπικές απαντήσεις είναι α) δίνει σφάλμα κατάτμησης, β) εκτυπώνει “Hello, World!” [αλλαγή γραμμής] ή γ) κάνει κάτι άλλο, ίσως παράξενο, οπότε προσπαθούμε να εξηγήσουμε γιατί το κάνει.

    Προσωπικά με ενδιαφέρει η περίπτωση (γ). 😉

  • Δημήτρης Καμενόπουλος

    Μα το τέσταρα, σε SuSE 9.3 (gcc με default options). Τυπώνει “Hello world”. Γι’ αυτό κατέληξα ότι δε χάθηκε ο κόσμος. 🙂

  • Simos

    Σίγουρα εμφανίζει Hello world;

    Μόλις δοκίμασα σε Ubuntu (gcc 4.0.2, i686) και εμφανίζει αυτό που θέλω. Αυτό που κάνει είναι να τερματίζει η εφαρμογή χωρίς να εμφανίζει κανένα μήνυμα.

  • fade

    Ω, δεν έπρεπε να το δω αυτό 3:30 το βράδυ…

    Το τελευταίο iteration του for loop προφανώς πηγαίνει και αυξάνει κάποια θέση της στοίβας κατά 16. Αυτή η θέση είναι 3 words μετά το τέλος του p[]. Τι είναι τώρα εκεί, είναι ένα καλό ερώτημα.

    Απ’όσο θυμάμαι σε αυτήν την θέση πρέπει να είναι η return address της calculate(). Αν την αυξάνεις κατά 16 bytes == 4 words υπάρχει μία καλή περίπτωση να επιστρέψεις αμέσως μετά την κλήση της printf, οπότε δεν εκτυπώνεις τίποτα.

    Βέβαια το πόσες εντολές παρεμβάλλονται ανάμεσα στην αρχική return address και την κλήση της printf πρέπει να είναι τελειώς implementation depended, οπότε δεν μπορείς να βασίζεσαι σε αυτό…

    Ίσως με μεγαλύτερη αύξηση (πχ 128 αντί για 16) και με αρκετή σαβούρα κώδικα ανάμεσα στην printf και το return της main, θα μπορούσε να δουλέψει σίγουρα.

  • Γιώργος Κεραμίδας

    Το πως και τι θα γίνει εξαρτάται πολύ από την οργάνωση της runtime στοίβας. Μπορεί να μη γίνει τίποτα… μπορεί να γίνει overwrite η διεύθυνση επιστροφής της calculate() και να επιστρέψει μετά την printf()… μπορεί να πετάξουν πορτοκαλί ρινικοί δαίμονες ντυμένοι με ασπρόμαυρες στολές πιερότου από τη μύτη σας και να δείτε σε όραμα τον Νοστράδαμο να πίνει φραπέ με τον Μακιαβέλι, τον Μάρξ και τον Πλάτωνα.

    Σύμφωνα με το C standard, η προσπέλαση θέσεων μνήμης μετά το τέλος ενός πίνακα προκαλεί “undefined behavior”. Τι θα είναι αυτό, είναι… uhm, “undefined”.

  • mperedim

    μπορεί να πετάξουν πορτοκαλί ρινικοί δαίμονες ντυμένοι με ασπρόμαυρες στολές πιερότου από τη μύτη σας και να δείτε σε όραμα τον Νοστράδαμο να πίνει φραπέ με τον Μακιαβέλι, τον Μάρξ και τον Πλάτωνα

    Κάποιος κλέβει ναρκωτικά από τον Ρικούδη μου φαίνεται 😛

  • Δημήτρης Καμενόπουλος

    > Τι θα είναι αυτό, είναι… uhm, “undefined”

    Σημαίνει ότι το πρότυπο δεν ορίζει κάποια συγκεκριμένη συμπεριφορά και η υλοποίηση είναι απολύτως ελεύθερη να κάνει ό,τι θέλει (συνήθως τον Κινέζο με αποτέλεσμα το πρόγραμμα να τα παίξει λίγο αργότερα χωρίς να έχεις ιδέα γιατί).

    @simos ναι σίγουρα, αλλά εγώ έχω gcc 3.3.

  • Simos

    Ευχαριστώ όλους για τα σχόλια.

    Fade, πράγματι έτσι είναι, βρήκες την απάντηση!

    Γιώργο, έχεις επηρεαστεί από την lgu και παρέσυρες και τον mperedim :).

    Πράγματι, το τι υπάρχει εκτός των συνόρων ενός τύπου δεδομένου είναι πληροφορία μη ορισμένη (undefined), σε τυπικές υλοποιήσεις μπορείς να χρησιμοποιήσεις τα σχετικά εργαλεία για να δεις.

    Σε επόμενη εγγραφή στο ιστολόγιό μου θα περιγράψω τις λεπτομέρειες.

  • Γιώργος Κεραμίδας

    Σε amd64 που έτρεξα εγώ το πρόγραμμα, τα σχετικά μεγέθη των stack pointers είναι λίιιιιιγο διαφορετικά, οπότε πρέπει να παίξεις λίγο παραπάνω για να πετύχεις το σωστό stack byte.

    Δεν έχω επηρεαστεί από την lgu όμως. Από το comp.lang.c έχω επηρεαστεί, που οι “nasal demons” είναι κλασικό αστείο πλέον 🙂

  • Simos

    @Γιώργος: Σε AMD64 είναι sizeof(int)==8; Με objdump -d μπορείς να δεις τί διαφορά υπάρχει. Για παράδειγμα, είναι p[9]==i; μπορείς να δοκιμάσεις άλλες τιμές για την συνάρτηση επιστροφής, όπως p[11] ή μεγαλύτερη τιμή. Έπρεπε πάντως να δουλέψει διότι χρησιμοποιώ int…

    Για το σχόλιο για την lgu, αναφερόμουν στην συνήθεια που υπάρχει για κάθε θέμα να γίνονται άσχετα σχόλια και η προσοχή να πάει αλλού. Έτσι δεν επιλύεται κανένα θέμα και χάνουν όλοι πια το ενδιαφέρον. Είναι κάτι σαν attention deficit disorder… 🙁

    Έκανα νέα εγγραφή στο ιστολόγιό μου για το θέμα με την C. Δείτε
    http://simos.info/blog/?p=422

Leave a Reply

%d bloggers like this: