2017年5月2日火曜日

palloc で access violation … Visual Studio 2005 で作った PostgreSQL 8.2 の C 関数にて

BUILDING_DLL を定義したらダメみたいです。

参考: Re: Access violation from palloc, Visual Studio 2005, C-language function

include/server/utils/palloc.h に定義があります。

/*
 * Type MemoryContextData is declared in nodes/memnodes.h. Most users
 * of memory allocation should just treat it as an abstract type, so we
 * do not provide the struct contents here.
 */
typedef struct MemoryContextData *MemoryContext;

/*
 * CurrentMemoryContext is the default allocation context for palloc().
 * We declare it here so that palloc() can be a macro. Avoid accessing it
 * directly!  Instead, use MemoryContextSwitchTo() to change the setting.
 */
extern DLLIMPORT MemoryContext CurrentMemoryContext;

/*
 * Fundamental memory-allocation operations (more are in utils/memutils.h)
 */
extern void *MemoryContextAlloc(MemoryContext context, Size size);
extern void *MemoryContextAllocZero(MemoryContext context, Size size);
extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size);

#define palloc(sz) MemoryContextAlloc(CurrentMemoryContext, (sz))

#define palloc0(sz) MemoryContextAllocZero(CurrentMemoryContext, (sz))

MemoryContextAlloc や CurrentMemoryContext は、インポートライブラリを利用して postgres.exe プロセスからインポートします。

---
結論から申しますと、つぎのようにあるべきが、

extern __declspec (dllimport) MemoryContext CurrentMemoryContext;

BUILDING_DLL を定義することで、つぎのように変化することが問題でした。

extern __declspec (dllexport) MemoryContext CurrentMemoryContext;

---
それでは納得できないこともあろうかと、アセンブラレベルで解析もしました。

palloc するだけの C 関数:
PG_FUNCTION_INFO_V1(ddtest);
Datum ddtest(PG_FUNCTION_ARGS) {
 palloc(0x123456);
 PG_RETURN_NULL();
}

まず、
extern __declspec (dllimport) MemoryContext CurrentMemoryContext; となる場合。


緑下線を引いた部分 100470F8 が CurrentMemoryContext の実体のアドレスです。そこに意味のあるコードはありませんが一応。88 87 04 00 の部分が MemoryContextSwitchTo を呼び出すことで、本来の値に書き換えられるわけです。


つぎに、
extern __declspec (dllexport) MemoryContext CurrentMemoryContext; となる場合。


緑下線を引いた部分が <CurrentMemoryContext> になっています。一見これが正解じゃないかと思いますが、参照先は jmp dword ptr [0x100470f8] の命令コードです。



0x70f825ff に 4 を足した 0x70f82603 にアクセスしようとして、access violation が発生することが冒頭のエラーにつながります。

『postgres.exe の 0x005fbb4a で初回の例外が発生しました: 0xC0000005: 場所 0x70f82603 を読み込み中にアクセス違反が発生しました。』

外部の exe/dll からインポートする変数は、__declspec (dllimport) を使いましょう。

0 件のコメント:

コメントを投稿