Home > バグ Archive

バグ Archive

KeyPointerEX修正

ちょっと前にえらそうに改良したKeyPointerEXですが、開発環境(というかMFCライブラリ)が入っていないPCだと動かないっていう致命的なバグがあったので直しました。
あんまりダウンロードもされていないのですが、もしダウンロードして動かなかった人はごめんなさい。

以上

VC2008のバッファオーバーラン?

なぜかエラーにならない。


void overrun(void) {
	int i = -3;
	int test[100];

	test[i] = 1;
}


int _tmain(int argc, _TCHAR* argv[])
{
	overrun();

	return 0;
}

2003くらいだとエラーになる。/GSオプション入れとけばエラーが出ることもあるけど、どこでエラーなのか分からない。大丈夫か2008!

以上

簡単なことが実はできてない

例えばnCrをどうやって計算するか。私は素直なので以下のようにやってしまいます。


int nPr(int n, int r)
{
    int retval = 1;
    if (n < r) return 0;
    for (int i = n; i > (n-r); i--) {
        retval *= i;
    }
    return retval;
}

int nCr(int n, int r)
{
    return nPr(n, r)/nPr(r, r);
}

数学的には上のような感じでいいはず(nとかrの不正値について無視すれば)。でもこれだとオーバーフローするらしいのです。速攻で。まあ、そりゃそうかも。階乗だし。例えばrを10にしたら分母のnPr(r,r)がもうオーバーフローします。なのでnCr(10,10)なんて簡単に1になることが分かるのに、計算できないわけです。まあ、この例ならnCr(10,10)=nCr(10,0)=1って計算しろよ、なんですが、まあすぐオーバーフローすると。で、どうしたらいいかというと漸化式で計算すればいいらしいです。


int nCr(int n, int r)
{
    int retval = 1;
	for (int i = 1; i < r; i++) {
		retval = retval * (n-i+1)/i;
	}
	return retval;
}

プログラムって微妙に数学と違うところが難しい。

以上

応募権を獲得した

なんかgooで検索したら応募権がもらえるらしいです。AM3:00~AM11:00に検索した場合。
http://guide.search.goo.ne.jp/summer2008/
↑これです。

でも、20:30くらいにメタルギアソリッドを検索したら応募権もらえました。
証拠にはなりませんが、一応javascriptで現在時刻を表示しています。


javascript:(function(){dt = new Date(); h = dt.getHours(); m = dt.getMinutes(); s = dt.getSeconds();alert(h+":"+m+":"+s);})();

時間関係ないの??

で、応募ページに飛べます。
https://regist.goo.ne.jp/summer2008/form.php
え?なにもかも関係ないの?

以上

Vistaでメニューが真っ黒になる

Vista使っておりますが、時々メニューが真っ黒になります。Firefox2で例えばGoogleツールバーの検索ボックスのサジェストが真っ黒になったりします。普通ならプルダウンで検索単語がいくつか表示されるところが真っ黒に塗りつぶされてしまいます。あるいはメニューなども同じようになります。「ツール」をクリックしたら真っ黒のプルダウンメニューが出てきます。なんですかこれは。最初はFirefoxの問題かと思っていたんですが、先日IEでもなりました。ググってもいまいちいい情報が出てこない。まあ、再描画させればすぐ直るんですが。
http://oshiete.slmame.com/e203548.html
これとかはセカンドライフですが見た目一緒なので原因も一緒なのかもしれません。そこそこの頻度で発生します。1日1回くらいかな。

↓再現イメージ図。
真っ黒イメージ図

だれか解決方法おしえてくだしあ。

以上

CakePHPではまったこと16(Mysqlでdeleteしたら1066??)

これすげー便利。
Ajaxとかでよく使うLoading中のgif画像をジェネレートとしてダウンロードさせてくれる。

そんなわけでCakePHP1.2ですが、Mysqlでもはまりました。
$this->Model->delete()をすると1066っつうエラーが出るという。
ただしこれはMysql4.0系だけの話かもしれません。
deleteでaliasに対応してないっぽいです。(またaliasか)
これに関してはnightly(24-01-2008)でもだめでした。
でどうしたかというと、dbo-source.phpの_delete()をdelete()に、delete()を_delete()に変更しました。
だって_delete()のコメントに

