0

The following two programs are almost similar. In the two programs, memory is not allocated for null('\0') character.

Ex A:

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

Ex 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.

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

Ex B

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

Why this happens?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Akaash
  • 61
  • 1
  • 8

3 Answers3

3

TL;DR both the codes cause undefined behavior.

  • In first case

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

    you're off-by-one, as mentioned in C11, chapter §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.

    So, the size of s1 should at least be 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.

    Related, quoting the POSIX manual,

    [...] 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; [...]

    A char array, without a null-terminator in place, is not considered a string.


Having said that, there are a few sggestions,

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0

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 l s \0 when it is stored in memory. Most of the algorithm are based on this NULL character to find the length of string of value of string.

So just declare your array of length 3 and you will be good to go.

Thanks.

Vishwajeet Vishu
  • 492
  • 3
  • 16
  • 2
    BTW: it's `NUL` and not `NULL`, these two are very different things. – Jabberwocky May 24 '17 at 05:35
  • Thank u. I know the difference. I have mentioned "character" after it. which is \0. If I could have just said NULL and not NUL then it wold have created confusion. which is pointer and which is character – Vishwajeet Vishu May 24 '17 at 06:15
-1

In the first case:

ptr = (char *)malloc(2);

memory is allocated for two bytes but strcpy stored 3 bytes at this location. 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.

In the second case:

char ptr[2] = "ls";

This assignment itself is wrong and is not supposed to work. Behaviour is undefined.

DineshB
  • 37
  • 2
  • 2
    What you cite as second case **is** defined, it initializes the char array to [l,s] (without `\0`), it is **not** an assignment. UB occurs later when using this array as a string, because the terminating `\0` is missing. –  May 24 '17 at 06:02
  • 1
    `This assignment itself is wrong`... -1, my downvote. – Sourav Ghosh May 24 '17 at 06:05