如果内存未分配给' \ 0'在char数组和char指针中

时间:2017-05-24 04:49:00

标签: c

以下两个程序几乎相似。在这两个程序中,内存不是为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

为什么会这样?

3 个答案:

答案 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数组 不被视为字符串

话虽如此,有一些想法,

答案 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";

这项任务本身是错误的,不应该有效。行为未定义。