プロが教える店舗&オフィスのセキュリティ対策術

はじめまして、shigure2005と申します。

私は普段UNIX上でC言語のプログラムを書いているのですが、
わけあってWindows上で動くようにする必要が出てきました。
そのプログラムをそのままcygwinでコンパイルしたところ
コンパイルでき、実行ファイルも問題なく実行できたのですが、
このままですとcygwin1.dllが必要になってしまいます。
ですので、これがなくてもすむような別のコンパイル方法を
教えていただければと思ったしだいです。

過去ログを探って、MinGWについては試してみたのですが、
コンパイルは問題なく通るのに、なぜか実行ファイルを
実行すると、うまく起動できません。Mingwは以下のファイルを
ダウンロードしてインストールしました。
mingw-runtime-3.8.tar.gz
mingw-utils-0.3.tar.gz
MinGW-4.1.1.exe
w32api-3.3.tar.gz
binutils-2.15.91-20040904-1.tar.gz
mingw32-make-3.80.0-3.exe
PATHは「C:\mingw/bin;C:\cygwin/bin」の順に通していて、
コマンドプロンプトでコンパイルし、コンパイル後、
コンパイルに用いたdllがcygwin1.dllでないのを確認して
います。また、helloworldなど簡単なプログラムなら、
Mingwでもうまくコンパイルできてます。cygwinとMingwで
コンパイル性能に大きな差などがあるのでしょうか?

また、cygwinだけでも、Mingw-runtimeをインストール
すれば、cygwin1.dllを必要としない形式にコンパイル
できるという話を聞いたのですが、ご存知の方が
いらしたら教えてください。

どうぞよろしくお願いします。

A 回答 (7件)

> なぜかプログラム中に一箇所printfを入れないとまったく動かず、


> 入れると動くという状況になってしまいました。

私も昔はときどきそういったことに遭遇しました。
結局、不定や未定義の動作に依存した実装をしているからそういうことが起こるんですね。
現物合わせで動けばOKではなく、きちんと言語仕様を把握した上で実装すれば、そうした問題はなくなりますし、逆にそうしないと信頼性の高いコードはかけません。

前にも書いたように、実際にソースを見てみないことには、正確なことは何もわからないので、推測ばかりの発言になってしまうかと思います。
    • good
    • 0
この回答へのお礼

たびたび丁寧なご回答ありがとうございます。

このような事例は特殊なことではなく、よく起こることなのですね。
たしかに、ここでアドホックにprintf()を書いていくと、非常に
危険なものになる気がします。その動作、結果ともになんとも
信頼をおくことができないので、もう一度メモリ関係を中心に
全部洗いなおしてみようと思います。

言葉足らずな状況説明にもかかわらず、何度も丁寧に教えていただき
どうもありがとうございました。またどうしてもわからず御質問したときには、
どうぞよろしくお願いします。

お礼日時:2005/09/23 01:27

こんにちは。

横から失礼します^^)

> 初歩的な質問で申し訳ありませんが、sjis形式のファイルの
> 改行は、windows上でプログラムの入力としたときは\r\nではなく
> \nと扱われるのでしょうか?

いいえ。sjis だからではなく、msvcrt だからと言った方が良いと思います。

多分、元のファイルが "\r\n" 形式なら、fopen する際に、fopen("..", "rb") と第二引数に "b" をつけたら結果は変わると思います。

> また、このプログラムはコマンドプロンプトからなら実行できるのですが、
> cygwinからでは実行できません・・・。何のメッセージも出ずに終了してしまいます。
> このように同じ実行ファイルなのに実行環境を選ぶことなどあるのでしょうか?

の件は、記述の内容からでは何とも断言できませんが、これも先の malloc の件と似たようなものかも知れませんね(即ち Library の内部仕様の差異で、使用法を誤った(仕様外の利用をした)場合、その後の挙動が異なる)。

ですから、この件は(想像を逞しくすれば)、例えば stdin を fflush() しているとか、stdout を fpurge() しているとか...って類の記述が無いでしょうか?

ちなみに、debug のために printf() を入れたら正常に動いてしまったというのは良くある話です。大概は printf を入れることにより、変数領域の 配置が変わったり、実行イメージの配置が変わったりで今まで突いていた秘孔の位置が変わるって感じですね。でも、結局はどこかを突付いているので、いつか死んでしまう可能性はあります。

## まあ、純粋なコンパイラーの bug って事もありましたが...
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

msvcrtはそのようなことをしてくれるんですね。まったく
想定外でした。コンパイラによって大きく違ってくるんですね。
ご指摘の方法試してみようと思います。

通らなかったり通ったり、実行できなかったりできたり、
という時点で、もうプログラム自体がかなり怪しいものに
なってるんですね。printfを入れたら正常に動くという話が
よくあるというのは驚きです。しかし、つぼを押されないと
動けないようなプログラムでは安心して任せられませんね・・・