/**
* Generates and executes an SQL DELETE statement.
* For databases that do not support aliases in UPDATE queries.
*
* @param Model $model
* @param mixed $conditions
* @return boolean Success
*/

って書いてあったんだもん。
結果としては、動いてます。いいのかなぁ。

以上

CakePHPではまったこと15(sqliteを使っているときのupdate)

CakePHPの1.2を使い、さらにsqliteをデータベースとして使うという果敢なことをしています。
そういうわけで普通に使うであろうupdate処理を行うとエラーでた。
まあいわゆる
$this->Model->save($data);
なんですけどね。
新規insertは問題ないけど既存のデータを上書きするときです。

Warning (2): sqlite_query() [function.sqlite-query]: near “AS”: syntax error [CORE\cake\libs\model\datasources\dbo\dbo_sqlite.php, line 115]

“AS”の近くが変だと。ようするに”AS”が変だと。
そりゃあそうです。調べてみたらsqliteではupdate句でas(エイリアス)は使えないっていうじゃありませんか。
どうやって直したらいいのかと悩んでいたんですが、最新のソースでは直ってるそうです。
今までBETA:1.2.0.6311を使ってたんですが、nightlyに昇格しました。ますます果敢になりました。

以上

Windowsのハンドルやらファイルオープンやらのリーク?

前にも書いたとおり、VC++を使っている場合はメモリリークは簡単に検出できます。
でもオープンしたファイルをクローズしてなかったり、Windowsハンドルをクローズしてなかったりって言うのは検出できません。まあ、普通はプログラムが終了すればファイルとかはクローズされるかもしれませんが、怪しい場合もあるし、そこはちゃんと責任もってクローズしたほうがいいでしょう。

そういうわけで、面白そうなツールがリリースされていたのでポインタを置いておきます。
オブジェクトリークチェッカー
ヘッダをインクルードするだけという手軽さがいいですね。まだバージョンが0.1のようですが。
ただ、正直に申し上げますと現在VC環境がまだ整っていないので使ってみてません。
取り急ぎご報告まで。ということであしからず。

以上

VC++でメモリリークを発見する

やっぱり肩こりはいやだ・・・。

VCを用いている場合、crtdbg.hを使えば簡単にCやC++のメモリリークを発見することができる。
(以上既報)

やり方は簡単です。


#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>

ってな感じでヘッダをインクルードして、main関数の冒頭で


_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 

を実行すればよろしい。あとはデバッグ実行するだけ。プログラム終了後、出力ウインドウにリークしている箇所が表示されます。
#includeの前_CRTDBG_MAP_ALLOCを定義しておけば該当ソースファイル名もわかります。
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); の引数はなんだか忘れちゃったので、各々調べてください。

とまあ、こんな感じですが、なんかcrtdbg.hは頭悪いらしく、C++でクラスとかを使ってると上記のままだとリークしている箇所が正しく表示されません。
以下のようにするとOKです。


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

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>                // 最後にインクルードしたほうがいい気がする。C++の場合。標準ヘッダの中にnewとかあると変になる??
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)     // これが重要
#endif

int main(void)
{
   char *aznable;

   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

   aznable = (char *)malloc(3*sizeof(char));

   return 0;
}

newを再定義するのが重要です。正しくリーク位置を取得するためには、すべてのファイルでcrtdbg.hをインクルードする必要があり、newの再定義も必要になるので、


#ifndef MEMORY_LEAK_H
#define MEMORY_LEAK_H
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
#endif

みたいなmemory_leak.hを作ってこいつをみんなでインクルードしようぜ!って感じにするといいかもしんない。

参考文献 http://support.microsoft.com/kb/140858/ja

以上

インクリメントはインプリメント依存

o-taki氏からのタレコミです。
まずはC言語。
問題のコードは下記です。


#include <stdio.h>

