Debugging C pointers on 64 bit

Giorgos Keramidas keramida at ceid.upatras.gr
Thu Dec 2 16:03:43 EET 2010


On Thu, 02 Dec 2010 12:36:01 +0200, Antonis Christofides <anthony at itia.ntua.gr> wrote:
> Έχω μια shared library γραμμένη σε C, η οποία χρησιμοποιείται από μια
> εφαρμογή Python/Django. Είχε ένα bug με αποτέλεσμα, όταν έτρεχε σε
> σύστημα 64 bit, να χάνει κάποια στιγμή τα άνω 32 bit.

Short story...

------------------------------------------------------------------------
Ψάξε για warnings σχετικά με missing realloc/calloc/malloc() prototypes!
------------------------------------------------------------------------

Long(-ish) story...

Αυτό γίνεται συνήθως όταν ένα πρόγραμμα χρησιμοποιεί casting σε 32-bit
type για το αποτέλεσμα της malloc ή λείπει το prototype της malloc().
Ειδικά στη δεύτερη περίπτωση ο C compiler εισάγει αυτόματα ένα 'stub'
prototype για τη malloc() του τύπου:

       int malloc(...);

Οπότε όταν ένα C source file καλέσει τη malloc() ο compiler θεωρεί ότι
το return value της «χωράει» σε 'int', το οποίο σε 64-bit περιβάλλον
τυχαίνει να είναι 32-bit.

Μια λύση για να έχεις early warning σχετικά με τέτοια bugs είναι να
μεταγλωττίζεις πάντα τον κώδικα με -Wmissing-prototypes και να προσέχεις
ΠΟΛΥ όταν ο μεταγλωττιστής λέει κάτι σαν αυτό:

: keramida at bokos:/home/keramida$ cat -n foo.c
:      1  #include <stdio.h>
:      2
:      3  int
:      4  main(void)
:      5  {
:      6          char *p = malloc(100);
:      7
:      8          p[0] = '\0';
:      9          (void)printf("%s\n", p);
:     10          return 0;
:     11  }
:
: keramida at bokos:/home/keramida$ cc -Wmissing-prototypes foo.c
: foo.c: In function 'main':
: foo.c:6: warning: incompatible implicit declaration of built-in function 'malloc'

Όλα τα 'implicit function declaration' warnings σημαίνουν ότι ο compiler
δεν έχει δει ως εκείνη τη στιγμή 'valid' prototype για τη συγκεκριμένη
function και αυτόματα εισάγει ένα stub declaration της μορφής:

        int function(...);

Αυτό μπορεί να είναι από «αθώο» έως και επικίνδυνο, αφού - όπως μόλις
ανακάλυψες - σε αρχιτεκτονικές 64-bit είναι συχνά πολύ σοβαρό bug το να
μην έχεις ορατό prototype για συναρτήσεις οι οποίες επιστρέφουν τιμές
από pointers.

<pedant-rant>

Θεωρητικά οποιαδήποτε συνάρτηση επιστρέφει pointer-value μπορεί να
εμφανίσει το 'clipping των άνω 32-bit' που είδες.  Το ακόμα πιο
εντυπωσιακό είναι ότι συνήθως το πρόγραμμα είναι «αρκετά τυχερό» και
τυχαίνει ο runtime loader να το φορτώσει σε διεύθυνση που είναι κάτω από
το όριο των 32-bit διευθύνσεων, π.χ. η main() του είναι σε διεύθυνση
όπως η 0x0000000008048470, τα δεδομένα του είναι επίσης σε χαμηλή
διεύθυνση, σαν την 0x0000000028049000 και _κανείς_ δεν καταλαβαίνει ότι
οι pointers γίνονται 'clip' επειδή ΕΤΥΧΕ να μην πειράζει!

Μέχρι τη μέρα που το ίδιο πρόγραμμα το ενσωματώνεις ως dlopen-able
module σε κάποιο server process, και ο runtime linker αποφασίζει να το
φορτώσει σε high-address.  ***CABOOM: OUT OF CHEESE ERROR***

</pedant-rant>



More information about the Linux-greek-users mailing list