ありがとうございました。疑わしいメモリ部分を徹底的に
もう一度洗ってみます。

お礼日時:2005/09/23 01:22

No1です。


朝ははずしていてすみません。
MinGWでは失敗する, cygwinで成功する(-mno-cygwinでは失敗する), gdbで成功する
というmallocのソースを考えてみました。
-----------------------------------------------------------------------
/* 多少, 無駄や汚いところがありますが, ご勘弁を */
#include<stdio.h>
#include<stdlib.h>

int main(void) {
int i;
int r;
char *p[10];
for(i=0;i<10;i++) {
puts("メモリ確保開始");
fflush(stdout); /* エラー箇所をバッファリングで見失わないように */
p[i] = (char *)malloc(sizeof(char)*65536);
puts("メモリ確保確認開始");
if(p[i]==NULL) {
puts("メモリの確保に失敗");
exit(1);
}
puts("メモリを確保");
fflush(stdout); /* エラー箇所をバッファリングで見失わないように */
p[i][65536] = 'a'+rand()%26; /* 普通はいけない */
putchar(p[i][65536]);
}
putchar('\n');
return 0;
}
-----------------------------------------------------------------------
以上のソースはMinGWで"メモリ確保開始"表示の直後に強制終了になります。
つまりmallocでおかしくなっていると考えられると思います。
cygwinでは何故か無事動きます。そしてこれも何故かcygwinのgdbでは動きます。
-O1オプションでコンパイルしています。

みそは65536個確保した場所の65537番目, つまり,
確保した領域からはみ出したところに代入しているところです。
shigure2005様には大変失礼ですが, mallocで確保した領域と, 格納する
値の大きさを今一度, 確認されてはいかがでしょうか?
既知だったり, 再びはずしていたらごめんなさい。
    • good
    • 0
この回答へのお礼

ご回答&丁寧にソースを書いていただきありがとうございます。

試してみたところ、確かにcygiwnコンパイル or MinGWコンパイルgdb実行だと
このソースは領域侵犯してても実行できるのですね。念のため疑わしいところを
再度確認してみたところ、mallocする領域の大きさが、UNIXで行ったとき
よりも小さくなっていました・・・
入力ファイルとして、sjis形式のcsvファイルを開いて、一行読み込み、
その(文字数-2+1)/2の領域を確保していたのですが、(-2は改行\r\n分、+1は,の分)
cygiwnのgdbで読み取った文字行の改行コードを見たところ\nになってました。
初歩的な質問で申し訳ありませんが、sjis形式のファイルの
改行は、windows上でプログラムの入力としたときは\r\nではなく
\nと扱われるのでしょうか?

この修正を施した後、もう一度全体を洗いなおしたところ、
なんとかMinGWでコンパイラしてできた実行ファイルをコマンドプロンプト上で
動かすことができるようになりました。しかし・・・、
なぜかプログラム中に一箇所printfを入れないとまったく動かず、
入れると動くという状況になってしまいました。このように、
時間稼ぎor意味のない出力をするしないでプログラムが動く動かない
に影響することがあるのでしょうか? printfがないと、何も出力されず終了します。
また、このプログラムはコマンドプロンプトからなら実行できるのですが、
cygwinからでは実行できません・・・。何のメッセージも出ずに終了してしまいます。
このように同じ実行ファイルなのに実行環境を選ぶことなどあるのでしょうか?

たびたび申し訳ございませんが、どうぞよろしくお願いします。

お礼日時:2005/09/22 12:13

> 前者の「使用しているDLLとの間で矛盾したmalloc/freeの組み合わせをしている」


> というのはどのような意味でしょうか?

例えば、あるDLLではCygwinのmallocを使い、それが返したポインタをアプリ側でMinGWのfreeを使って解放するようなことがあると、問題が起こります。
ですが、今回の場合はそうした問題はなさそうです。

これ以上は、実際のソースを見ないと原因が分かりませんね。
    • good
    • 0
この回答へのお礼

たびたびご回答頂き、ありがとうございます。そのようなDLLもあるのですね。

先ほど、MinGWでコンパイルするときに-gでデバッグ
できるようにして、cygwinのgdb内で実行したところ、
なんとgdb内ではうまく実行でき、出力も正常に行う
ことができました。しかしながら、同じ実行プログラムを
普通のところで実行すると、また以前のように止まってしまいます。
gdb内でのみ動くなどということがあるのでしょうか・・・?
また、gdb内は普通の環境とは大きく違っているのでしょうか?

短い間に何度も申し訳ございませんが、お答えいただけると
幸いです。

お礼日時:2005/09/21 17:58

> 具体的には、mallocを何度か繰り返しているところが


> あるのですが、4回ほどmallocを繰り返すと終了
> してしまっています。