int main(int argc, int *argv[]){
    int a[2][2] = {{6,8},{100,120}};    // ①
    int *t = *a;        // ②
    int **l = &t-1;    // ③

    printf("%d\n",++*++*++l*++*++*l++);   // ④
    
    return 0;
}

まあ、②、③のあたりでやや意味不明ですが、要はlはtのアドレスの一個手前だからaの一個手前、つまり何もないところ指してる。多分、直接**lにアクセスすると怒られると思われます。

④の所を解析すると、演算子の優先順位を考えると


++*++*++l*++*++*l++

= ++*++(*(++l)) * ++*++(*(l++))

= (++(*(++(*(++l))))) * (++(*(++(*(l++)))))

= (++(*(++(*(++l))))) * (++(*(++(*(l++)))))      //  ⑤

になるんじゃないかと思います。ややこしいことは間違いないですが、問題は「後置インクリメントがどのタイミングで評価されるのか」ということに集約されると思います。
まず、⑤の最初の大きな括弧


(++(*(++(*(++l)))))   // ⑤-i

が最終的にどこを指しているか考えます。a[][]のメモリ領域を便宜的に下記の表現すると、


Z.a:0   Z.b:0
A.a:6   A.b:8
B.a:100  B.b:120

初期状態でlはZ(=Z.a)を指しています。順を追うと、


(++l) => A (=A.a)
(*(++l)) => A.a
(++(*(++l))) => A.b   // ⑥
</code></pre>
したがって最後の
<pre><code>
(++(*(++(*(++l)))))

でA.bの値が8から9に変更されます。
注意すべきは、最後の時点でlが指している先はA.bです。(多分)
⑥のインクリメントは*lに対するインクリメントですが、*lもlも一緒な気がします。

で、⑤の二つめの大きな括弧(これが問題)


(++(*(++(*(l++)))))     // ⑤-ii

も同様に考えると


(l++) => A (=A.b)   // ⑦
(*(++l)) => A.b
(++(*(++l))) => B.a

というわけで、⑦は後置のため、参照される段階ではまだインクリメントされません。(多分)
したがって最後の


(++(*(++(*(l++))))) 

でB.aの値が100から101に変更されます。

ということは、④=⑤=


(++(*(++(*(++l))))) * (++(*(++(*(l++))))) 

は9*101=909になります。
といいたいところなんですけど、コンパイラの実装依存ぽい感があります。まあ、上の解析が間違っている可能性も大ですが、最初のmainをコンパイルして実行すると、
・cygwin gcc ⇒ 909
・cygwin g++ ⇒ 909
・VC6 ⇒ 909
・VC2005 ⇒ 10201
謎です。VC2005。
これを解釈するには、二項演算子*は最後に評価されるため、前半の括弧(⑤-i)と後半の括弧(⑤-ii)の前置インクリメントが評価された後のlを考えれば、説明が付くような、付かないような・・・。

次にPerl。
超単純な次のコード。


$i = 1;

print ++$i + $i++;
print "\n";

$i = 1;
print $i++ + ++$i;
print "\n";

$i = 1;
print $i++ + $i++;

最初の出力は後置インクリメントなわけですから、2+2=4と表示されると思われたんですが結果は5。謎。
上記結果は下記のようになります。


5
4
3

全く謎。

Cでやると


 i = 1;
 printf("%d\n", ++i + i++);

 i = 1;
 printf("%d\n", i++ + ++i);

 i = 1;
 printf("%d\n", i++ + i++);

もちろん結果は


4
4
2

よって、結論!
インクリメントは使ってはならない。ルビーのように。

追記:2009-04-27
匿名さんのコメントより
>少なくともC/C++言語仕様上、副作用完了点の前に同じ変数を複数回変更した結果は「未定義(undefined)」です。
ということらしいです。他の言語についてまだ調べてませんが、言語使用上は動作を規定する義務はないので、どうなろうが知ったこっちゃないという。そうだったのか・・・。
まあ結論は同じで、そんな変なインクリメントをするなってことだと思います。

以上

Home > バグ Archive

Search
Feeds
Meta
 合計:000240
 今日:0112 昨日:0128

Return to page top