草庐IT

c# - 来自 C# : why do I have to override new/delete? 的 mingw DLL

coder 2024-06-12 原文

我正在尝试从 Windows 10 上的 C# 调用最小的 C 函数。我使用 mingw/g++ 将 C 代码编译成 .dll

事实证明,我必须定义 opterator new[] 或使用 Visual Studio 编译 .dll。否则我的 C# 程序会因以下错误而崩溃:

程序“[14740] Test.exe”已退出,代码为 -1073741819 (0xc0000005)“访问冲突”。

我真的很想了解这里究竟发生了什么,以及我如何在不覆盖所有新/删除运算符但仍然使用 mingw 的情况下解决这个问题。

这是重现错误的最小示例,包括解决方法(如果定义了 AddNewOperatoroperator new[] 将被定义并且生成的 .dll 将正常工作):

Test.cs(使用 Visual Studio 2017 编译/运行):

using System;
using System.Runtime.InteropServices;
class Program
{
    [DllImport("libTest", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)]
    public static extern int TestFunction();
    static void Main(string[] args)
    {
        Console.WriteLine("!!" + TestFunction());
    }
}

用mingw编译的Test.cpp(见下文):

#include <new>
#include <cstdlib>

#ifdef AddNewOperator // This will fix the issue
void* operator new[](std::size_t sz){
    return std::malloc(sz);
}
#end

