🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Q&A

解決済

4回答

3171閲覧

C言語 プログラム外からメモリーリークを確認する方法を知りたい。

Kchan_01

総合スコア110

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

0グッド

1クリップ

投稿2020/12/07 05:56

編集2020/12/07 06:56

C言語を学んでいるものです。
日頃、自分の書いたプログラムや、人の書いたプログラムをレビューしあいながら、学習を進めています。

C言語の初学者が多く、プログラムがメモリーリークを起こしていることもしばしばあリます。
関数をチェックし合うような場合は、評価する関数をmain関数内で呼び出し、その後でsystem("leaks a.out");と書いて、リークスコマンドによって、メモリーリークをチェックしています。

ですが、プログラムをチェックする場合は、main関数を含めて、相手のコードになるので、そこを書き換えて、チェックするのは相手のプログラムを書き換えることになるので、プログラムのレビューとしては、不完全だと思っています。

プログラムのコードを傷付けることなく、メモリリークを確認をする方法はないでしょうか?

現状、プログラムの終了とともにメモリも解放されてしまいますので、コードをいじらない限り、メモリリークの確認は不可能という理解です。

追記 2020/12/07 14:59
プログラムからの確認が難しい場合は、コンパイルの段階で、何かしらの方法を施すような処理でも構いません。

追記 2020/12/07 15:49

課題のレベル感としては、lsコマンドを自作する、簡易zshを自作するくらいの難易度の課題に取り組んでおります。最初はファイル数も1つでしたが、今はファイル数も多く、ヘッダーファイルもかき分けだったり、Makefile含めての自作をやっています。やっている課題のレベルが徐々に上がってきており、自分たちのレビューの質を向上させるためにも、方法を知っておきたいと考えております。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/12/07 06:16

ValgrindやElectric Fenceなどのその手のメモリリーク検出ツールの利用は除外、でしょうか。 あるいは、(参考) [メモリリークを検出するツールを教えて欲しい] https://teratail.com/questions/143773
maisumakun

2020/12/07 06:37

> チェックするのは相手のプログラムを書き換えることになるので、プログラムのレビューとしては、不完全だと思っています。 この考え方自体がわからないのですが、もう少しご説明いただけないでしょうか?
Kchan_01

2020/12/07 06:39

@maisumakunさん @epistemeさんにうまく言い換えて頂いておりますが、 > mainを書き換えるやりかたではmainがテストできない ということです。
Kchan_01

2020/12/07 06:43

@dodox86さん いろんな環境でレビューしあっているので、ツールに依存しない方法が望ましいですが、ツールがないと難しいのでしたら、mac環境で使えるツールを検討してみたいです。 Valgrindに関しては、現在のMacのversionではうまく動かず、動いたとしてもMacが熱々になるということが確認できているので、それ以外で使い勝手の良いものでしたら使ってみたいです。 ``` ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H15 ```
t_obara

2020/12/07 07:25

Macと言うことであれば、 instruments ではいかがでしょうか。
guest

回答4

0

ベストアンサー

ツールに依存しない方法が望ましいですが

言語仕様で説明される意味規則と実際に生成される機械語がどのように対応付けられるかはわかりません。 見かけ上の動作が仕様通りであれば書いた通りにコンパイルされなくてもよいことになっています。 プログラムの字面の上でメモリリークを発生させうるものであったとしても具体的にメモリリークとして観察できるかというのはわからないのです。

試しに、私はこのような (メモリの解放をしていない) プログラムを書いてみました。

c

1#include <stdlib.h> 2#include <stdio.h> 3 4int main(void) { 5 int *x = malloc(sizeof(int)*3); 6 x[0] = 1; 7 x[1] = 2; 8 x[2] = 3; 9 for(int i=0; i<4; i++) 10 printf("%d\n", x[i]); 11}

x86-64 をターゲットにした clang 11.0.0 で -O2 オプションを使ってコンパイルしたところ、以下のようなコードが生成されました。

asm

1main: # @main 2 push rax 3 mov edi, offset .L.str 4 mov esi, 1 5 xor eax, eax 6 call printf 7 mov edi, offset .L.str 8 mov esi, 2 9 xor eax, eax 10 call printf 11 mov edi, offset .L.str 12 mov esi, 3 13 xor eax, eax 14 call printf 15 mov edi, offset .L.str 16 xor eax, eax 17 call printf 18 xor eax, eax 19 pop rcx 20 ret 21.L.str: 22 .asciz "%d\n"

これは最適化の結果、以下のように書いた場合と同じだとみなされたということです。

c

1#include <stdio.h> 2 3int main(void) { 4 printf("%d\n", 1); 5 printf("%d\n", 2); 6 printf("%d\n", 3); 7}

字面の上ではメモリリークしているにもかかわらず、実際の実行プログラムはメモリリークしません。

