简体   繁体   English

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

[英]What if memory is not allocated to '\0' in char array and char pointer

The following two programs are almost similar. 以下两个程序几乎相似。 In the two programs, memory is not allocated for null( '\\0' ) character. 在这两个程序中,未为null( '\\0' )字符分配内存。

Ex A: 例A:

void main()
{
        char *ptr;
        ptr = (char *)malloc(2);
        strcpy(ptr, "ls");
        printf("%s\n",ptr);
        system(ptr);
        free(ptr);
}

Ex B: 前B:

void main()
{
        char ptr[2] = "ls"; 
        system(ptr);
}

1.The first program(Ex. A) is working But i have seen error only with valgrind tool. 1.第一个程序(示例A)正在工作,但是我只看到valgrind工具出错。

output 输出

[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.But the second one is not working 2.但是第二个不起作用

Ex B 前乙

[root@localhost Cprgm]# ./a.out 
sh: $'ls%\211\376\177': command not found

Why this happens? 为什么会这样?

TL;DR both the codes cause undefined behavior . TL; DR这两个代码都导致未定义的行为

  • In first case 在第一种情况下

     ptr = (char *)malloc(2); strcpy(ptr, "ls"); 

    you're off-by-one, as mentioned in C11 , chapter §7.24.2.3, 就像C11第7.24.2.3章中提到的,

    The strcpy function copies the string pointed to by s2 (including the terminating null character) into the array pointed to by s1 . strcpy函数将s2指向的字符串(包括终止空字符)复制到s1指向的数组中。

    So, the size of s1 should at least be strlen(s2)+ 1 . 因此, s1大小至少应为strlen(s2)+ 1

  • In second case 在第二种情况下

     char ptr[2] = "ls"; 

    ptr does not have a null-terminator which in essence, causes out of bound access which again causes UB. ptr没有空终止符,从本质上讲,它会导致超出范围的访问,从而再次导致UB。

    Related, quoting the POSIX manual , 相关,引用POSIX手册

    [...] If command is not a null pointer, the system() function shall pass the string pointed to by command to that command processor to be executed in an implementation-defined manner; [...]如果command不是空指针,则system()函数必须将command指向的字符串传递给该命令处理器,以便以实现定义的方式执行; [...] [...]

    A char array, without a null-terminator in place, is not considered a string . 没有放置空终止符的char数组不视为string


Having said that, there are a few sggestions, 话虽如此,但有一些建议,

The array that you used in Ex B is only of length 2. whenever you store a string in a array "ls" automatically a null character is added with is '\\0' so "ls" will become ls \\0 when it is stored in memory. 在示例B中使用的数组只有长度2。每当将字符串存储在数组"ls"系统会自动向其添加一个空字符'\\ 0',因此存储时“ ls”将变为ls \\0在记忆中。 Most of the algorithm are based on this NULL character to find the length of string of value of string. 大多数算法都是基于此NULL字符来查找string的值的字符串长度。

So just declare your array of length 3 and you will be good to go. 因此,只需声明长度为3的数组,就可以了。

Thanks. 谢谢。

In the first case: 在第一种情况下:

ptr = (char *)malloc(2);

memory is allocated for two bytes but strcpy stored 3 bytes at this location. 内存分配了两个字节,但strcpy在此位置存储了3个字节。 So it is basically a memory corruption case but still "ls" command with \\0 at the end is stored at the location which makes system command to work. 因此,这基本上是一个内存损坏的情况,但是仍然以使系统命令起作用的位置存储以\\ 0结尾的“ ls”命令。

In the second case: 在第二种情况下:

char ptr[2] = "ls";

This assignment itself is wrong and is not supposed to work. 此分配本身是错误的,不应起作用。 Behaviour is undefined. 行为是不确定的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM