以下两个程序几乎相似。在这两个程序中,内存不是为null('\0'
)字符分配的。
Ex A:
void main()
{
char *ptr;
ptr = (char *)malloc(2);
strcpy(ptr, "ls");
printf("%s\n",ptr);
system(ptr);
free(ptr);
}
前B:
void main()
{
char ptr[2] = "ls";
system(ptr);
}
1.第一个程序(例如A)正在运行但是我只看到了valgrind工具的错误。
输出
[root@localhost tmp]# valgrind --leak-check=full ./a.out
==8619== Memcheck, a memory error detector
==8619== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==8619== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==8619== Command: ./a.out
==8619==
==8619== Invalid write of size 1
==8619== at 0x400635: main (in /home/gen4linux/Projects/Cprgm/tmp/a.out)
==8619== Address 0x51f2042 is 0 bytes after a block of size 2 alloc'd
==8619== at 0x4C29C4F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==8619== by 0x400627: main (in /home/gen4linux/Projects/Cprgm/tmp/a.out)
==8619==
==8619== Invalid read of size 1
==8619== at 0x4C2CC14: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==8619== by 0x4EA4D3B: puts (in /usr/lib64/libc-2.20.so)
==8619== by 0x400644: main (in /home/gen4linux/Projects/Cprgm/tmp/a.out)
==8619== Address 0x51f2042 is 0 bytes after a block of size 2 alloc'd
==8619== at 0x4C29C4F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==8619== by 0x400627: main (in /home/gen4linux/Projects/Cprgm/tmp/a.out)
==8619==
ls
==8620== Syscall param execve(argv[i]) points to unaddressable byte(s)
==8620== at 0x4EF9537: execve (in /usr/lib64/libc-2.20.so)
==8620== by 0x4E77D18: do_system (in /usr/lib64/libc-2.20.so)
==8620== by 0x400650: main (in /home/gen4linux/Projects/Cprgm/tmp/a.out)
==8620== Address 0x51f2042 is 0 bytes after a block of size 2 alloc'd
==8620== at 0x4C29C4F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==8620== by 0x400627: main (in /home/gen4linux/Projects/Cprgm/tmp/a.out)
==8620==
a.out test37.c
==8619==
==8619== HEAP SUMMARY:
==8619== in use at exit: 0 bytes in 0 blocks
==8619== total heap usage: 1 allocs, 1 frees, 2 bytes allocated
==8619==
==8619== All heap blocks were freed -- no leaks are possible
==8619==
==8619== For counts of detected and suppressed errors, rerun with: -v
==8619== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
2.但第二个不起作用
Ex B
[root@localhost Cprgm]# ./a.out
sh: $'ls%\211\376\177': command not found
为什么会这样?
答案 0 :(得分:3)
TL; DR 这两个代码都会导致undefined behavior。
在第一种情况下
ptr = (char *)malloc(2);
strcpy(ptr, "ls");
你是一个一个人,正如C11
中提到的,章节§7.24.2.3,
strcpy
函数复制s2
指向的字符串(包括终止空值) 字符)到s1
指向的数组中。
因此,s1
的尺寸至少应为strlen(s2)+ 1
。
在第二种情况下
char ptr[2] = "ls";
ptr
没有一个null-terminator,它本质上会导致越界访问,从而再次导致UB。
相关,引用POSIX manual,
[...]如果
command
是 不是空指针,system()
函数应传递字符串command
指向要在其中执行的命令处理器 实施定义的方式; [...]
没有空终结符的char
数组 不被视为字符串 。
话虽如此,有一些想法,
void main()
至少应int main(void)
符合标准。malloc()
and family in C
.。答案 1 :(得分:0)
您在Ex B中使用的数组只有长度2.每当您在数组"ls"
中存储字符串时,会自动添加一个空字符,其中包含' \ 0'所以" ls"当它存储在内存中时将变为l s \0
。大多数算法都是基于这个NULL字符来查找字符串值的字符串长度。
因此,只需声明长度为3的数组,就可以了。
感谢。
答案 2 :(得分:-1)
在第一种情况下:
ptr = (char *)malloc(2);
内存分配给两个字节,但strcpy在此位置存储了3个字节。所以它基本上是一个内存腐败案例,但仍然是" ls"最后使用\ 0的命令存储在使系统命令起作用的位置。
在第二种情况下:
char ptr[2] = "ls";
这项任务本身是错误的,不应该有效。行为未定义。