実行時に mallocfree の呼出しを乗っ取ってチェックするタイプのツールではこのような間違いを検出できないのです。 ツールを選ぶならば、コンパイラと連携するか、静的解析を指向しているものを選んだ方がよりよいでしょう。


特定のツールに頼らず大抵のコンパイラ・実行環境で出来る範囲でということならば、マクロで書き換えて機能を乗っ取ってしまうという方法が考えられます。 (言語仕様の範囲では) メモリリークが発生するというのは malloc calloc realloc で得たメモリが free されないということですから、これらの呼出しを監視すればよく、たとえば gcc のコマンドで言えば

gcc -lmyalloc -Dmalloc=mymalloc -Dfree=myfree sample.c

といった要領で自前で定義した関数に置き換えることは出来ます。 置き換えた関数でログを取った上で本来の関数を呼び出すようにしておけばメモリの確保・解放の様子を監視することが出来るでしょう。

ただ、初心者のコードだとリークよりも不正アクセスの類の方が多いでしょうし、不正アクセスの挙動は (言語仕様上は) 未定義なので言語仕様の範囲内ではどうしようもありません。 ポータブルな解決方法は無いです。

投稿2020/12/07 08:34

SaitoAtsushi

総合スコア5684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kchan_01

2020/12/07 09:29

> 試しに、私はこのような (メモリの解放をしていない) プログラムを書いてみました。 この例のプログラムは、アクセス可能領域にポインタが存在しているから、リークを検出しないのだと思っていたのですが、コンパイラによる最適化の結果でleakにならないというケースがあることは知りませでした。 c - Still Reachable Leak detected by Valgrind - Stack Overflow https://stackoverflow.com/questions/3840582/still-reachable-leak-detected-by-valgrind > 実行時に malloc や free の呼出しを乗っ取ってチェックするタイプのツールではこのような間違いを検出できないのです。 ツールを選ぶならば、コンパイラと連携するか、静的解析を指向しているものを選んだ方がよりよいでしょう。 ツールの違いにも注意して、理解を深めようと思います。 malloc、freeを上書きして、ログを取るのはすごくいいアイディアで、実装方法を考えてみようと思います。以下の方法は試したことがありましたが、そもそもsystem関数など使って、外部にログを残せば、コードを書き換える必要が無くなりそうです。 【C言語】メモリの解放忘れ(メモリリーク)を自力で検出する方法 | だえうホームページ https://daeudaeu.com/memory_leak/ ありがとうございます。
guest

0

ですが、プログラムをチェックする場合は、main関数を含めて、相手のコードになるので、そこを書き換えて、チェックするのは相手のプログラムを書き換えることになるので、プログラムのレビューとしては、不完全だと思っています。

「mainを書き換えるやりかたではmainがテストできない」ってことですか。
ならば

C

1#ifdef TEST 2int actual_main(int argc, char** argv) 3#else 4int main(int argc, char** argv) 5#endif 6{ ... }

とでもしてしまえば、コンパイル時にオプション -DTEST をつけてコンパイルすることで
main が actual_main に置き換わります。そのうえで

C

1int main(int argc, char** argv) { 2 extern int actual_main(int,char**); 3 int result = actual_main(argc, argv); 4 /* 必要に応じいろいろテストする */ 5 return result; 6}

を追加すればいい。

...なんてな泥臭い力業はいかがでしょ。

投稿2020/12/07 06:28

episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

静的解析ツールというものが存在します。
無償・有償様々なものがあります。
どれを使えばよいかというのは割愛しますので、まずは静的解析ツールとはどんなものかなどググってみるとよいでしょう。

というのがメモリリークを解析する手段についての回答ですが、まだ学習段階であるとのことなので、実際のところツールに頼るほど大規模なコードを書いているとは思えません。
C言語を使う以上、メモリリークのことは常に念頭に置いておく必要はありますが、失敗してもいいので、まずは沢山コードを書いて、失敗から学ぶ方がよいのではないかと個人的には思います。
あとは初学者同士だけではなく、有識者の方にコードレビューしてもらうとか、レビューしてもらえるようなサイトを利用するなどのほうがよりよいアドバイスをもらえると思います。
というのもツールでメモリリークを検出しても、「ここでメモリリークするよ」という情報は得られるものの、「どうしたらいいのか」「こういう風に書いた方がよい」などの情報は得られないためです。

以上、参考まで。

投稿2020/12/07 06:14

ttyp03

総合スコア17000

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ツールを使う方法として、コンパイル時に-g -fsanitize=leakオプションを使う方法を見つけました。

コマンドで完結するので、楽そうでした。

clang -g -fsanitize=leak test.c

投稿2020/12/07 09:31

Kchan_01

総合スコア110

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問