2011-11-02
■[プログラミング言語 C++]VisualStudio2008 SP1 vectorのバグ?
以下のプログラムはstd::allocatorを継承して自作アロケータを作成し、実際よりも32byte多めに確保してその前後に
固定値を入れ、解放時に固定地を書き込んだ領域に不正書き込みがないか確認するものである。
#include <stdio.h> #include <map> #include <vector> #include <string> struct Data { std::string file; int line; size_t size; }; static std::map<void*, Data> data_; /*! * @brief アロケータクラスを提供します。 */ template <class T> class CAllocator : public std::allocator<T> { public: typedef typename std::allocator<T>::size_type size_type; typedef typename std::allocator<T>::pointer pointer; template<typename U> struct rebind { typedef CAllocator<U> other; }; CAllocator() {} CAllocator(const CAllocator<T> &) {} template <class U> CAllocator(const CAllocator<U> &) {} // メモリを割り当てる pointer allocate(size_type size, const void* hint = 0) { Data data; char* p = ::new char[size + 32]; memset(p, 0xFD, 16); memset(p + size + 16, 0xFE, 16); data.size = size; p += 16; data_[p] = data; printf("alloc 0x%p size:%u\n", p, size); return reinterpret_cast<pointer>(p); } // メモリを解放する void deallocate(pointer p, size_type num) { printf("deallocate 0x%p\n", p); if (data_.count(p) != 0) { Data data = data_[p]; char* pp = reinterpret_cast<char*>(p) - 16; size_t end_off = data.size + 16; for (int i = 0; i < 16; ++i) { unsigned char c1 = pp[i]; unsigned char c2 = pp[end_off + i]; if (c1 != 0xFD) { // 先頭16バイトが不正アクセスされた // printf("0x%02x %pの前方に不正アクセス FILE:%s LINE:%d\n", c1, p, data.file.c_str(), data.line); printf("0x%02x %pの前方に不正アクセス\n", c1, p); } if (c2 != 0xFE) { // 先頭16バイトが不正アクセスされた // printf("0x%02x %pの後方に不正アクセス FILE:%s LINE:%d\n", c2, p, data.file.c_str(), data.line); printf("0x%02x %pの後方に不正アクセス\n", c2, p); } } ::delete pp; data_.erase(pp); } else { // 登録されていない不正なポインタ } } // 割当てることができる最大の要素数を返す size_type max_size() const { return 100 * 1024 * 1024; } }; int main() { std::vector<char, CAllocator<char> > buf(100); }
このプログラムを起動した場合、期待する出力というのは以下となる
alloc 0x00678EF0 size:100 deallocate 0x00678EF0
アドレスは環境によってことなるが、期待する動作はこれである。VS2008で起動した場合はこの結果が得られた…Debugビルドではな!
Releaseビルドして実行すると驚くべき結果になった
alloc 0x00098F60 size:1 alloc 0x00091730 size:100 deallocate 0x00091730 deallocate 0x00098F60 0xfb 00098F60の後方に不正アクセス 0x1d 00098F60の後方に不正アクセス 0x00 00098F60の後方に不正アクセス
これはいったいどういうことだ!
size1の領域取得、さっぱりわからん。いったい何のために取得しているんだ。
取得と解放のログを見る限り、1byteの確保と100byteの確保は別の目的で使用されているらしい。
解放ログが100byte解放の後に1byte解放しているからね。
しかし、その後不正アクセスが入っている。グローバルnewで確保している以上、確保領域が被ることはない
つまり、何かしらの理由で不正アクセスがされているのは確定である。誰か説明して><
2011-09-15
■[ゲーム製作]プライオリティ描画管理
以前まではスプライト描画用の構造体を作って、その構造体を保存しておき
ソートをかけて描画するという手法をとっていたわけだが、結構メモリを消費するのと
数を増やしづらいというのがあったので、新しい手法として関数単位のソートを書くようにしてみた。
class DrawList { public : typedef void (*DrawFunc)(void* arg1, void* arg2); DrawList(int n) : data_(n){} void Clear() { for (unsigned int i = 0; i < data_.size(); ++i) { data_[i].clear(); } } void Set(DrawFunc func, void* arg1, void* arg2, int prt) { Data data; data.func = func; data.arg1 = arg1; data.arg2 = arg2; data_[prt].push_back(data); } void Draw() { for (unsigned int i = 0; i < data_.size(); ++i) { std::list<Data>::iterator it = data_[i].begin(); for (; it != data_[i].end(); ++it) { (it->func)(it->arg1, it->arg2); } } } private : struct Data { DrawFunc func; void* arg1; void* arg2; }; std::vector<std::list<Data> > data_; };
2011-08-10
2010-03-26
■[PS3]PS3開発始めました
こっちの日記長いこと書いていませんね
なぜならやる気がないから(キリィ
PS3の仕事を請け負い、現在勉強中なのですがどうもやる気がでません。
たぶん一人だからですね。
正直なところ職場でプログラマ一人という環境に限界を感じています。
周りとプログラムの話をできないというのが苦痛で仕方ありません。
今の会社に入ったばかりの頃は、新しい職場ということで気が引き締まっていましたが
今では仕事中にゲーム三昧という体たらく。
それでもまぁ仕事なので一応やりますけどね。
PS3の中身はOpenGL ES+拡張API+Cg(シェーダ)
サウンドは、CRIに任せちゃいます。
画像表示以外のところのライブラリは一通り完成しました
画像表示は終わっているので、文字表示とレンダリングターゲット変更と
出力時にテレビサイズに合わせるのをやれば、ライブラリは一通り完成です。
やる気があればとっくに終わっているのですが、やる気がないのでなかなか終わりませんマル
melpon
だから上司に相談しなさいとあれほど・・・
わい
PS3ですかぁ〜。大変そうですがうらやましいです。でも、1人はきついですね。世間は、春で旅立ちの季節となっていますが、わたしっも旅立ちたい気分です。しかし、不景気でなかなか・・・。とりあえず、個人でやれることを、やり始めたところです。1人で開発となると、精神面で大変そうですが、電車から見える(通勤が電車であれば)サクラでも見て、がんばってください〜。コンシューマ開発したい人間なんて山ほどいるんですから。
GPGA
コメントもらったのに返信遅れて申し訳ない
最近自分のブログみないんですよ^^
>melpon
相談はしてるけど、プログラマは自分で連れてこいと・・・
まぁ当たり前っちゃあたりまえ
>わいさん
限界を感じているのはモチベーションのほうでして
別に技術面とか仕事の内容に限界を感じているわけではないです。
用語とか覚えるのは面倒ですけどね。

T じゃないと rebind されたときに困るので。
今回の場合だと 32 バイト余分に確保するので、new char[sizeof(T)*count+32] だけ領域を確保すればいいかと(16バイトもあれば T が十分アライメントされる前提として)。
あと deallocate の第1引数にはポインタが、第2引数には、生成時に要求した要素数が渡されるのに、num を一切使ってないので、本来有効な領域を調べているのがその表示になる直接の原因かと。
ので多分rebindの方が問題になってるかと
で、多分今回は、そのsize:1と出力されているときのTの型はcharではない別の型のアロケータを使っている気がする。
そうすると、sizeof(T)*sizeだけのメモリが必要なのにも関わらず、有効なメモリとしてはsizeof(char)*sizeしか確保していないので、そりゃアクセス違反になりますよねっていう。