回答編集履歴
1
回答を修正
test
CHANGED
@@ -1,6 +1,30 @@
|
|
1
|
-
経験的に言うと(具体的なアドレスなどはともかく)原因も違いも明確です。例外が発生するかしないかの違いは、コピーのソース側となっている
|
1
|
+
経験的に言うと(具体的なアドレスなどはともかく)原因も違いも明確です。例外が発生するかしないかの違いは、コピーのソース側となっている配列 char szString2[512]; の配置場所(メモリアドレス)に依ります。もう少し言うと、この512バイトのメモリに続く**残り512バイトのメモリ領域の中に、アクセス許可されている(=保護されていない)メモリと、許可されていない(=保護されている)メモリの境界があった**という事です。境界が残り512バイトのメモリ領域の中に無ければクラッシュしません。
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
|
5
|
+
> クラッシュするケースでは保護されているメモリ空間に不正にアクセスしたから、クラッシュした
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
は正しい理解です。念の為に繰り返しますが、アクセス許可されているメモリとは、保護されていないメモリ、ですよ。
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
書き込む先のメモリ領域にバッファオーバーランして書き込んだら、他の用途に使っているメモリ(他の変数)を上書きするので、その後、プログラムが異常動作する事は容易に想像できると思います。
|
14
|
+
|
15
|
+
一方、ご質問の状況は読み出し側のバッファオーバーランです。通常、コピー元のメモリ領域は、読みだす分にはオーバーランアクセスしたって(メモリを書き変えないのだから)問題を起こすことは無いものです。従って、問題なく動作することは少なくありません。というか、読み出しだけならオーバーランアクセスしても何も問題を起こさないでしょう。
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
ところがクラッシュするケースがある、それは例外(**メモリアクセス例外**、OSやCPUによって具体的な呼び名は違うかもしれない)が起こったことを意味します。そうなる理由はただひとつ、残り512バイトのメモリ領域の、ある番地から、アクセスが許可されていない・保護されたメモリだった、ということに尽きます。
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
プログラムが動作する時、動作に必要なメモリを、OSはアクセス可能なメモリ領域として割当てます。現在のCPUは[メモリ管理ユニット](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%A2%E3%83%AA%E7%AE%A1%E7%90%86%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88)、略してMMUを内蔵しており、OSはMMUを制御することで、各プロセスがアクセスできるメモリに制限をかけています。アクセス制限されたメモリ領域をアクセスしようとすれば(プログラムの異常動作であると見做して)例外を発生させ、プログラムを停止するようにしています。それがクラッシュするという事です。
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
そのアクセスを許可したメモリ領域の中に szString1[1024] も szString2[512]も配置されますが、szString2[512] に続く、残りの512バイトがアクセス可能なメモリである保証はありません。アクセスできたなら、それは運が良かったわけです。szString2[512]をメモリのどこに配置するか、なぜ境界の近くに配置されたのか、は**コンパイラと、OSの、両方の事情の合わせ技**のようなもので決まります。お使いのOSとコンパイラ次第なので具体的な説明はできかねますが。
|
4
28
|
|
5
29
|
|
6
30
|
|
@@ -34,28 +58,16 @@
|
|
34
58
|
|
35
59
|
}
|
36
60
|
|
37
|
-
|
38
|
-
|
39
61
|
```
|
40
62
|
|
41
|
-
|
63
|
+
「境界」を超えた時点で「temp = *s; // コピー元のメモリを読む」というメモリアクセス命令が
|
42
64
|
|
43
|
-
|
65
|
+
> 「保護されているメモリに読み取り(中略)操作を行おうとしました・・・」
|
44
66
|
|
45
67
|
|
46
68
|
|
47
|
-
ところがクラッシュするケースがある、それは例外(**メモリアクセス例外**?OSやCPUによって具体的な呼び名は違うかもしれない)が起こったことを意味します。そうなる理由はただひとつ、残り512バイトのメモリ領域の、ある番地から、アクセスが許可されていないメモリだった、ということに尽きます。
|
48
|
-
|
49
|
-
|
69
|
+
即ち不正アクセスになり、例外を起こしたのです。
|
50
70
|
|
51
71
|
|
52
72
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
そのアクセスを許可したメモリ領域の中に szString1[1024] も szString2[512]も配置されますが、szString2[512] に続く、残りの512バイトもアクセス可能なメモリである保証はありません。アクセスできたなら、それは運が良かったわけです。szString2[512]をメモリのどこに配置するかは、**コンパイラと、OSの、両方の事情の合わせ技**のようなもので決まります。
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
こういうことを実感するには、各変数、配列などの**メモリアドレスを確認する**などして、具体的なメモリ上の配置を調べてみるとよいです。さらに、荒っぽい話に聞こえるかもしれませんが、わざとバッファーオーバーランアクセスを起こしてして、どこで例外が起こるか試してみる、なんていうのも良い経験になります。
|
73
|
+
こうしたことを実感するには、各変数、配列などの**メモリアドレスを確認する**などして、具体的なメモリ上の配置を調べてみるとよいです。また変数の配置は、コンパイラ(実際はリンカ)の仕様を調べると共に、コンパイル時に**リンケージマップ情報を出力させて調べる**ことができます。さらに、荒っぽい話に聞こえるかもしれませんが、わざとバッファーオーバーランアクセスを起こしてみて、どこで例外が起こるか試してみる、なんていう調べ方もできます。
|