とんでもなく大きなメモリブロックの割り付けを行っていない限り、そんなことはないと思います。それに、メモリが枯渇しても、mallocがNULLを返すだけで、いきなり終了することはありえません。
使用しているDLLとの間で、矛盾したmalloc/freeの組み合わせを行っているとか、二重解放を行っているとかいったことはありませんか?

> 同様のプログラムをcygwinでコンパイル
> するとこのようなことはないので、MinGWとcygwinでは
> cygwinの方がメモリ管理がうまいソースを作るのかと
> 思った次第です。実行時にメモリがどのように使われて
> いるのかを見る方法はわからなかったので、この推測が
> 正しいかはわからないのですが、他に原因が思い浮かばない状況です。

Cygwinのmallocのソースを見る方法はあります。
Cygwinのsetup.exeを使って、cygwinモジュールのソースをインストールしてください。/usr/src下にソースが展開されます。
ちょっとわかりにくいですが、/usr/src/cygwin-バージョン/winsup/cygwin/malloc_wrapper.ccがmallocやfreeのソースコードがあります(C++です)。

MinGWのソースコードは、Visual C++のソースコードを見る必要があります。
    • good
    • 0
この回答へのお礼

丁寧なご回答ありがとうございます。

>使用しているDLLとの間で、矛盾したmalloc/freeの
>組み合わせを行っているとか、二重解放を行っている
>とかいったことはありませんか?
ファイルから入力するところなので、まだfreeは行っていないので、
二重開放はしていません。
前者の「使用しているDLLとの間で矛盾したmalloc/freeの組み合わせをしている」
というのはどのような意味でしょうか?
objdump -p 実行ファイル名 | grep "DLL Name"
と実行したところ、MinGWで作ったものは、
 DLL Name: KERNEL32.dll
 DLL Name: msvcrt.dll
となりこのプログラムは実行できず、cygwinは
 DLL Name: cygwin1.dll
 DLL Name: cygwin1.dll
 DLL Name: KERNEL32.dll
となり、このプログラムは実行できました。
msvcrt.dllというDLLに適さないmalloc/freeの組み合わせ
というものがあるのでしょうか?

せっかく教えていただいたのに申し訳ございませんが、
C++は現在わかりませんので、ソースは読めなそうです。

お礼日時:2005/09/21 15:37

> コンパイルは問題なく通るのに、なぜか実行ファイルを


> 実行すると、うまく起動できません。

具体的にはどんな現象になるのでしょうか?
いきなり異常終了するとかであれば、ソースコードやコンパイルオプションを詳しく見ない限り、何ともいえません。

> cygwinとMingwで
> コンパイル性能に大きな差などがあるのでしょうか?

Cygwinに比べてMinGWはコンパイル速度が幾分か速くなります。生成されたコードの質は変わりませんが、Cygwinの場合はUNIXのエミュレーション層が多い分、実行時のオーバーヘッドにつながります。

> また、cygwinだけでも、Mingw-runtimeをインストール
> すれば、cygwin1.dllを必要としない形式にコンパイル
> できるという話を聞いたのですが、ご存知の方が
> いらしたら教えてください。

コンパイル時に-mno-cygwinオプションを付ければ、CygwinだけでMinGWを利用することが出来ます。
    • good
    • 0
この回答へのお礼

レスありがとうございます。

具体的には、mallocを何度か繰り返しているところが
あるのですが、4回ほどmallocを繰り返すと終了
してしまっています。メモリの枯渇が原因かと
考えたのですが、同様のプログラムをcygwinでコンパイル
するとこのようなことはないので、MinGWとcygwinでは
cygwinの方がメモリ管理がうまいソースを作るのかと
思った次第です。実行時にメモリがどのように使われて
いるのかを見る方法はわからなかったので、この推測が
正しいかはわからないのですが、他に原因が思い浮かばない状況です。

コンパイルオプションは -Wall -O1 -lmをつけています。

-mno-cygwinオプションについても教えていただき、
ありがとうございます。これで実行した場合も、MinGW
で実行したときと同じく(当然の話ですが(^^;)、
mallocで終了していました。

お忙しいところ申し訳ございませんが、どうぞアドバイス
よろしくお願いします。

お礼日時:2005/09/21 10:47

cygwin1.dllを必要としないようにするには, Mingwを入れなくても, gccの-mno-cygwinオプションでオッケーだったかと...


gcc -mno-cygwin foo.c
はずしてたらごめんなさい。
あと, cygwinとMingwの違いについてはわかりません...
すみません。
うまくいくこと, 願っております。
    • good
    • 0
この回答へのお礼

レスありがとうございます。「gcc -mno-cygwin」と
すれば、mingw-runtimeを入れていればこちらで
コンパイルしたことになるんですね。試してみたところ、
MinGWを用いてコンパイルしたときと同じく、
「コンパイルは通るけれど実行できない」
状況になってました。やはり、MinGWでは通らない
ようです・・・。

お礼日時:2005/09/21 10:20

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!