2008-02-02

_ 日常

本当は朝のうちに行くつもりだったのに、 結局夕方になってから、 No Country for Old Men を観に行った。

原作の評判は聞いていたのだが、映画も割と評判良さそうだったので、 見に行く気になった。 少々オーソドックスなストーリーと言えなくもないが、 映画の世界にどっぷり浸かれて、かなり良かったー。 ハリウッドじゃ、最近はゲームやコミックの映画化が多くて、 どうしても勧善懲悪な内容になりがちで、 少々食傷気味だっただけに、 こういう善対悪にならない構図は非常によろしい。 一応善に限りなく近い存在であるシェリフは常に事件から一歩退いた位置にいるし、 観客の多くが一見善と捉えがちな主役は所詮こそ泥だ。 どっちの方がより恐ろしい存在か程度の違いしかないと言っていい。

たぶん、この映画で最も重要なテーマは自分の運命の決め方なんだと思う。 われわれは常に何かを選択しながら生きていて、 その選択を意識しようがしまいが、常に選択は行われ、 それで人生が決まっていく。 決めるのは結局コインなのか本人なのか、とても興味深い質問だと思った。

いつか原作も読んでみよう。

_ mallocの返り値は確認せねばならない理由

ちょっと浦島な感がしないでもないが、 今日たまたま思い出すきっかけがあったので、書いておく。 以前、メモリ確保の失敗に関する考察 でメモリ保護がきちんとしてないOSの話は書いたのだが、 メモリ保護がちゃんとしているOSの話を書き忘れていたのだ。

一部の人々はfailmallocは無意味であると断定する根拠として、 Linuxとかだと、mallocは常に成功し、メモリが足らなくなったら OOM Killer でぶち殺されるだけなので、対処の意味がないというものであった。

これがいかに間違っているか、極めて恣意的なコードで実証してみる。

#include <stdio.h>
#include <stdlib.h>

int
main (void)
{
  char a = 'a';
  size_t size = (size_t) &a;
  char *p;

  p = (char *) malloc (size + 1);
  p[size] = 'b';

  printf ("%c\n", a);
  return 0;
}

32ビットのx86なら、a ではなく、 b が表示される。 Segmentation faultなんか、もちろん起きない。 たぶん、他の32ビットCPUでも再現すると思うが、試してはいない。

釈迦に説法な相手が多そうではあるが、 念のために解説すると、 大抵のOSではスタックのアドレス位置はかなり高い位置に設定される。 最近はスタックを攻撃されるのを防ぐために位置が変動するので、 いろいろとふざけたテストがやりにくくなって困るが、 x86上でLinuxを動かしているなら、スタックは常に 0xb0000000 以降になるはずだ。

そうすると、このスタック位置程度のメモリを動的に確保しようとしたとき、常に失敗せざるを得ない。 なぜなら、そこまで巨大なメモリを連続的にアドレス空間に配置することが不可能だからだ。 いくらメモリの実際の確保を遅延させるとはいっても、 それはメモリ効率のためにやっているだけで、 初めから駄目だと分かっているものまで後回しにする必要はない。 よって、mallocはこういう場合にはきちんとNULLを返すものなのである。 返さない実装があったら、それはかなりまずい実装だと思う。

結果的に、NULLが返されて、そのまま使われて、それがたまたま有効な位置を指しているため、スタックが上書きされて、お終いである。

これが極めて恣意的な例であることは認めるが、ポインタを演算要素に使うのは何ら珍しいことではない。 こういう事態が発生する可能性はゼロじゃないからには、 安全側に倒して、ちゃんと確認するのが真っ当なプログラマってもんだ。

別に私はメモリが足らない時にも何とか頑張れと言っているわけじゃない。 死ぬなら死ぬで、きれいに死ねと言っているだけである。 Exceptional C++ (Moreの方だったっけ?)にもOOM Killerとメモリ管理の話はちょっぴり言及されているが、 そこでも確認しなくていいなんて、一言も書いてない。 サッターが言っているのは、大体においてどうしようもないので、 さっさと死んだ方がいいということだけで、 死ななくていいとか、確認しないでいいとか、誰も言ってない。 C++だとnew使う限り、例外を起きるから、デフォルト通りに死ねばいいってだけのこと。

ちなみに、GNUでは

void *xmalloc (size_t size)
{
  void *ptr;
  ptr = malloc (size);
  if (! ptr)
    abort ();
  return ptr;
}

みたいなxmallocを用意しておいて、いつもチェックしないでも済むようにしていることが多々ある。 救いようがないなら、悪くない手だ。

[]

トップ «前の日記(2008-01-31) 最新 次の日記(2008-03-01)»