当我释放由CFFI生成的DLL分配的char *时,为什么我的应用程序崩溃? [英] Why my app crashes when I free a char* allocated by a DLL generated with CFFI?

查看:68
本文介绍了当我释放由CFFI生成的DLL分配的char *时,为什么我的应用程序崩溃?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用CFFI生成DLL:

I'm using CFFI to generate a DLL:

import cffi

ffibuilder = cffi.FFI()

ffibuilder.embedding_api('''
    char* get_string();
''')

ffibuilder.set_source('my_plugin', '')

ffibuilder.embedding_init_code('''
    from my_plugin import ffi, lib

    @ffi.def_extern()
    def get_string():
        val = "string"
        return lib.strdup(val.encode())
''')

ffibuilder.cdef('''
    char *strdup(const char *);
''')

ffibuilder.compile(target='my-plugin.*', verbose=True)

我通过运行此先前的脚本来生成DLL.现在,我创建此C ++代码示例以使用我的DLL:

I generate the DLL by running this previous script. Now, I create this sample of C++ code to use my DLL:

#include <iostream>
#include <windows.h>

typedef char* (__stdcall *get_string_t)();

int main()
{
    HINSTANCE hGetProcIDDLL = LoadLibrary("my-plugin.dll");

    if (!hGetProcIDDLL) {
        std::cout << "could not load the dynamic library" << std::endl;
        return -1;
    }

    get_string_t get_string = (get_string_t)GetProcAddress(hGetProcIDDLL, "get_string");
    if (!get_string) {
        std::cout << "could not locate the function" << std::endl;
        return -1;
    }

    char* val = get_string();

    std::cout << "Value = " << val << std::endl;

    free(val); // Crash !

    std::cout << "End" << std::endl;

    return 0;
}

我使用Visual Studio 2010的编译器进行编译,运行我的应用程序时,它在free指令期间崩溃:

I compile using the compiler of Visual Studio 2010 and, when I run my app, it crashes during the free instruction:

> cl get_string.cpp
Compilateur d'optimisation Microsoft (R) 32 bits C/C++ version 16.00.40219.01 pour 80x86
Copyright (C) Microsoft Corporation. Tous droits réservés.

get_string.cpp
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\xlocale(323) : warning C4530: Gestionnaire d'exceptions C++ utilisé, mais les sémantiques de déroulement n'ont pas été activées. Spécifiez /EHsc
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:get_string.exe
get_string.obj

> get_string.exe
Value = string

我遵循此答案中给出的指示.我应该怎么做才能释放内存并避免我的应用程序崩溃?确实,如果删除free指令,我的应用程序可以很好地运行,但这不是一个干净的解决方案.

I follow the indication given in this answer. What should I do to free the memory and avoid my app to crash? Indeed, if I remove the free instruction, my app works well but it's not a clean solution.

推荐答案

在一个位置进行分配然后跨DLL边界释放是一种危险的做法.除非您知道自己做得对(避免使用CRT版本等),否则请避免使用它. 因此请Microsoft :

It is a dangerous practice to allocate in one place and then free across a DLL boundary. Avoid it unless you know that you're doing it right (same CRT version etc.). Thus spake Microsoft:

当您将C运行时(CRT)对象(例如文件句柄,语言环境和环境变量)传入或传出DLL(跨越DLL边界的函数调用)时,如果DLL以及调用DLL的文件使用CRT库的不同副本.

When you pass C Run-time (CRT) objects such as file handles, locales, and environment variables into or out of a DLL (function calls across the DLL boundary), unexpected behavior can occur if the DLL, as well as the files calling into the DLL, use different copies of the CRT libraries.

当您分配内存(使用new或malloc显式或使用strdup,strstreambuf :: str等隐式)然后在DLL边界上传递要释放的指针时,可能会发生相关的问题.如果DLL及其用户使用CRT库的不同副本,则可能导致内存访问冲突或堆损坏.

A related problem can occur when you allocate memory (either explicitly with new or malloc, or implicitly with strdup, strstreambuf::str, and so on) and then pass a pointer across a DLL boundary to be freed. This can cause a memory access violation or heap corruption if the DLL and its users use different copies of the CRT libraries.

对此的一种解决方案是从DLL中公开一个free函数,该DLL将翻转已分配的对象,以便客户端可以在其上调用free函数,或者在C ++中,您可以将智能指针与自定义一起使用删除程序即可正确执行此操作.

One solution to this is to expose a free function from your DLL that is turning over an allocated object so the client can call your free function on it, or in C++ you might use a smart pointer with a custom deleter to do it right.

这篇关于当我释放由CFFI生成的DLL分配的char *时,为什么我的应用程序崩溃?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