Library liba defines a certain function f. When writing a C program that uses function f, compilation will not complete unless I add -lb to the compilation command, even though I don't refer to anything from libb directly in my C code. Using p/invoke, however, I don't have the option of linking to library b and when I call function f (after a [DllImport("liba")], of course) from within my C# code I get a symbol lookup error: /usr/lib/liba.so: undefined symbol: X (X is defined within libb). ldd /usr/lib/liba.so does not contain a row referring to libb. libb is in /usr/lib. I believe this question is essentially the same as Linux, Mono, shared libs and unresolved symbols, but unlike in that case I cannot recompile liba. Is there any way to resolve this problem?
You can also DllImport a function from libb before reaching the code that p/invokes from liba: this will cause libb to be loaded in the process as well.
This is a poor solution, but it might be the best possible under the circumstances: running the resulting mono binary with
LD_PRELOAD=libb.so ./binary.exe
avoids the problem.
Found a good general solution, exemplified in the code below:
class MainClass
{
//Constants from /usr/include/bits/dlfcn.h
private const int RTLD_LAZY = 0x00001; //Only resolve symbols as needed
private const int RTLD_GLOBAL = 0x00100; //Make symbols available to libraries loaded later
[DllImport("dl")]
private static extern IntPtr dlopen (string file, int mode);
[DllImport("a")]
private static extern void f ();
public static void Main (string[] args)
{
//Load libb. RTLD_LAZY could be replaced with RTLD_NOW, but
//RTLD_GLOBAL is essential
dlopen("libb.so", RTLD_LAZY|RTLD_GLOBAL);
//Call f(), no unresolved symbol problem!
f();
}
}
Related
Here's the scenario I am confronted with:
in a simple DLL, written in C, there are functions which access files, for example:
DLL_EXPORT void Virt_Hello(void) {
FILE *f = fopen("Hello_world", "w");
if (f) {
fprintf(f, "Hello world!\n");
}
fclose(f);
}
in the managed code:
[SuppressUnmanagedCodeSecurity]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void Virt_HelloDelegate();
private IntPtr m_helloPtr;
m_helloPtr = GetProcAddress(m_libraryPtr, "Virt_Hello");
Virt_Hello = Virt_HelloDelegate)Marshal.GetDelegateForFunctionPointer(m_helloPtr, typeof(Virt_HelloDelegate));
and later, this function is called as:
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public void Hello()
{
Virt_Hello();
}
I've been reading for the last couple of days pretty much everything I could find on this topic however it still doesn't work: the file is not open, and the calling managed code/process just hangs - no exceptions are thrown either.
Tried StdCall calling convention, changed several parameters on the SecurityPermission attribute - to no avail. I've even made sure all assembly dependencies are signed.
Of course I would prefer to integrate it through C++/CLI instead of PInvoke-ing however the DLL is a blackbox for me.
Any help or suggestion how to go forward would be much appreciated.
I'm pretty sure I'm missing something obvious but right now I just can't see it.
My best regards to the community!
I’ve compiled libsass 3.3.6 into a DLL with VS 2015 using the included solution files. Running the code below causes the program to crash immediately with no output.
using System;
using System.Runtime.InteropServices;
namespace Sass.Cli {
static class Sass {
[DllImport(#"C:\...\libsass\win\bin\libsass.dll")]
public static extern String libsass_version();
}
class Program {
static void Main(string[] args) {
Console.WriteLine(Sass.libsass_version());
}
}
}
The source for the invoked function is at sass.cpp:61.
const char* ADDCALL libsass_version(void)
Both the DLL and the above code were compiled for x86. Running the VS debugger on crash gives me the following exception: Unhandled exception at 0x771A9841 (ntdll.dll) in Sass.Cli.exe: 0xC0000374: A heap has been corrupted (parameters: 0x771DC8D0).
Is this something that can be fixed or that I’ve overlooked? Or is it just the case that libsass DLLs aren’t currently working?
When a string is used as a return type then the framework assumes it was allocated by calling CoTaskMemAlloc. It then copies the content of the string and deallocation by calling CoTaskMemFree. That is the explanation for your error.
Solve it by changing the return value to IntPtr and getting the string content with Marshal.PtrToStringAnsi. You won't need to deal located anything since this version string will be static.
I can't tell what the calling convention is. You should check the code and docs to find out. Still, this function is so simple that it behaves the same way for both cdecl and stdcall so that can't explain the error. Still, you will need to get it right for the rest of the library.
Note that I am guessing a little here. You've not provided full details. You should consult the code and docs to double check my guesswork.
Using embedded Mono, I'm trying to execute a very simple C function from within C#.
This is the function in C++ code (in global scope):
extern "C"
{
static int __attribute__((noinline)) dllImportTest()
{
return 66;
}
}
This is the C# code:
[DllImport("__Internal", EntryPoint="dllImportTest")]
public static extern int dllImportTest();
public void testCFunctions()
{
int dllImport = dllImportTest();
System.Console.Write("Got dllImport: " + dllImport + "\n");
}
And this is the error I get:
System.EntryPointNotFoundException: dllImportTest
at (wrapper managed-to-native) MonoGlue.ATestClass:dllImportTest ()
at MonoGlue.ATestClass.testCFunctions () [0x0000a] in <9effaf2265b34fbcb9a10abd58c42ed7>:0
I've been looking at examples and similar problems, but I fail to see what is going wrong. To make sure the C function does not get optimized away, I execute it in the C++ code.
I even prevent inlining, as you can see.
However, still no luck. There must still be something I'm missing.
Turns out the dllImportTest function did not appear in the executable due to it being static. Admittedly, a static function in the global namespace makes little sense in most situations anyway.
So replacing this:
extern "C"
{
static int __attribute__((noinline)) dllImportTest()
{
return 66;
}
}
With this:
extern "C"
{
int __attribute__((noinline)) dllImportTest()
{
return 66;
}
}
Solves the problem.
The reason is that by making a function in global namespace static, it becomes inaccessible to external compilation units, which makes it inaccessible to C# as well (I had incorrectly assumed that this wouldn't affect the C# access).
Things become a little complicated here, so if you want to inform yourself, go ahead and read about compilation units.
If you do require to access a static function (no matter in which namespace), I recommend the "Internal Call" approach - as seen in the official mono example. It has many other benefits, as well.
In my c# code I need to call a c++ function (myWrapper) that is exported by a dll that I've created.
When myWrapper returns I get the following runtime error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
As I will show below, I already specified the calling conventions a __cdecl.
In detail, my C# code:
class myClass
{
[DllImport("MyWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void myWrapper();
public void myMethod()
{
myWrapper();
}
}
c++ code for myWrapper:
#include "IpIpoptApplication.hpp"
extern "C" __declspec(dllexport) void (__cdecl myWrapper)()
{
SmartPtr<IpoptApplication> solver = IpoptApplicationFactory();
ApplicationReturnStatus status = solver->Initialize();
}
The IpoptAppliationFactory function is imported from an external dll in IpOptApplication.hpp (which is part of an open source project and can be viewed from https://projects.coin-or.org/svn/Ipopt/stable/3.11/Ipopt/src/Interfaces/IpIpoptApplication.hpp) with this line:
extern "C" __declspec(dllexport) class Ipopt::IpoptApplication * __cdecl IpoptApplicationFactory();
The strange thing is that the error happens only when "solver->Initialize()" in myWrapper is called. If I comment the call to this method myWrapper returns without errors.
The problem is not related to the definition of "Ipopt::IpoptApplication", nor in the implementation of IpoptApplicationFactory() or Initialize() because 1) they are from a well known open source project (http://www.coin-or.org/projects/Ipopt.xml) used by thousands of programmers, 2) myWrapper works correctly if used in a standalone executable written in c++ code.
I've already googled for hours and I believe that the problem is in the way I call myWrapper but I can't find a solution.
Can anyone give me some suggestion? Thanks a lot.
Roberto
Thanks to Hans Passant the problem has been solved. I must compile "myWrapper" in release mode.
IPOPT DLLS CAN BE COMPILED ONLY IN RELEASE MODE (see readme.txt distributed with IpOpt dlls)! I've set the configuration manager to compile this project always in release mode (even when the solution is in debug).
To debug my myWrapper function (which calls IpOpt dlls), it's necessary to set in the properties of my StartUp project, the check box "Enable unmanaged code debugging"
Since unmanaged code debugging does not allow code modifications during debug, I keep diabled this if I don't need to debug myWrapper.
I hope this will help
I am currently working on a project with really short deadline, so I don't have much time to understand everything. Also, I am not an expert in C++ development and memory management.
So, what I am trying to do is to create a DLL in with both C and C++ code. Then, I would like to call this DLL in a C# code. Currently, the communication between C++ and C# is OK. The problem comes up when I try to transfer a string from the DLL to the C# code. The error is this one :
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
at NMSPRecognitionWrapper.Program.<Main>b__0() in <my dir>\Program.cs:line 54
at NMSPRecognitionWrapper.Program.StartRecognitionExt()
at NMSPRecognitionWrapper.Program.Main(String[] args) in <my dir>\Program.cs:line 60
Also, I can give you some piece of code below (really simplified !). Actually, the C++ expose two methods : StartRecognition() launch operations to get some data from microphone, then process them and store the results. GetResults() return an instance of the results previously stored. The WrapperCallback() allows the C# part to be called when a Result is able for processing. The C# part, when the Callback is called, will ask to get the results using the GetResults() method.
I know the architecture may seem really inappropriate in this presentation, but I don't want to explain the whole project to validate the model, please be sure everything is correct.
To finish, the problem is when the C# callback call the GetResults() method. Trying to access to the resultsForCS seems to be impossible from the C#.
C++ part - header
// NMSPRecognitionLib.h
#pragma once
#include <iostream>
using namespace std;
extern "C" __declspec(dllexport) char* GetResults();
extern "C" static void DoWork();
extern "C" __declspec(dllexport) void StartRecognition();
C++ part - sources
#include "stdafx.h"
#include "NMSPRecognitionLib.h"
static char * resultsForCS;
static SUCCESS ProcessResult(NMSPCONNECTION_OBJECTS *pNmspConnectionObjects, LH_OBJECT hResult)
{
[...]
char* szResult;
[...]
resultsForCS = szResult;
DoWork();
[...]
return Success;
error:
return Failure;
} /* End of ProcessResult */
extern "C" __declspec(dllexport) char* GetResults()
{
return resultsForCS;
}
extern "C"
{
typedef void (*callback_function)();
callback_function gCBF;
__declspec(dllexport) void WrapperCallback(callback_function callback) {
gCBF = callback;
}
static void DoWork() {
gCBF();
}
}
extern "C" __declspec(dllexport) void StartRecognition()
{
char* argv[] = { "path", "params" };
entryPoint(2, argv);
}
C# part
class Program
{
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetResultsExt();
public delegate void message_callback_delegate();
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "WrapperCallback")]
public static extern void WrapperCallbackExt(message_callback_delegate callback);
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "StartRecognition")]
public static extern void StartRecognitionExt();
static void Main(string[] args)
{
WrapperCallbackExt(
delegate()
{
Console.WriteLine(GetResultsExt());
}
);
StartRecognitionExt();
Console.WriteLine("\nPress any key to finish... ");
var nothing = Console.ReadLine();
}
}
I understand that the problem comes because I am using a pointer to store the results (char *), but I actually don't know how to do this in another way. The szResults type is char * too and I can't change this !
Yes, the return type is the problem. The pinvoke marshaller must do something to release the memory that was allocated for the string. The contract is that memory allocations that need to be released by the caller must be allocated from the COM heap. CoTaskMemAlloc() in native code, also exposed in .NET as Marshal.AllocCoTaskMem().
This rarely comes to a good end, most native code allocates with malloc() or ::operator new, allocating from a heap that's created by the C runtime library. The wrong heap. So inevitably the CoTaskMemFree() call will fail. Ignored silently in Windows XP and earlier, a kaboom on Vista and up.
You must stop the pinvoke marshaller from trying to release the memory. Do so by declaring the return value as IntPtr. And use Marshal.PtrToStringAnsi() to recover the string.
You still have a Big Problem, the kind of problem that bedevils any native code that tries to use this function as well. You still have a string buffer that needs to be released. You cannot do that from C#, you can't pinvoke the correct version of free() or ::operator delete. A memory leak is inevitable. The only thing you can hope for is that the native code takes care of it, somehow. If it doesn't then you must use C++/CLI to interop with it. With the additional requirement that the native code needs to be rebuilt with the same compiler so that it uses the same shared CRT. Code that's difficult to use correctly from native code is also hard to pinvoke. That's a design flaw, always allow the caller to pass a buffer to be filled in so there's never a question who owns the memory.
Looking at:
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
I can see that your callback is called, but the runtime tries to free some memory. I think it assumes your pointer would be to com memory. Try converting the string yourself, it is easy!
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
public static extern IntPtr GetResultsExt();
[...]
string result = Marshal.PtrToStringAnsi(GetResultsExt())
No 100% guarantee, but worth a try.
I have found that it is usually easier to write a wrapper in C++/CLI around the C++ native code. A C++/CLI class can directly call and use native C++, but is accessible from C# (and any .Net language). In my experience, using DLLImport as you do leads to hard to debug and find errors.