"Manuel M. T. Chakravarty" <[EMAIL PROTECTED]> wrote,

> If I link
> 
>   import Addr (Addr, nullAddr)
> 
>   foreign import ccall "foo" foo :: Int -> Addr -> IO ()
> 
>   main = foo (id 32) nullAddr
> 
> with
> 
>   void foo (int x, char *y)
>   {
>     printf ("foo: x = %d; y = %xl\n", x, (long) y);
>   }
> 
> I get
> 
>   foo: x = 134516888; y = 0l

After closer inspection of the generated C code, I found an
explanation of the problem.  The reason is a mistake in the
C code generation for the primitive `_ccall_GC_'.  It
becomes apparent when considering the C generated for

  foo x y = _ccall_GC_ foo x y

In STG, this turns into a case cascade including 

  {-_ccall-}__ccall_GC foo [c1nt x4 x6]

(this is an expression scrutinized in one of the case).  The
C code emitted for this STG expression is

  IFN_(c1nF_ret) {
          FB_
          Sp[1]=(W_)((P_)&c1nG_info);
          Sp=Sp+1;
          {
          I_ _ccall_arg1=(I_)(*Sp);
          StgAddr _ccall_arg2=(StgAddr)(R1.p[1]);
          do { SaveThreadState();
          (foo((_ccall_arg1),(_ccall_arg2)));
          LoadThreadState();} while(0);
          }
          JMP_(((P_)(*Sp)));
          FE_
  }
  
Unfortunately, the topmost stack location, where the
(unboxed) first argument to `foo' sits is recycled and used
for `&c1nG_info' before the line

          I_ _ccall_arg1=(I_)(*Sp);

extracts the value of the first argument.  So, the address
of `c1nG_info' is passed to `foo' instead of the correct
value. 

Hope this helps,

Manuel

Reply via email to