Tietew です。

On Mon, 20 Oct 2003 23:53:22 +0900
In article <20031020232800.AA1F.ARTONX / yahoo.co.jp>
[[ruby-list:38619] dl and win32 API call]
arton <artonx / yahoo.co.jp> wrote:

> win32に特化した問題ですが、ruby-win32が止まっているようなのでこちらに振
> ります。

まだ止まってますか?

> 主題:ruby-1.8.0添付のdlを利用してWIN32 APIを呼び出すとスタックポインタ
> がずれる。元の話題はhttp://www.tietew.jp/beckrb/msg00113.html です。
> 詳細:WIN32 APIでは、引数のスタックからのポップを呼ばれた側が実行する。
> しかし、dlは関数呼出し後に引数をスタックからポップする。そのため、引数の
> 分だけ余分にスタックポインタがポップされてしまう。

問題提起拾ってもらったのにほっぽってしまってすみません。

上記に関連して,MSVC のランタイムスタックチェックをすり抜けられ
るパッチを作ってみました。(-RTCs を付けていても abort しない)

mswin32 でしか確認できてないのですが,呼び出しが終わった後,全て
のレジスタが正常になっていることを確認しています。

i686-linux でのコンパイルでも,dl.so の make test は正常に終了し
ました。

alloca を呼ぶとスタックフレームが保存されるというコンパイラの仕
様をアテにしているので,他の環境でも問題ないか検証をお願いしたい
です。



Index: ext/Win32API/Win32API.c
===================================================================
RCS file: /src/ruby/ext/Win32API/Win32API.c,v
retrieving revision 1.19
diff -p -u -2 -r1.19 Win32API.c
--- ext/Win32API/Win32API.c	13 Aug 2003 04:52:35 -0000	1.19
+++ ext/Win32API/Win32API.c	21 Nov 2003 05:13:24 -0000
@@ -138,4 +138,22 @@ Win32API_initialize(self, dllname, proc,
 }
 
+#ifdef __MSVC_RUNTIME_CHECKS
+# pragma runtime_checks("s", off)
+#endif
+#ifdef _MSC_VER
+__declspec(noinline)
+#endif
+static unsigned long
+CallApiFunction(ApiFunction, param)
+    FARPROC ApiFunction;
+    struct { unsigned long params[16]; } param;
+{
+    volatile char *guard = ALLOCA_N(char, 1); /* guard stack pointer */
+    return ApiFunction(param);
+}
+#ifdef __MSVC_RUNTIME_CHECKS
+# pragma runtime_checks("s", restore)
+#endif
+
 static VALUE
 Win32API_Call(argc, argv, obj)
@@ -189,5 +207,5 @@ Win32API_Call(argc, argv, obj)
     }
 
-    ret = ApiFunction(param);
+    ret = CallApiFunction(ApiFunction, param);
 
     switch (FIX2INT(obj_export)) {
Index: ext/dl/dl.h
===================================================================
RCS file: /src/ruby/ext/dl/dl.h,v
retrieving revision 1.8
diff -p -u -2 -r1.8 dl.h
--- ext/dl/dl.h	7 Nov 2002 16:42:07 -0000	1.8
+++ ext/dl/dl.h	21 Nov 2003 05:13:24 -0000
@@ -171,4 +171,5 @@
 #elif defined(USE_DLSTACK)
 # define DLSTACK
+# define DLSTACK_GUARD
 # define DLSTACK_METHOD "dl"
 # define DLSTACK_PROTO long,long,long,long,long,\
Index: ext/dl/sym.c
===================================================================
RCS file: /src/ruby/ext/dl/sym.c,v
retrieving revision 1.21
diff -p -u -2 -r1.21 sym.c
--- ext/dl/sym.c	8 Nov 2003 13:32:07 -0000	1.21
+++ ext/dl/sym.c	21 Nov 2003 05:13:24 -0000
@@ -353,4 +353,88 @@ rb_dl_win32_set_last_error(VALUE self, V
 #endif
 
+#ifdef DLSTACK_GUARD
+# ifdef __MSVC_RUNTIME_CHECKS
+# pragma runtime_checks("s", off)
+# endif
+#ifdef _MSC_VER
+__declspec(noinline)
+#endif
+static int
+rb_dlsym_guardcall(char type, ANY_TYPE *ret, long *stack, void *func)
+{
+  volatile char *guard = ALLOCA_N(char, 1); /* guard stack pointer */
+  switch(type){
+  case '0':
+    {
+      void (*f)(DLSTACK_PROTO) = func;
+      f(DLSTACK_ARGS);
+    }
+    break;
+  case 'P':
+  case 'p':
+    {
+      void * (*f)(DLSTACK_PROTO) = func;
+      ret->p = f(DLSTACK_ARGS);
+    }
+    break;
+  case 'C':
+  case 'c':
+    {
+      char (*f)(DLSTACK_PROTO) = func;
+      ret->c = f(DLSTACK_ARGS);
+    }
+    break;
+  case 'H':
+  case 'h':
+    {
+      short (*f)(DLSTACK_PROTO) = func;
+      ret->h = f(DLSTACK_ARGS);
+    }
+    break;
+  case 'I':
+  case 'i':
+    {
+      int (*f)(DLSTACK_PROTO) = func;
+      ret->i = f(DLSTACK_ARGS);
+    }
+    break;
+  case 'L':
+  case 'l':
+    {
+      long (*f)(DLSTACK_PROTO) = func;
+      ret->l = f(DLSTACK_ARGS);
+    }
+    break;
+  case 'F':
+  case 'f':
+    {
+      float (*f)(DLSTACK_PROTO) = func;
+      ret->f = f(DLSTACK_ARGS);
+    }
+    break;
+  case 'D':
+  case 'd':
+    {
+      double (*f)(DLSTACK_PROTO) = func;
+      ret->d = f(DLSTACK_ARGS);
+    }
+    break;
+  case 'S':
+  case 's':
+    {
+      char * (*f)(DLSTACK_PROTO) = func;
+      ret->s = f(DLSTACK_ARGS);
+    }
+    break;
+  default:
+    return 0;
+  }
+  return 1;
+}
+# ifdef __MSVC_RUNTIME_CHECKS
+# pragma runtime_checks("s", restore)
+# endif
+#endif /* defined(DLSTACK_GUARD) */
+
 VALUE
 rb_dlsym_call(int argc, VALUE argv[], VALUE self)
@@ -643,4 +727,10 @@ rb_dlsym_call(int argc, VALUE argv[], VA
   DLSTACK_END(sym->type);
 
+#ifdef DLSTACK_GUARD
+  if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, func)) {
+    FREE_ARGS;
+    rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
+  }
+#else /* defined(DLSTACK_GUARD) */
   {
     switch( sym->type[0] ){
@@ -712,4 +802,5 @@ rb_dlsym_call(int argc, VALUE argv[], VA
     }
   }
+#endif /* defubed(DLSTACK_GUARD) */
 
   {


―[ Tietew ]――――――――――――――――――――――――――
 メ : tietew / tietew.net / tietew / raug.net / tietew / masuclub.net
ホペ: http://www.tietew.net/     Tietew Windows Lab.
      http://www.masuclub.net/   鱒倶楽部
指紋: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA