タダでソフト開発の生産性と品質を上げる方法(9):メモリリークを一瞬で見つける「Valgrind」(その2):山浦恒央の“くみこみ”な話(99)(2/3 ページ)
「タダでソフト開発の生産性と品質を上げる方法」の第9回。前回紹介した「Valgrind」を用いた具体的なメモリリークの検出方法について解説します。
2.動的解析と静的解析
導入したいツールを探す場合、ツールの種類に着目するのが近道です。Valgrindの機能を解説する前に、プログラムを解析するツールの概要を簡単に説明します。プログラムの解析ツールには、「動的解析」と「静的解析」の2種類があります。
動的解析は、プログラムを実際に動作させて解析するものです。テスト網羅度の計測やデバッガも、この一種ですね。例えば、第86回で紹介した「gcov」が動的解析ツールです。今回紹介するValgrindも、プログラムを実行して使うので動的解析ツールです。
静的解析は、プログラムを動かさずに解析し、構造上の誤りを形式的に検出する手法です。静的解析は、コーディング規約やコードメトリクスを検出するタイプで、プログラムを動作させなくても解析できます。例えば、第91回で紹介した「SourceMonitor」は、プログラムを動作せずに解析するので、静的解析ツールです。
解析ツールを探す際は、両者の違い、長所と短所を把握して調べるとよいでしょう。
3.Valgrindで検出できるバグ
前回は、Valgrindの環境を構築する方法と、メモリリークを検出する具体例を解説しました。今回は、例題を示しながら、以下のバグを検出する方法を説明します。
- 初期化していない変数
- 領域外読み込みと書き込み
3.1 初期化していない変数
「初期化していない変数」とは、その名の通り、宣言はしたが初期化しないまま使用している変数です。C言語では、ローカル変数を宣言するだけでは、値に何が入るか分かりません※4)。通常は「int val = 1」のように、初期化します(この記事の読者は、初期化しないことはないでしょうが)。例えばリスト1をご覧ください。
※4)大学でのプログラミング演習の授業では、学生の多くが「初期化していない変数」に戸惑うようです。例えば、「int a;」としたが「a」を初期化せず、「a」の値をコンソールに出力させると、意味不明な数値が画面に現れ、ビックリすることが少なくありません。場合によっては、「私のPCは壊れています」と言い出す生徒もいます。
#include <stdio.h> main() { int x; print("%d",x); }
リスト1は、変数xを宣言し、コンソールに変数xを出力するプログラムです。簡単なプログラムですね。変数xは初期化しておらず、初期値は不定です。このプログラムに対して、解析をかけると図1のようなメッセージが出ます。
図1は、リスト1のプログラムの解析結果の一部です。1行目に、「Conditional jump or move depends on uninitialised value(s)」という記述があります。これは、未初期化の変数がある場合に出るメッセージで、「初期化していない変数の値により、条件ジャンプや処理をしようとしている」の意味です。3行目を「int x=1;」に変更すると、このエラーメッセージは消えます。プロのエンジニアが変数を初期化せずに使用することは、まずありませんが、うっかりミスを防ぐため、Valgrindで自動チェックするといいでしょう。
3.2 領域外読み込み
プログラミングの単純ミスとして、配列の領域外読み込みや書き込みも、よく見かけます。例えば、「int array[100]と宣言した後、array[100]を読んでしまった」は、王道的なバグでしょう。C言語でarray[100]と宣言すると、実際には、array[0]からarray[99]までしかアクセスできず、array[100]は領域外読み出しとなります。制御構文が複雑になると、見落とすので注意が必要です。Valgrindを使うと、間違って領域外の変数にアクセスした時に、メッセージを表示します。リスト2で考えてみましょう。
#include<stdio.h> #include<stdlib.h> main(){ char *str; str = (char*)malloc(5); printf("%c",str[5]); free(str); }
リスト2は、malloc関数で5バイト分の領域を確保し、その内容をコンソールに表示するものです(str[0〜4]は、未初期化となっていますが、無視してください)。printfで、配列の領域外のstr[5]を読み出しています。strは、0〜4までしかアクセスできませんので、領域外の読み込みですね。Valgrindを実行すると、以下のメッセージでバグが分かります。
図2は、リスト2を実行時のログの一部を示したものです。「invalid read of size 1」と出ています。つまり、「1バイトを誤って読み込んでいる」という意味です。
Copyright © ITmedia, Inc. All Rights Reserved.