

### 質問

mallocしたときに、確保してない領域へも値を代入できて、出力もできるということに遭遇しています。確保してない領域を使ってそのようなことができる理由はなんなのでしょうか？  
これだと予想しない挙動になって、バグの原因になったりしそうだなと思っていまして。

### 例

下記の場合、mallocでchar4つ分を確保してるので、p[0]からp[3]に書き込めるのは納得です。  
一方で、p[4]とp[5]にも文字を書き込めて、その後の出力でも表示されます。

[code]

    #include <iostream>
    
    using namespace std;
    
    int main () {
        char* p;
        p = (char*)malloc(sizeof(char)*4);
    
        p[0] = 'a';
        p[1] = 'b';
        p[2] = 'c';
        p[3] = 'd';
        // p[4], p[5]にも書き込めてしまう！
        p[4] = 'e';
        p[5] = 'f';
    
        cout << p << endl; // abcdef
        free(p);
    }
    
[/code]


CC BY-SA 4.0
2018-08-15T00:20:20.727
47521
2018-08-15T23:20:46.630
2018-08-15T01:08:37.763
4236
29267
question
c++
mallocしたときに確保してない領域にも書き込める理由


C/C++ が配列サイズのチェックをしていないだけでは?

> バグの原因になったりしそうだな

これはC言語で最初から言われてきた事で、初心者には危険と言われる要因の一つ。  
そういう意味では、Java/C# は安全です。

その一方、 Cソースでは、char a[1]; の宣言しか無く、リンカ等で実体を確保するなんても昔のソースでは散見する。 (malloc()ではないが)


CC BY-SA 4.0
2018-08-15T01:04:20.510
47523
2018-08-15T01:04:20.510
47521
answer


メモリは１バイト単位で管理すると管理コストが高くなりすぎます。そのため最低限`sizeof(void*)`よりも大きな単位で管理されます。  
ある程度のブロック単位で管理されているため、範囲を超えて読み書きできることがあります。

> バグの原因になったりしそう

その通りであり、C言語の弱点を補うためにもC++言語では[`std::array`](https://cpprefjp.github.io/reference/array/array.html)や[`std::vector`](https://cpprefjp.github.io/reference/vector.html)、[`std::string`](https://cpprefjp.github.io/reference/string/basic_string.html)などのクラスが用意されています。これらのクラスはいずれも範囲チェックを行わないC言語互換の[`operator[]`](https://cpprefjp.github.io/reference/vector/op_at.html)だけでなく、範囲チェックを行う[`at()`](https://cpprefjp.github.io/reference/vector/at.html)が用意されています。後者は範囲外にアクセスすると`std::out_of_range`例外が発生します。

* * *

metropolisさんからgccの例が挙げられているので、MicrosoftのVisual C++についても。

Viusal C++コンパイラには[C/C++ Code Analysis](https://docs.microsoft.com/en-
us/visualstudio/code-quality/code-analysis-for-c-cpp-
overview)機能が組み込まれています。これを使用すると質問文のコードはコンパイル時に

[code]

    source.cpp(14): warning C6200: Index '4' is out of valid index range '0' to '3' for non-stack buffer 'p'.
    source.cpp(15): warning C6200: Index '5' is out of valid index range '0' to '3' for non-stack buffer 'p'.
    source.cpp(9): warning C6011: Dereferencing NULL pointer 'p'. 
    source.cpp(14): warning C6386: Buffer overrun while writing to 'p':  the writable size is '4' bytes, but '5' bytes might be written.
    
[/code]

という具合に[C6200警告](https://docs.microsoft.com/en-us/visualstudio/code-
quality/c6200)と[C6386警告](https://docs.microsoft.com/en-us/visualstudio/code-
quality/c6386)が出ます。なお9行目の[C6011警告](https://docs.microsoft.com/en-
us/visualstudio/code-quality/c6011)は`malloc`がメモリ確保に失敗し`NULL`を返す可能性を指摘するものです。

またDebugビルドでは[`malloc`](https://docs.microsoft.com/en-us/cpp/c-runtime-
library/reference/malloc)は[`_malloc_dbg`](https://docs.microsoft.com/en-
us/cpp/c-runtime-library/reference/malloc-
dbg)に切り替えられます。`_malloc_dbg`は確保したメモリを`0xCD`で初期化してから返すため、

[code]

     cout << p << endl; // abcdef
    
[/code]

この行で正しく出力できずに止まります。（文字列終端を表す`\0`が見つからないため）  
もちろんそれだけでなく、`_GLIBCXX_DEBUG`とに相当する機能もあり`free`の際に範囲外アクセスを検出しエラー報告します。


CC BY-SA 4.0
2018-08-15T01:05:47.307
47524
2018-08-15T23:20:46.630
2018-08-15T23:20:46.630
4236
4236
47521
answer


ちなみに、最近の gcc ではコンパイル時に `-D_GLIBCXX_DEBUG` オプションを指定しておくと、実行時に boudary check
を行うコードを追加してくれます。

[code]

    ====
    x.cc
    ====
    
    #include <iostream>
    #include <iterator>
    #include <array>
    
    int main () {
      std::array<int, 4> p;
    
      p[0] = 'a'; p[1] = 'b'; p[2] = 'c'; p[3] = 'd'; p[4] = 'e'; p[5] = 'f';
    
      std::copy(p.begin(), p.begin()+6, std::ostream_iterator<char>(std::cout));
      std::cout << "\n";
    }
    
    $ g++ --version
    g++ (Ubuntu 7.3.0-16ubuntu3) 7.3.0
    
    $ g++ -o x x.cc && ./x
    abcdef
    
    ## Define _GLIBCXX_DEBUG
    $ g++ -D_GLIBCXX_DEBUG -o x x.cc && ./x
    /usr/include/c++/7/debug/array:155:
    Error: attempt to subscript container with out-of-bounds index 4, but 
    container only holds 4 elements.
    
    Objects involved in the operation:
        sequence "this" @ 0x0x7fff151c6a10 {
          type = std::__debug::array<int, 4ul>;
        }
    Aborted (core dumped)
    
[/code]

その他に、[cppcheck - tool for static C/C++ code
analysis](https://sourceforge.net/p/cppcheck/wiki/Home/) というツールがあります。

[code]

    $ cppcheck x.cc
    Checking x.cc ...
    [x.cc:10]: (error) Array 'p[4]' accessed at index 4, which is out of bounds.
    [x.cc:10]: (error) Array 'p[4]' accessed at index 5, which is out of bounds.
    
[/code]


CC BY-SA 4.0
2018-08-15T03:25:46.177
47529
2018-08-15T03:33:46.257
2018-08-15T03:33:46.257
47521
answer