extern "C" {
int __stdcall __declspec(dllexport) TestFunction() {
        int* test = new int[3]; // removing this line will make everything work when building
        return test[2];
}

这是构建脚本:

# Remove the following # and the compiled dll will work just fine
g++ -g -s -Wall -c -fmessage-length=0 Test.cpp  #-DAddNewOperator
g++ -g -shared -o libTest.dll *.o -Wl,--subsystem,windows

编辑:为 x86 而不是 64 位编译所有内容也解决了这个问题(这对我来说也是没有选择的)

最佳答案

长话短说

不得在编译器之间混合分配/释放!

您面临的问题非常棘手,实际上您的程序每次都应该崩溃,无论是否有 void* operator new[](size_t){...} 定义。

如果您调试您的程序,它实际上应该在删除您的 test 变量时崩溃。这个变量是用mingw的new操作符创建的,但是用MSVC的delete操作符删除的,它们不是interoperable .所以你必须使用mingw的delete功能。

对于一个简单的测试,你可以这样做:

C++代码:

int* test = nullptr;
int __stdcall __declspec(dllexport) TestFunction() {
    test = new int[3]; // note test is global
    return test[2];
}
void __stdcall _declspec(dllexport) CleanUp() {
    delete[] test;
}

c#代码:

public static extern int TestFunction();
public static extern int CleanUp();
static void Main(string[] args)
{
    Console.WriteLine("!!" + TestFunction());
    CleanUp();
}

如果您重新定义新运算符,为什么您的程序不会崩溃?!

我其实不确定,但我认为,mingw 的 malloc 实现使用 legacy C runtime它使用 HeapAlloc 进行分配,使用 HeapFree 删除您的 test 变量。简而言之,你只是幸运/不幸当你自定义你的 operator new 并在里面使用 malloc 时它没有崩溃......

但是,如果您使用 Visual Studio 编译它,则两者(dll 和 exe)都使用相同的运行时,因此分配/解除分配是在相同的内存空间组织器中完成的。 但是它仍然是 UB,你会遇到问题!例如:如果您使用 msvc10 创建您的库并想将此库与 msvc14 一起使用,同样可以在这里发生!我记得一些代码问题来自内存管理错误的错误;我们使用了用 msvc11 创建的库,但我们的代码是用 msvc12 编译的...

关于c# - 来自 C# : why do I have to override new/delete? 的 mingw DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49983571/

有关c# - 来自 C# : why do I have to override new/delete? 的 mingw DLL的更多相关文章

  1. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  2. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  3. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  4. ruby - 可以正常中断的来自 Rake 的长时间运行的 shell 命令? - 2

    在几个项目中,我希望有一个类似rakeserver的rake任务,它将通过任何需要的方式开始为该应用程序提供服务。这是一个示例:task:serverdo%x{bundleexecrackup-p1234}end这行得通,但是当我准备停止它时,按Ctrl+c并没有正常关闭;它中断了Rake任务本身,它说rakeaborted!并给出堆栈跟踪。在某些情况下,我必须执行Ctrl+c两次。我可能可以用Signal.trap写一些东西来更优雅地中断它。有没有更简单的方法? 最佳答案 trap('SIGINT'){puts"Yourmessa

  5. ruby - ruby 中的同一个程序如何接受来自用户的输入以及命令行参数 - 2

    我的ruby​​脚本从命令行参数获取某些输入。它检查是否缺少任何命令行参数,然后提示用户输入。但是我无法使用gets从用户那里获得输入。示例代码:test.rbname=""ARGV.eachdo|a|ifa.include?('-n')name=aputs"Argument:#{a}"endendifname==""puts"entername:"name=getsputsnameend运行脚本:rubytest.rbraghav-k错误结果:test.rb:6:in`gets':Nosuchfileordirectory-raghav-k(Errno::ENOENT)fromtes

  6. ruby-on-rails - Rails 3,在RAILS_ROOT上方显示来自本地文件系统的jpg图片 - 2

    我正在尝试找出一种方法来显示来自不在RAILS_ROOT下(在RedHat或Ubuntu环境中)的已安装文件系统的图像。我不想使用符号链接(symboliclink),因为这个应用程序实际上是通过Tomcat部署的,而当我关闭Tomcat时,Tomcat会尝试跟随符号链接(symboliclink)并删除挂载中的所有图像。由于这些文件的数量和大小,将图像放在public/images下也不是一种选择。我查看了send_file,但它只会显示一张图片。我需要在一个格式良好的页面中显示6个请求的图像。由于膨胀,我宁愿不使用Base64编码,但我不知道如何将图像数据与呈现的页面一起传递下去。

  7. c# - C# 中的 Flatten Ruby 方法 - 2

    我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

  8. ruby - 可以像在 C# 中使用#region 一样在 Ruby 中使用 begin/end 吗? - 2

    我最近从C#转向了Ruby,我发现自己无法制作可折叠的标记代码区域。我只是想到做这种事情应该没问题:classExamplebegin#agroupofmethodsdefmethod1..enddefmethod2..endenddefmethod3..endend...但是这样做真的可以吗?method1和method2最终与method3是同一种东西吗?还是有一些我还没有见过的用于执行此操作的Ruby惯用语? 最佳答案 正如其他人所说,这不会改变方法定义。但是,如果要标记方法组,为什么不使用Ruby语义来标记它们呢?您可以使用

  9. c# - Ruby 等效于 C# Linq 聚合方法 - 2

    什么是Linq聚合方法的ruby​​等价物。它的工作原理是这样的varfactorial=new[]{1,2,3,4,5}.Aggregate((acc,i)=>acc*i);每次将数组序列中的值传递给lambda时,变量acc都会累积。 最佳答案 这在数学以及几乎所有编程语言中通常称为折叠。它是更普遍的变形概念的一个实例。Ruby从Smalltalk中继承了这个特性的名称,它被称为inject:into:(像aCollectioninject:aStartValueinto:aBlock一样使用。)所以,在Ruby中,它称为inj

  10. ruby-on-rails - Ruby Integer()、Array() 等——它们是什么?他们来自哪里? - 2

    我有时遇到过Array(value)、String(value)和Integer(value)形式的转换。在我看来,这些只是调用相应的value.to_a、value.to_s或value.to_i方法的语法糖。所以我想知道:这些是在哪里/如何定义的?我在对象、模块、类等中找不到它们是否有任何常见场景更适合使用这些而不是相应/底层的to_X方法?这些可以用于泛型强制转换吗?也就是说,我可以按照[Integer,String,Array].each{|klass|klass.do_generic_coercion(foo)}?(...不,我真的不想那样做;我知道我想要的类型,但我希望避免

随机推荐