2017-05-24 5 views
0

次の2つのプログラムはほぼ同じです。 2つのプログラムでは、ヌル('\0')文字にメモリが割り当てられません。char配列とcharポインタの ' 0'にメモリが割り当てられていない場合はどうですか?

例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のツールでエラーを見てきました。これが起こる理由第1 2.But

出力

[[email protected] 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) 

例B

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

が動作していませんか?

+8

両方が未定義の動作です。つまり、何かが起こる可能性があり、一貫している必要はありません。 –

+3

これはサイドノートです:(char *)型キャストは 'malloc'では必要ありません。 –

答えて

0

例Bで使用した配列の長さは2です。文字列を配列"ls"に格納するたびにnull文字が '\ 0'で自動的に追加されるため、lsは格納時にl s \0になります。メモリ内にある。アルゴリズムのほとんどは、文字列の値の文字列の長さを見つけるためにこのNULL文字に基づいています。

長さ3の配列を宣言するだけでよいです。

ありがとうございました。最初のケースで

+2

ところで、それは 'NUL 'で、' NULL'ではなく、これら2つは非常に異なるものです。 –

+0

ありがとうございます。私はその違いを知っている。私はそれの後に "文字"を言及しています。これは\ 0です。もしNULではなくNULLと言っていたら、混乱してしまいました。これはポインタであり、文字である –

-1

ptr = (char *)malloc(2); 

メモリは、2バイトのために割り当てられたが、strcpyのこの位置に3つのバイトが格納されます。だから、基本的にメモリ破損の場合ですが、最後に\ 0をつけた "ls"コマンドは、システムコマンドを動作させる場所に格納されています。

後者の場合:

char ptr[2] = "ls"; 

この割り当て自体が間違っていると動作するようになっていません。振る舞いは未定義です。

+2

2番目のケースとして引用した**は**定義されており、char配列を[l、s]( '\ 0'なし)に初期化します**割り当てではありません**。この配列を文字列として使用するとUBが後で発生します。なぜなら、終端の '\ 0 'がないからです。 –

+1

「この割り当て自体は間違っています」... -1、私のdownvote。 –

+0

大丈夫です。あなたは正しいです。この代入文は有効です。 – DineshB

3

TL; DR両方のコードが原因でundefined behaviorが発生します。最初のケースで

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

    あなたはオフずつ、C11で述べたように、章§7.24.2です。図3に示すように、文字列が配列に(終了ヌル 文字を含む)s2によって指さ

    strcpy関数コピーがs1によって指されます。

    ので、サイズs1のは、少なくともstrlen(s2)+ 1でなければなりません。

  • 第2のケースで

    char ptr[2] = "ls"; 
    

    ptr本質的には、再びUBの原因となるバウンドアクセスのうち、原因ヌル・ターミネータを持っていません。

    POSIX manualを引用関連、

    [...] commandがNULLポインタ ない場合、system()関数を通過しなければならないストリング があると、そのコマンドプロセッサにcommandによって指さ実装定義の方法で で実行されます。 [...]

    char配列は、代わりにヌル・ターミネータなし、文字列とはみなされません。


void main()は少なくとも標準に準拠するようにint main(void)する必要があり、ホストされた環境のために

関連する問題