2013-11-23 3 views
0

Я действительно не знаю, как назвать этот вопрос, дело в том, что я вижу, как происходит серьезная магия на следующем фрагменте кода.Случайное поведение с добавлением неиспользуемой переменной

Здесь я разместил все соответствующие фрагменты кода и их вывод.

void persist_receipt(Receipt * receipt, char * path) 
{ 
    int i, fd; 
    unsigned char block_fname[64]; 

    fd = open(".receipt", O_RDWR | O_CREAT, 0777); 
    printf("1.fd=%i\n", fd); 
    // Write receipt header 
    write(fd, receipt->hash, 32); 
    write(fd, receipt->name, 256); 
    write(fd, &receipt->size, sizeof(int)); 

    printf("2.fd=%i\n", fd); 

    for(i=0; i<receipt->size; i++) 
    { 
      printf("3.fd=%i\n", fd); 
      sha2hexf(block_fname, receipt->blocks[i].hash); 
      printf("4.fd=%i\n", fd); 
      write(fd, block_fname, 64); 
    } 

    close(fd); 
} 

Теперь позвольте мне показать вам вывод этой части коды:

1.fd=4 
2.fd=4 
3.fd=4 
4.fd=0 
85a2c67fe7f3dc586a0f231d0cc845e7094408769c8391da18d1ed35c7b1cb3c3.fd=0 
4.fd=0 
cbc6286fedb70a703f403e507e4daca7bb4a493cdd4d0f0c1787e56256afe5fd3.fd=0 
4.fd=0 
c364417c27bd887142e6c2de1f7a5b777d604c9df8bcd40bb1a20623b38de82b3.fd=0 

Что происходит с этим случайным дескриптором файла Теряя это значение? Из-за того, что он случайным образом перекодировал его значение в 0, он выводит на консоль хэш, но этого не должно произойти!

Здесь идет интересная часть! Если я просто объявляю новую переменную. Скажем, я объявляю новое целое, как так:

void persist_receipt(Receipt * receipt, char * path) 
{ 
    int i, fd, p; 
    unsigned char block_fname[64]; 

    fd = open(".receipt", O_RDWR | O_CREAT, 0777); 
    printf("1.fd=%i\n", fd); 
    // Write receipt header 
    write(fd, receipt->hash, 32); 
    write(fd, receipt->name, 256); 
    write(fd, &receipt->size, sizeof(int)); 

    printf("2.fd=%i\n", fd); 

    for(i=0; i<receipt->size; i++) 
    { 
      printf("3.fd=%i\n", fd); 
      sha2hexf(block_fname, receipt->blocks[i].hash); 
      printf("4.fd=%i\n", fd); 
      write(fd, block_fname, 64); 
    } 

    close(fd); 
} 

Как вы видите, теперь я объявил переменную «р», давайте скомпилировать и запустить его снова, о мальчик.

1.fd=4 
2.fd=4 
3.fd=4 
4.fd=4 
3.fd=4 
4.fd=4 
3.fd=4 
4.fd=4 
3.fd=4 
4.fd=4 
... 

Я надеюсь, что кто-то может даже объяснить, что происходит за кулисами. Потому что это кажется мне довольно темной магией, прямо здесь. Я подозреваю, что есть что-то подозрительное «sha2hexf», поэтому здесь я также помещаю код, особенно подозрительная часть - это вызов sprintf внутри.

void sha2hexf(unsigned char *outbuf, unsigned char *hash) { 
int i; 
    for (i = 0; i < 32; i++) { 
     sprintf((char*)outbuf, "%.2x", hash[i]); 
     outbuf += 2; 
    } 
} 

Есть ли реальные объяснения?

+0

странное и замечательное поведение может случиться, если вы пишете за пределами своих границ. запустите свою программу через valgrind [и напишите больше кода] – amdixon

ответ

1

Ваша функция sha2hexf довольно явно перекрывает буфер, в который вы проходили. Это нулевое завершение 64-байтовой строки (так что вам нужно не менее 65 байт в буфере).

Часто компилятор выкладывает стек в обратном порядке, так что вы получите:

block_fname (64 bytes) | fd (4 bytes) | i (4 bytes) 

         ^Overflow hits the first byte of 'fd', which zeros it 
          a little-endian architecture (if fd less than 256). 
+0

Спасибо, что показал мне! Какая ошибка. –

1

sha2hexf пишет над границами OutBuf (иначе block_fname), потому что Sprintf присоединяет «\ 0» в каждом цикле (который вам позаботьтесь об увеличении outbuf, но не в последнем запуске цикла!). Таким образом, для заполнения буфера требуется 65 символов.

+0

Большое вам спасибо! Настолько немой, чтобы контролировать это. –

Смежные вопросы