[Mono-list] passing and returning structs in native calls

Edd Barrett vext01 at gmail.com
Fri Jan 7 10:19:56 EST 2011


Hi,

(hopefully the right mailing list)

I am trying to write some bindings to some C code. I have managed to
correctly call native functions *without* structs in their signature,
but for some reason, calling this function is causing problems:

---8<---
struct Lit
msc_mk_lit(int var)
{
        struct Lit              l;

        if (msc_debug)
                std::cerr << __func__ << ": new lit from  " << var << std::endl;

        l = mkLit(var);

        if (msc_debug)
                std::cerr << __func__ << ": new lit " << l.x << std::endl;

        return l;
}
---8<---

The Lit stuct is from a C++ library and is defined as such:

---8<---
struct Lit {
    int     x;

    // Use this as a constructor:
    friend Lit mkLit(Var var, bool sign = false);

    bool operator == (Lit p) const { return x == p.x; }
    bool operator != (Lit p) const { return x != p.x; }
    bool operator <  (Lit p) const { return x < p.x;  }
};
---8<---

(note the operator overloading and friend method - AFAIK that does not change
the binary representation of the struct)

My C# looks like this:

---8<---
[StructLayout(LayoutKind.Sequential)]
public struct Lit {
        public int x;
};

unsafe class Solver {

...

[DllImport ("libminisatc")]
private static extern Lit msc_mk_lit(int s);

...

public Literal NewLiteral()
{
	int v = msc_new_var(solver_p);
	Console.WriteLine("C#: New var " + v);
	Lit lit_s = msc_mk_lit(v);
	Console.WriteLine("C#: New literal " + lit_s);

	Literal l = new Literal(lit_s);
	return l;
}
---8<---

The resulting output (which includes library debugging to stderr):

---8<---
% mono Monosat.exe
msc_new_solver: new 0x7cbf4800
msc_new_var: new var 0
C#: New var 0
msc_mk_lit: new lit from  -809763284
msc_mk_lit: new lit -1619526568
C#: New literal Monosat.Lit
msc_add_clause: add 1
Stacktrace:

  at (wrapper managed-to-native) Monosat.Solver.msc_add_clause (void*,Monosat.Lit[]&,int) <0x00003>
  at (wrapper managed-to-native) Monosat.Solver.msc_add_clause (void*,Monosat.Lit[]&,int) <0x00003>
  at Monosat.Solver.AddClause (Monosat.Literal[]) <0x0007b>
  at Monosat.Test.Main (string[]) <0x0007b>
  at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <0x00073>
zsh: abort (core dumped)  mono Monosat.exe
---8<---

The stacktrace is irrelevent, as the failure happened way before the crash:
  * C# has an integer variable (v) whos value is 0. (C#: New var 0)
  * This is passed to the natve function: Lit lit_s = msc_mk_lit(v);
  * C code prints out the integer immediately as the wrong value.

Why is this? Myself and a colleague have spent a number of hours trying
to work this out.

Changing the function to return the integer within the struct instead of
the struct itself works as expected, but that is not really what I want.

I am using an amd64 machine on OpenBSD (which uses fastcall by default,
is this the issue? I know microsoft mono does not support fastcall.
Having said that, openbsd has working packages of gtk#, for example.)

Or perhaps this is a mono bug... I'm completely stuck at this point.

-- 
Best Regards
Edd Barrett

http://www.theunixzoo.co.uk


More information about the Mono-list mailing list