Why my app crashes when I free a char* allocated by a DLL generated with CFFI?
Asked Answered
Y

1

0

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)

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;
}

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

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.

Yalta answered 20/3, 2019 at 16:19 Comment(0)
B
3

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:

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.

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.

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.

Baptism answered 20/3, 2019 at 16:29 Comment(3)
I follow what you said. It works well but I have a weird error now. I updated my question.Yalta
@Pierre: I think this is a very different question than your first since it is now a Python problem, not a C++/DLL problem. If your initial problem is fixed, you should close this question. Then start by Googling 'Python "MemoryError: Stack overflow"' (with the double quotes), and you should find some other people with the same problem. If that does not lead you to a solution, post a new question on SO.Baptism
I didn't found an answer elsewhere. I asked a new question here: #55323216Yalta

© 2022 - 2024 — McMap. All rights reserved.