Буфер Void неверно ссылается все еще работает - PullRequest
0 голосов
/ 30 августа 2018

Пока я работал над небольшим количеством кода на C, я наткнулся на эту странную ошибку.

Я допустил ошибку в своем коде и написал buf вместо &buf, но это сработало почти просто отлично.

...
void* buf;
int ret;

int fd = open("1", O_CREAT | O_RDWR, 0777);
write(fd, "test\n", 5);
lseek(fd, 0, SEEK_SET);
ret = read(fd, buf, 5);                 // Yes, this should be &buf
printf("Ret: %d Str: %s\n", ret, buf);
---- output ----
Ret: 5 Str: test\n

Этот код работает, и я получаю test\n в моем stdout, даже при том, что у меня должен был быть &buf в моем вызове чтения. Пожалуйста, я знаю, что изменение buf на &buf работает. Дело не в этом.

Вот что не работает:

...
void* buf;
void* blah = "a";     // Using char* still did not work
int ret;

int fd = open("1", O_CREAT | O_RDWR, 0777);
write(fd, "test\n", 5);
lseek(fd, 0, SEEK_SET);
ret = read(fd, buf, 5);
printf("Ret: %d Str: %s\n", ret, buf);
---- output ----
Ret: -1 Str: 1�I��^H��H���PTI��`@

Двоичный файл для файла 1 одинаков для обеих программ. Нет ошибок при записи 1.

  • Почему работает первый фрагмент кода?

  • Как добавление переменной, которая никогда не используется, делает это больше не работа

  • Почему запись в buf, а не &buf сработала?

Вот раздел строк в каждом двоичном файле:

Функциональный код:

0000770: 0100 0200 0000 0000 0000 0000 0000 0000  ................
0000780: 3100 7465 7374 0a00 4572 723a 2025 640a  1.test..Err: %d.
0000790: 0a00 5374 723a 2025 730a 0000 011b 033b  ..Str: %s......;
00007a0: 3000 0000 0500 0000 34fd ffff 7c00 0000  0.......4...|...

Неисправный код:

0000770: 0100 0200 0000 0000 0000 0000 0000 0000  ................
0000780: 6100 3100 7465 7374 0a00 4572 723a 2025  a.1.test..Err: %
0000790: 640a 0a00 5374 723a 2025 730a 0000 0000  d...Str: %s.....
00007a0: 011b 033b 3400 0000 0500 0000 30fd ffff  ...;4.......0...

Спасибо.

1 Ответ

0 голосов
/ 31 августа 2018

(поскольку в комментариях практически невозможно поместить больше строки кода)

Предупреждения от компиляции с -Wall -Wextra:

x.c: In function ‘main’:
x.c:15:25: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘void *’ [-Wformat=]
   printf("Ret: %d Str: %s\n", ret, buf);
                        ~^
                        %p
x.c:14:9: warning: ‘buf’ is used uninitialized in this function [-Wuninitialized]
   ret = read(fd, buf, 5);
         ^~~~~~~~~~~~~~~~

Результаты запуска вашей программы через valgrind:

==6978== Memcheck, a memory error detector
==6978== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6978== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6978== Command: ./a.out
==6978== 
==6978== Syscall param read(buf) contains uninitialised byte(s)
==6978==    at 0x4F4C081: read (read.c:27)
==6978==    by 0x1087BF: main (x.c:14)
==6978== 
==6978== Syscall param read(buf) points to unaddressable byte(s)
==6978==    at 0x4F4C081: read (read.c:27)
==6978==    by 0x1087BF: main (x.c:14)
==6978==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==6978== 
==6978== Conditional jump or move depends on uninitialised value(s)
==6978==    at 0x4E97A41: vfprintf (vfprintf.c:1643)
==6978==    by 0x4EA0F25: printf (printf.c:33)
==6978==    by 0x1087DC: main (x.c:18)
==6978== 
Ret: -1 Str: (null)
==6978== 
==6978== HEAP SUMMARY:
==6978==     in use at exit: 0 bytes in 0 blocks
==6978==   total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==6978== 
==6978== All heap blocks were freed -- no leaks are possible
==6978== 
==6978== For counts of detected and suppressed errors, rerun with: -v
==6978== Use --track-origins=yes to see where uninitialised values come from
==6978== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

Вы должны указать buf, чтобы указывать на действительную память, которую вы имеете право использовать, или вы получаете неопределенное поведение, где может произойти все что угодно. Если вам повезет, ваша программа просто рухнет, но вы не можете на это рассчитывать.

...