2014-04-21 4 views
0

Le programme C suivant a une autre sortie si j'écrire quelque chose dans ma fonction principale et je ne comprends vraiment pas pourquoi ..non déterministe programme C trivial

Si nous commentons la déclaration myVariable, tout va bien et nous obtenir le résultat attendu (en appliquant 3 fois SHA256 à 0x12345678). Mais, si j'écris quelque chose dans la fonction principale, alors la sortie change et ne prend pas la valeur attendue.

Comment est-il possible que la déclaration d'une nouvelle variable affecte cela?

Le code (precompute.c):

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

#include <openssl/sha.h> 

unsigned char* sha256_3(int* input) { 
    char *s = (char*)input; 
    unsigned char *d = SHA256(s, strlen(s), 0); 
    d = SHA256(d, strlen(d), 0); 
    d = SHA256(d, strlen(d), 0); 

    return d; 
} 

void print_hash(unsigned char* d) { 
    int i; 
    for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 
     printf("%02x", d[i]); 
    putchar('\n'); 
} 

int main(int argc, const char * argv[]) { 
    int A = 0x12345678; 
    unsigned char *B = sha256_3(&A); 
    print_hash(B); 

    // int myVariable = 3; // Uncomment this line and recompile to see the difference 

    return EXIT_SUCCESS; 
} 

Le Makefile:

CC=gcc 
CFLAGS=-c 
LDFLAGS=-lssl -lcrypto 
SOURCES=precompute.c 
OBJECTS=$(SOURCES:.c=.o) 
EXECUTABLE=hello 

all: $(SOURCES) $(EXECUTABLE) 

$(EXECUTABLE): $(OBJECTS) 
    $(CC) $(OBJECTS) -o [email protected] $(LDFLAGS) 

.c .o: 
    $(CC) $(CFLAGS) $< -o [email protected] 

clean: 
    rm -rf *o hello 

La sortie attendue (déclaration de myVariable a commenté):

8f3d8f8c5eff23dc137762220cf24f140b7a1b804cc20442617 42fd73286c169

Une sortie inattendue (déclaration de myVariable décommentée):

663e9571f713f83b19c913938e2947c8fc0a7072d1fc442385857c456c43295b

Merci beaucoup!

+3

vous n'avez jamais alloué d'espace. vous écrivez juste à la mémoire aléatoire (UB) –

+4

aussi à peu près aucune de ces lignes de C n'a de sens. lire et écrire dans la même mémoire, en écrivant à plusieurs reprises aux pointeurs comme s'ils étaient des primitifs. Cela ne semble pas réductible, il suffit de recommencer. –

+5

La longueur d'une chaîne C est déterminée par le caractère nul final, donc 'strlen (s)' est UB, car 's' ne fait que pointer vers un segment de mémoire – Dabo

Répondre

0

En analysant cet extrait:

char *s = (char*)input; 
unsigned char *d = SHA256(s, strlen(s), 0); 

Peu d'erreurs sont visibles. input est à l'origine un pointeur vers un int (défini par la ligne avec int A). Un int a généralement 4 octets. Lorsque vous lancez un pointeur sur char *, c'est bien, vous pointez sur une mémoire allouée de 4 octets. Mais, toutes les fonctions dans string.h, y compris strlen(), s'appuient sur la présence d'un caractère NUL ('\ 0') à la fin de la chaîne. Fondamentalement, strlen() compte combien de caractères sont là jusqu'à NUL. Comme vous n'avez pas de caractère NUL après ces 4 octets de l'int, le résultat est basé sur ce qui peut être trouvé dans la mémoire (quelque part peut être un 0 en mémoire, qui est la valeur du caractère NUL, et strlen s'arrête) . Maintenant, pour le réparer, vous avez 2 solutions possibles: soit créer une chaîne depuis le début avec les valeurs dont vous avez besoin, ou, en fonction sha256_3, créer une chaîne de 5 octets, copier les 4 de l'int fourni en tant que paramètre et affecter NUL à la dernière.

Questions connexes