【问题标题】:Why my app crashes when I free a char* allocated by a DLL generated with CFFI?为什么当我释放由 CFFI 生成的 DLL 分配的 char* 时,我的应用程序会崩溃?
【发布时间】:2019-08-11 10:18:18
【问题描述】:

我正在使用 CFFI 生成 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:

#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 指令期间崩溃:

> 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

我遵循this answer 中给出的指示。我应该怎么做才能释放内存并避免我的应用程序崩溃?事实上,如果我删除 free 指令,我的应用程序运行良好,但它不是一个干净的解决方案。

【问题讨论】:

    标签: python c++ memory python-cffi


    【解决方案1】:

    在一个地方分配然后跨 DLL 边界释放是一种危险的做法。除非您知道自己做得对(相同的 CRT 版本等),否则请避免使用它。 Thus spake Microsoft:

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

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

    对此的一种解决方案是从您的 DLL 中公开一个 free 函数,该函数正在翻转分配的对象,以便客户端可以在其上调用您的 free 函数,或者在 C++ 中您可以使用带有自定义的智能指针删除器来做正确的事。

    【讨论】:

    • 我听你说的。它运作良好,但我现在有一个奇怪的错误。我更新了我的问题。
    • @Pierre:我认为这是一个与您的第一个问题非常不同的问题,因为它现在是 Python 问题,而不是 C++/DLL 问题。如果您最初的问题得到解决,您应该关闭此问题。然后通过谷歌搜索'Python "MemoryError: Stack overflow"'(使用双引号)开始,你应该会发现其他一些人也有同样的问题。如果这不能让您找到解决方案,请在 SO 上发布一个新问题。
    • 我没有在其他地方找到答案。我在这里问了一个新问题:stackoverflow.com/questions/55322716/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 2019-04-18
    • 1970-01-01
    相关资源
    最近更新 更多