2012/04/02
ご近所さん
我が家の近所には同じ年頃の子供を持つ家庭が偶然多く暮らしているので、 非常に楽しく素敵なご近所つきあいをさせて頂いている。
ご近所さんのうちの1家族は震災の随分前に福島から引っ越してきたのだが、 同じ年の子供がいたのでとっても仲良くさせて頂いていた。 いつも仲が良いとっても素敵な家族で子供達も凄く素直で優しい良い子達だった。 その家族が仕事の都合で先日引っ越してしまったのだが、 引っ越した先が京都だという事を訊いて何とも言えない気分になった。
横浜を経由しているとは言え福島から来た家族がいじめられたりしないだろうか? 今思うとその家族が乗っている自動車のナンバーは福島ナンバーだったんだけど、 特に子供達がいじめや仲間はずれになっていないだろうか。 がれき受け入れの記事を読んで人ごとながら胸が痛くなる思いで一杯だ。
京都に限らず福島からの人々が虐められ迫害されているという記事や
ニュースを見る度に本当に心が痛くなる。
彼ら・彼女らこそが一番の被害者なのに、
一番傷付き疲れ果て様々な迷惑や不便を味わっているのに、
何故そんな仕打ちを受けなければならないのだろうか。
「自分たちの子供のため」などと言って思考停止していないで、
足りないなら足りないなりにその頭で考えて欲しい。
本当に自分の子供の事を考えているのであれば、
親として自分の子供に見せるべきはどういう姿なのか、を。
よく言われているが子供は親の背中を見て育つのだ。
理由も根拠もなく他者を差別し迫害し虐げる親のその姿をね。
2012/02/22
C 中級者が意外と陥りやすいワナ
ある程度プログラミングにも慣れてきて
言語仕様もそこそこ理解した中級者にとって
意外と陥りやすくセキュリティホールの温床になりがちなワナ。
勿論オンラインマニュアルにも仕様として明記してあるのだが、
直感とは反する仕様のなので特に中級者にこれらのミスが多い気がする。
- strncpy(3) は ``\0'' 終端してくれない場合がある
- strncat(3) のサイズ指定はコピー先のサイズを指定するのではない
- snprintf(3) は領域が重なってはいけない
strcpy(3) はバッファオーバーフローの危険性があるから
strncpy(3) を利用する様によく言われるが、
ここにワナが潜んでいる。
strncpy(dst, src, len);
とした時に
文字列 src の長さが len バイト未満の場合は
dst は ``\0'' で終端される。
終端どころか dst の残り領域は何故か
全て ``\0'' が詰められるという
無駄とも思われる謎仕様。
ところが文字列 src の長さが len バイト以上の場合、
dst に len バイトだけコピーするという
memmove(3) 同様の動作となってしまい、
dst が ``\0'' で終端されない。
文字列操作の関数なのにも関わらず得られた結果が
文字列として扱えないという不思議な仕様なのだ。
snprintf(3) などの様に
len - 1 バイトを dst にコピーして
``\0'' で終端される事を期待していると
痛い目に遭ってしまう。
文字列操作関数なので、
殆んどの場合 ``\0'' 終端が必要になると思うので
以下の様な処理が代替になる。
strncpy(dst, src, sizeof(dst) - 1); *(dst + sizeof(dst) - 1) = '\0';
strcat(3) も同様にバッファオーバーフローの危険性があるので
strncat(3) を利用する様によく言われるが、
ここにもワナが潜んでいる。
strncat(dst, src, len);
とした時の len はコピーする src の長さであって、
前述の strncpy(3) や snprintf(3)の様に
dst のサイズ指定ではない
ここで dst のサイズのつもりで len を指定すると
バッファオーバーフローの原因になってしまう。
殆んどの場合は dst の最大値が重要になると思うので
以下の処理が代替になる。
strncat(dst, src, sizeof(dst) - strlen(src) - 1);
前述した通りに使いやすいとは言いづらい strncpy(3) や
strncat(3) の代用として、
コピー先のサイズ指定が直感的な
snprintf(3) を利用する場合も多いと思うが、
strncat(dst, src, len) の置き換えとして
snprintf(dst, sizeof(dst), "%s%s", dst, src);
とすると正しく動作しない(結果は処理系依存になる)。
ANSI X3.159-1989 (ANSI C) や ISO/IEC 9899:1999 (ISO C99) 、
IEEE Std 1003.1-1988 (POSIX.1) 等をざっと探したけど
関連する記述は見つける事はできなかったが、
snprintf(3) は重なった領域では正しく動作しない様だ。
2012/02/10
2012/01/11
OWC SSD for MacBook Air
MacBook Air Late 2010 のディスク容量が逼迫してきていたので、
折からの円高に後押しされ(た事にして)
OWC の Mercury Aura Pro Express を購入した。
MacBook Air はその薄さ故か、
通常の HDD タイプの SSD ではなく
独自な専用設計の SSD モジュールを使用している。
そのため汎用的な HDD タイプの SSD は利用できず、
Apple からは交換用の SSD モジュールは発売されていないのだが、
OWC では互換性のある交換用の SSD モジュールを販売しているので、
それらの SSD モジュールのうち 240GB のものを購入した。
国内でも OWC の SSD モジュールを扱っている販売店はあるのだろうが、
折から円高でもあるので OWC のサイトから普通に購入する。
取り外した純正の SSD モジュールを外付けディスクとして流用するための
インタフェイスボックスを同時購入すると多少割引になるとの事なので、
折角なのでそれも同時に購入する事にする。
大体 1 ドル 88 円弱の換算となったので
送料を払った上でも国内で購入するよりも随分と格安にて購入できた。
交換自体は非常に簡単なので困ったり迷ったりする事もなく順調に作業完了。
OWC の Web Site でも
機種毎の交換作業の動画 が公開されていので
一通り閲覧しておけば作業の手順もつかめるので良いだろう。
- TimeMachineを利用したバックアップ
- 今回は USB 接続の外付け HDD に TimeMachine を利用して バックアップを取得した。
- 裏蓋の取外し
-
MacBook Air の裏蓋はペンタローブという
特殊な形式のネジが使用されているが、
SSD に同梱されている専用のドライバを利用すれば簡単に
ネジをはずす事ができる。
裏蓋を外した状態 - SSD モジュールの取外し
-
トルックスネジで固定されているオリジナルの SSD モジュールを
これも同梱されてる専用のドライバを利用してゆるめると、
オリジナルの SSD は簡単にはずれる。
オリジナルの SSD モジュール - SSD モジュールの組み付け
-
OWC の SSD モジュールをオリジナル同様に差し込んで、
トルックスネジを締め付けて固定すれば完了。
OWC の SSD モジュール - 裏蓋の組み付け
- 取り外した裏蓋を組み付ける。 ネジは仮締めしておき、最後に対角線上のネジを 交互に本締めするのがコツ(というか基本ですね)。
- 環境の復元
- 環境をバックアップした外付け HDD を接続した状態で MacBook Air に標準添付される USB メモリから起動。 自動で実行されるインストーラのバックアップから復元 を選択して新しい SSD に環境をレストアして作業完了。
環境の復元まで全て終了したら MacBook Air を起動すると、
無事に新しい SSD への移行が完了。
システムプロファイラ の シリアル ATA の項目を確認すると
OWC Merucry Aura Pro Express SSD と表示されている。
但し、現在の Mac OS X (10.6.8) では社外品の SSD に対する
trim 機能は無効とされてしまっているので、
システムプロファイラ の TRIM サポート項目は
いいえと表示されている。
この状態でも勿論利用可能なのだが、
折角高速な SSD の機能を最大限に使うために
Trim Enabler
を利用して trim 機能を有効にして再起動する。
再度 システムプロファイラ 上で確認すると、
今度は TRIM サポートが はいと表示されるので、
SSD の性能が最大限に活用できる気がして嬉しい。
2012/01/04
「今度ね…」
子供を育てていると、ついつい「今度ね」とか「後でね」とか言ってしまう。
大人にとってはその場しのぎで、次の瞬間には忘れてしまう様な事でも、
子供は「今度」や「後で」を楽しみに心待ちにしている事が多い。
そして結局「今度」や「後で」が来ない事を知ると落胆してしまう。
約束を守って貰えない親だと子供に思わせれるのは親として情けないと思うし、
約束を守って貰えない親だと思うしかない子供は不憫だと思う。
だから、自分の子供に「今度」や「後で」の約束をしたら、 必ずこちらから「今度」や「後で」を実現させてあげる様にしようと思うし、 なるべく「○○できたら」とか「○○の後で」と条件を明確にする様にしている。
極論かもしれないが、そういう細かな不信感の積み重ねで 大人になった時に約束は守らなくても良いと思う様な 責任感が希薄な人に育っていくのだとさえ思う。だから軽々しい口約束は極力控えて約束したらちゃんと守るようにしないとと思う。
2012/01/01
2011/12/14
cvs や svn のリビジョン番号
プログラムを作成する際、
特にまだ未完成で頻繁に修正とコンパイルを繰り返している間は、
どのリビジョンのプログラムを実行しているのか知りたい事はよく有る。
そんな時に、例えば実行時オプションとして -v を指定すると
cvs や svn のリビジョン番号とコミットした日時が表示されると便利だ。
しかし、多くの場合において -v オプションを解析し実行するだろう
main 関数が含まれるファイルが最終修正されているとは限らない。
従って main 関数の含まれるファイル中に
static char *id = "$Id$";などと定義しておいて commit 時に $Id$ を展開したとしても、 必ずしも最新のリビジョンにはならない場合が多い。
そこで -v オプションのハンドラ部分では
static char *id = "revision: " REVISION ", " COMMITED ;と記述としておいて make 時に自動で REVISION と COMMITED を全てのソース/ヘッダファイル中の cvs や svn の $Id$ キーワードから取得して設定する方法を検討してみる。
build 時に必ず実行する必要がある処理なので Makefile に記述して、 make 中で自動的に実行してしまうのが楽。
: # 変数定義 PROGRAM = myprog OBJECTS = sub.o pthread.o common.o util.o HEADER = myprog.h const.h config.h # 全ソース/ヘッダ中の `$Id' 行から最大のリビジョンを取得する REVISION = $(shell awk '/\$$Id/{ if($$4 ~ /[[:digit:]]/) \ if(max < $$4) max = $$4 } END{ print max }' \ $(OBJECT:.o=.c) $(HEADER) $(PROGRAM).c) # 全ソース/ヘッダ中の `$Id' 行から最大のリビジョンのコミット日時を取得する COMMITED = $(shell awk '/\$$Id.*'$(REVISION)'/{ \ print $$5 " " $$6; exit }' \ $(OBJECT:.o=.c) $(HEADER) $(PROGRAM).c) # コンパイルオプション(REVISIONとCOMMITEDを定義) CFLAGS = -g -Wall -Wextra -Werror -Wno-unused-parameter -I.-O2 \ -DREVISION=\""$(REVISION)"\" -DCOMMITED=\""$(COMMITED)"\" : : # ターゲット(デフォルトターゲットは touch と $(PROGRAM)に依存 all: touch $(PROGRAM) # $(PROGRAM).o ファイルの削除($(PROGRAM).o ファイルは必ずコンパイルする) touch: rm $(@).o $(PROGRAM): $(OBJECTS) $(CC) $(CFLAGS) -o $(@) $^ $(OBJECTS): $(HEADER) :これでどのファイルを commit した場合でも 必ず最新のリビジョンとコミット日付が -v で表示される。
当初ターゲット touch は touch $(PROGRAM).c としていたが、
とある方よりの指摘で rm $(PROGRAM).o に変更した。
ご指摘感謝です > N.S. さま
2011/11/26
shell での while ループにおける問題
シェルスクリプトでコマンドの出力をループ処理する場合は
パイプ | を使用するのが一般的な手法だと思うが、
パイプ | を使うとループが別なプロセスとして実行されるので
ループ内部で設定したシェル変数がループ外部で参照できないという問題があり、
(存在するとすれば) shell script 業界では割と FAQ 的な問題だ。
何が問題かと言って posix で定義されていないから
シェルの実装に依存しているのが一番の問題だったりするのだろう。
この問題に対しては、シェルビルトインの exec (1) を利用して
ディスクリプタを複製して while ループの入力を標準入力にしてしまうのが
一番汎用的で柔軟性のある対応だと思うのだが、
シェルを愛する面々は
皆同じ様な苦労をしているのだ
と改めて認識した。
当初は一時ファイルを作成する方法を考えついたのだが、
自分的にはなるべく一時ファイルを使いたくなかったので
ファイルから入力する部分をバッククォートによるコマンド実行に置き換え等、
色々と試行錯誤した結果ヒアドキュメントを使う方法に落ち着いた。
# これでは正常に動作しなかった exec 3<&0 0<`${command}` while read line :
勿論一時ファイルを作成しても良いのだが、 ヒアドキュメントを利用する事で一時ファイルが不要になる分だけ 処理的に美しいかなと思う (完全に好みの問題)。
1#!/bin/sh 2# コマンドの出力をバッククォートしてヒアドキュメントとして使用する 3 4command="/path/to/command" 5count=0 6 7# exec 3<&0: 標準入力 (FD0) を FD3 に複製 8# exec 0<<EOF: ヒアドキュメントを標準入力として使用 9exec 3<&0 0<<EOF 10`${command}` 11EOF 12 13while read line 14do 15 : 16 count=`expr ${count} + 1` 17done 18 19# exec 0<&3: FD3 に複製した標準入力 (FD0) を復帰 20# exec 3<&-: FD3 をクローズ</i> 21exec 0<&3 3<&- 22 23echo ${count}
もう一点は子プロセスで親プロセスの変数値を変更する方法。
こちらはプロセスが別になってしまうとファイルを使うしかないので、
同じプロセス内で関数呼び出しとして対応する方法が汎用的ではないだろうか。
1#!/bin/sh 2# eval を利用して呼び元の変数を設定する 3 4default="デフォルト値" 5 6sub() 7{ 8 9 local _val 10 11 : 12 _val="設定したい値" 13 14 eval "${1}='${_val:-${default}}'" 15 16} 17 18value="元の値" 19 20sub value 21 22echo ${value}
ちなみに上のリンク元にある parent.sh の中の処理で
${tmp_file} の内容を for ループで eval しているが、
これはシェルビルトインの . もしくは source を利用して
. ${tmp_file} としても同一の結果が得られるので楽だと思う。
1#!/bin/sh 2 3g1="aa" 4g2="bb" 5 6tmp_file=`mktemp /tmp/ps.XXXXXX` 7export tmp_file 8 9./child.sh # child.sh で、上で設定した変数 g1, g2 の値を変更する 10 11# for v in `cat $tmp_file`; do 12# eval $v 13# done 14# ${tmp_file} の内容は name='value' 形式が保証されているので 15# ファイル自体を `.' コマンドで読み込むだけで 16# 行毎に eval を実行しなくてもシェル変数に代入された値が利用できる 17 18if [ -f ${tmp_file} ] 19then 20 . ${fmp_file} 21 rm -f ${tmp_file} 22fi 23 24echo $g1 #=> cc に変更された 25echo $g2 #=> dd に変更されたブログに直接コメントしたかったのだが、 はてなのアカウントが無いので申し訳ないがここで意見させて頂く。
2011/11/24
こどもの国
朝から好天に恵まれてぽかぽかな冬の休日を無駄にするのは勿体ないので、
かねてから気になっていた「こどもの国」に家族で出かけてみた。
行く前は「こどもの国」という名称から
『どうせ地方にありがちな子供向けのしょぼい遊園地の類だろう』等と
高をくくっていたのだが、実際に行ってみると大違い。
東京都と神奈川県にまたがる広大な敷地が、
自然の地形や環境上手に活かさて大人でも十分楽しめる遊園となっていて、
良い意味で期待が裏切られた。
あまりに広すぎるので一日では回りきれず
全体の半分程度を結構な駆け足で巡っただけなのだが、
それでも地面に自由に落書きできる広場や
本格的な牧場やポニーへの乗馬体験、
伊豆のサイクルスポーツセンターを彷彿とさせる様な
様々な変わり種自転車を集めた施設など盛りだくさんの内容だった。
しかも牧場では定番のソフトクリームや 首都圏で随一生産されるらしい牛乳も楽しめる。
2011/11/16
メモリリークチェッカー
c で daemon 動作するサーバを作っていると
malloc (3) などで動的に確保したメモリの free (3) 忘れによる
いわゆるメモリリークを防ぐ事が非常に重要になってくる。
この様なメモリリークを防止するために役立つ
様々なツールが世の中には沢山存在しており
それぞれ非常に有用ではあるのだが、
いざ利用しようと思うと割と面倒な作業が発生したり、
自分の求めている機能に対して明らかにオーバースペックだったりするので、
自分の用途に合わせて簡単に使える『俺様ツール』を作ってみた。
動作原理は簡単で malloc (3) や free (3) したアドレスを
ログに出力して、
後からログを解析してメモリの確保と解放が対になっていない部分を
抽出するだけである。
そのためにまずは元となるソースコードを修正して、
malloc (3) や free (3) を独自に作成した wrapper 関数に置換えて
確保、解放したアドレスをログに出力する機能を組込む必要があるのだが、
malloc (3) などはエラー処理を含めて共通化するために
あらかじめ wrapper 関数化されている場合が多いと思うので、
この部分はフォーマットを決めるだけで割りと簡単に追加できると思う。
今回は syslog (3) を利用して malloc (3)、strdup (3)、
free (3) で確保/解放するアドレスを出力した。
1/* 2 * malloc() の wrapper 3 */ 4void *mymalloc(size_t size) 5{ 6 7 void *p; 8 9 if(!(p = malloc(size))) 10 /* エラー処理 */; 11 syslog(LOG_DEBUG, "malloc: %p\n", p); 12 13 return(p); 14 15} 16 17/* 18 * strdup() の wrapper 19 */ 20char *mystrdup(const char *s) 21{ 22 23 char *p = NULL; 24 25 if(s){ 26 if((p = strdup(s))) 27 syslog(LOG_DEBUG, "strdup: %p\n", p); 28 else 29 /* エラー処理 */; 30 } 31 32 return(p); 33 34} 35 36/* 37 * free() の wrapper 38 */ 39void myfree(void *p) 40{ 41 42 if(p){ 43 free(p); 44 syslog(LOG_DEBUG, "free: %p\n", p); 45 } 46 47}
次に出力されたログの解析処理であるが、
確保したメモリのアドレスをキーとしたハッシュテーブルを利用したいので
入力行の解析やハッシュテーブルが簡単に利用できる言語として
今回はコマンドライン版の php (1) を利用してみた。
もちろん awk (1) を駆使したり perl (1) を利用しても問題ない。
1<?php 2 /* 3 * Copyright (c) 2011 Mitzyuki IMAIZUMI, All rights reserved. 4 * 5 * $Id: memcheck.php 1677 2011-10-12 06:58:03Z mitz $ 6 */ 7 8 /* 冗長指定 */ 9 if($argv[1] == "-v"){ 10 $verbose = 1; 11 array_shift($argv); 12 } 13 14 if($fp = fopen($argv[1], "r")){ 15 $line = 0; 16 while($buf = fgets($fp, 1024)){ 17 $buf = ltrim($buf); 18 $line++; 19 /* 20 * malloc か strdup か free を含む行の場合 21 * コマンドを配列 $p[0] に、アドレスを配列 $p[1] に格納する 22 */ 23 if(preg_match("/^(malloc|strdup|free):\s(.*)/", $buf, $p)) 24 /* 解放処理 */ 25 if($p[1] == "free") 26 /* 確保済みテーブルに解放アドレスが存在する場合 */ 27 if($alloc[$p[2]]){ 28 if($verbose) 29 printf("%s: % 8d -> % 8d\n", $p[2], $alloc[$p[2]], $line); 30 $alloc[$p[2]] = 0; 31 } 32 33 /* 確保済みテーブルに解放アドレスが存在しない場合 */ 34 else 35 printf("%s: unknown free at % 8d\n", $p[2], $line); 36 else 37 /* アドレスをキーとしたハッシュテーブルに行番号を格納 */ 38 $alloc[$p[2]] = $line; 39 40 } 41 fclose($fp); 42 43 foreach($alloc as $k => $v) 44 if($v) 45 printf("%s: NOT free (% 8d)\n", $k, $v); 46 } 47?>このスクリプトを実行する事により malloc(3) もしくは strdup(3) で確保したメモリが解放されていない場合、 もしくは確保していないメモリを解放した場合が簡単に発見可能である。
これらは自分が必要とする機能のみを簡単に実装したものであり、 例えば解放していない事を意図しているメモリまで警告されてしまう等、 汎用的に使える事を目指したツールでは勿論ない。 ただ、日頃発生しうる面倒な作業がちょっとの工夫で 多少なりとも楽になるだろう例の一つとして公開してみた次第である。
2011/11/28 追記
awk (1) 版の方が汎用的なので簡単に作成してみた。 処理内容は上記 php (1) 版と同じである。1#!/bin/sh 2 3if [ "${1}" = "-v" ] 4then 5 verbose=true 6 shift 7fi 8 9awk ' 10 /^(malloc|strdup)/{ 11 alloc[$4] = NR; 12 } 13 /^free/{ 14 if(alloc[$4]){ 15 if("'${verbose:-false}'" == "true") 16 printf("% 5d %s: % 5d\n", NR, $4, $alloc[$4]); 17 alloc[$4] = 0; 18 } 19 else 20 printf("% 5d %s: unknown free.\n", NR, $4); 21 } 22 END{ 23 for(i in alloc) 24 if(alloc[i]) 25 printf("% 5d %s: NOT free.\n", alloc[i], i); 26 } 27' ${1} | sort ${2}