【问题标题】:Void Buffer Incorrectly Referenced Still Works错误引用的无效缓冲区仍然有效
【发布时间】:2018-08-30 15:49:29
【问题描述】:

在编写一些 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,即使我的读取调用中应该有&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没有错误。

  • 为什么第一个代码sn-p有效?

  • 添加一个从未使用过的变量如何使其不再 工作吗?

  • 为什么首先写信给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...

谢谢。

【问题讨论】:

  • 除非您没有显示更多代码,否则这些“工作”都不会,因为您的 buf 指针实际上并没有指向任何有意义的东西,这意味着尝试读取它是未定义的并且任何事情都可能发生。你没有收到警告吗?如果您没有使用一组体面的警告进行编译(-Wall -Wextra 用于 gcc 和 clang(并且您还应该添加 Asan (-fsanitize=address))),请这样做,并注意 给他们..
  • 不,这不应该是&buf,除非你试图使该变量指向从文件中读取的地址(你不是,也不应该这样做)
  • 嗨,肖恩。我删除的唯一代码是int main() { ... }。我没有从 void 指针中读取。我正在读取文件1 并将其放入buf,这就是正在做的事情和我想要做的事情。至于那些警告,不,除了在我的 printf 语句中使用-Wall -Wextra 标签设置void*%s 之外,我没有收到任何警告。 void* buf 也是可识别的读取输入,如here 所示。这就是我遵循的地方。编辑:请注意读取函数的返回值。第一次没有错误。

标签: linux system-calls void dereference


【解决方案1】:

(因为在 cmets 中放置多于一行代码几乎是不可能的)

使用-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 指向您有权使用的有效内存,否则您将获得可能发生任何事情的未定义行为。如果你幸运的话,它只会让你的程序崩溃,但你不能指望它。

【讨论】:

    猜你喜欢
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 2012-06-09
    • 2016-07-08
    • 2021-01-31
    • 1970-01-01
    相关资源
    最近更新 更多