видишь ли в чём проблема - в консольном приложении...

Creado el: 2 de septiembre de 2025

Respondido usando GPT-5 Thinking por Chat01

Pregunta

видишь ли в чём проблема - в консольном приложении это работает (функция xor_rand и функция шекеля static inline float ShekelFunc(float x, uint32_t seed)
{
uint32_t i = 0u;
float res = 0.0f;
uint32_t current_state = seed; // Локальная копия для изменений

text
while (i < 10u) { const float x_part = fmaf(-xor_rand(current_state), 10.0f, x); res -= 1.0f / fmaf(fmaf(xor_rand(current_state), 20.0f, 5.0f), x_part * x_part, fmaf(xor_rand(current_state), 0.2f, 1.0f)); ++i; } return res;

} ... static float xor_rand(uint32_t& state) // Принимает state по ссылке для изменения
{
state ^= state << 13u;
state ^= state >> 17u;
state ^= state << 5u;
return state * 0x1.0p-32f;
}) без исключений но когда я использую эти функции в экспортируемой функции в моей DLL которая вызывается в управляемом коде winforms c++/clr по нажатию кнопки то я получаю SEH исключения static std::vector<float> Base_LNA_1_2_Mer_AGP(const uint32_t N,
const uint32_t global_iterations, const float a, const float b, const float c, const float d, const float r,
const bool mode, const float epsilon, const uint32_t seed)
{
std::ofstream logfile("function_debug.log", std::ios_base::app);
logfile << "=== Base_LNA_1_2_Mer_AGP called ===" << std::endl;

text
if (N == 1u) { logfile << "N == 1u branch" << std::endl; try { const float initial_length = b - a; float dmax = initial_length; std::vector<float> Extr; Extr.reserve((global_iterations << 1u) + 2u); std::vector<Interval> R; R.reserve(global_iterations + 1u); logfile << "Before ShekelFunc(a, seed)" << std::endl; float best_f = ShekelFunc(b, seed); logfile << "ShekelFunc(a, seed) = " << best_f << std::endl; logfile << "Before ShekelFunc(b, seed)" << std::endl; const float end_val = ShekelFunc(b, seed); logfile << "ShekelFunc(b, seed) = " << end_val << std::endl; uint32_t schetchick = 0u; std::pair<float, float> x_Rmax = std::make_pair(a, b); std::pair<float, float> y_Rmax = std::make_pair(best_f, end_val); logfile << "Before Interval creation" << std::endl; Interval interval(std::pair(a, best_f), std::pair(b, end_val), N); logfile << "Interval created successfully" << std::endl; logfile << "Before push to priority_queue" << std::endl; R.push_back(interval); logfile << "Push to priority_queue completed" << std::endl; //const float initial_length = b - a; //float dmax = initial_length; //std::vector<float> Extr; //Extr.reserve((global_iterations << 1u) + 2u); //std::vector<std::unique_ptr<Interval>> R; //R.reserve(global_iterations + 1u); //Priority_queue R; //float best_f = ShekelFunc(a, seed); //const float end_val = ShekelFunc(b, seed); //uint32_t schetchick = 0u; //std::pair<float, float> x_Rmax = std::make_pair(a, b); //std::pair<float, float> y_Rmax = std::make_pair(best_f, end_val); //R.emplace_back(std::make_unique<Interval>(std::make_pair(a, best_f), std::make_pair(b, end_val), 1u)); //float Mmax = R.front().M; //float m = r * Mmax; std::vector<float> myVector = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f }; for (float& num : myVector) { num *= 1.1f; } myVector.push_back(6.6f); logfile << "Returning result" << std::endl; return myVector; } catch (const std::exception& e) { logfile << "std::exception in Base_LNA_1_2_Mer_AGP: " << e.what() << std::endl; // Дополнительная информация об исключении std::stringstream ss; ss << "Exception details: N=" << N << ", a=" << a << ", b=" << b << ", seed=" << seed << ", what(): " << e.what(); logfile << ss.str() << std::endl; throw; } catch (const std::string& e) { logfile << "String exception in Base_LNA_1_2_Mer_AGP: " << e << std::endl; throw; } catch (int e) { logfile << "Integer exception in Base_LNA_1_2_Mer_AGP: " << e << std::endl; throw; } catch (...) { logfile << "Unknown exception in Base_LNA_1_2_Mer_AGP" << std::endl; // Попытка получить больше информации о неизвестном исключении try { std::rethrow_exception(std::current_exception()); } catch (const std::exception& e) { logfile << "Unwrapped exception: " << e.what() << std::endl; } catch (...) { logfile << "Completely unknown exception type" << std::endl; } throw; } } logfile << "N != 1u, returning empty vector" << std::endl; return std::vector<float>();

}

// C-обёртка: без std::vector в сигнатуре!
extern "C" __declspec(dllexport) int __cdecl Base_LNA_1_2_Mer_AGP_C(
uint32_t N, uint32_t global_iterations, float a, float b, float c, float d, float r,
bool mode, float epsilon, uint32_t seed,
float** out_data, uint32_t* out_len)
{
std::ofstream logfile("dll_debug.log", std::ios_base::app);
logfile << "=== Function called ===" << std::endl;
logfile << "Parameters: N=" << N << ", a=" << a << ", b=" << b << ", c=" << c
<< ", d=" << d << ", r=" << r << ", mode=" << mode
<< ", epsilon=" << epsilon << ", seed=" << seed << std::endl;

text
*out_data = nullptr; *out_len = 0; try { logfile << "Calling Base_LNA_1_2_Mer_AGP..." << std::endl; auto v = Base_LNA_1_2_Mer_AGP(N, global_iterations, a, b, c, d, r, mode, epsilon, seed); logfile << "Base_LNA_1_2_Mer_AGP completed, size: " << v.size() << std::endl; *out_len = static_cast<uint32_t>(v.size()); if (*out_len > 0) { *out_data = static_cast<float*>(CoTaskMemAlloc(sizeof(float) * (*out_len))); if (!*out_data) { logfile << "Memory allocation failed" << std::endl; return 2; } memcpy(*out_data, v.data(), sizeof(float) * (*out_len)); logfile << "Data copied successfully" << std::endl; } logfile << "Returning success" << std::endl; return 0; } catch (const std::exception& e) { logfile << "std::exception: " << e.what() << std::endl; // Получаем дополнительную информацию об исключении std::string ex_type = typeid(e).name(); logfile << "Exception type: " << ex_type << std::endl; return 1; } catch (const std::string& e) { logfile << "String exception: " << e << std::endl; return 1; } catch (int e) { logfile << "Integer exception: " << e << std::endl; return 1; } catch (...) { logfile << "Unknown exception occurred" << std::endl; // Попытка получить больше информации try { std::rethrow_exception(std::current_exception()); } catch (const std::exception& e) { logfile << "Unwrapped exception: " << e.what() << std::endl; } catch (...) { logfile << "Completely unknown exception type" << std::endl; } return 1; }

}

extern "C" __declspec(dllexport) void __cdecl Base_LNA_1_2_Mer_AGP_Free(float* p) {
CoTaskMemFree(p);
} это код в DLL, System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
chart2->Series[0]->Points->Clear();
chart2->Series[1]->Points->Clear();
chart2->Series[2]->Points->Clear();
chart2->Series[3]->Points->Clear();

text
static LARGE_INTEGER start, end; QueryPerformanceCounter(&start); uint32_t seed = GetTickCount(); typedef int(__cdecl* agp_c)( uint32_t, uint32_t, float, float, float, float, float, bool, float, uint32_t, float**, uint32_t*, char*, size_t); typedef void(__cdecl* agp_free)(float*); HINSTANCE h = LoadLibrary(L"TEST_FUNC.dll"); if (!h) { DWORD errorCode = GetLastError(); // Выводим код ошибки в текстовое поле textBox2->Text = "Ошибка загрузки DLL: " + errorCode.ToString(); return; } auto f = (agp_c)GetProcAddress(h, "Base_LNA_1_2_Mer_AGP_C"); auto ffree = (agp_free)GetProcAddress(h, "Base_LNA_1_2_Mer_AGP_Free"); if (!f || !ffree) { textBox2->Text = "Ошибка: не удалось получить функции из DLL"; FreeLibrary(h); return; } float* buf = nullptr; uint32_t len = 0; // Добавляем буфер для сообщения об ошибке const int ERROR_MSG_SIZE = 256; char error_msg[ERROR_MSG_SIZE] = { 0 }; try { int rc = f(1, 10000, 0.0f, 1.0f, -2.2f, 1.8f, 2.5f, false, 0.0001f, seed, &buf, &len, error_msg, ERROR_MSG_SIZE); if (rc == 0) { std::vector<float> Extr_2D(buf, buf + len); ffree(buf); textBox2->Text = "Результат: " + Convert::ToString(Extr_2D.back()); } else { // Попробуйте прочитать файл лога и показать его содержимое if (File::Exists("dll_debug.log")) { String^ logContent = File::ReadAllText("dll_debug.log"); textBox2->Text = "Код ошибки: " + rc.ToString() + "\n" + logContent; } else { textBox2->Text = "Код ошибки: " + rc.ToString() + " (лог не найден)"; } } } catch (const std::exception& ex) { textBox2->Text = "Исключение: " + gcnew String(ex.what()); } catch (...) { textBox2->Text = "Неизвестное исключение"; } FreeLibrary(h); - это код управляемый

Pensamiento

Diagnosing SEH exception

It looks like the user's issue involves a mismatch between the exported C function and its declaration in the calling code. The caller is passing extra parameters for error messages that the exported function signature doesn't expect. This could be causing misalignment, leading to SEH exceptions. A possible solution would be to adjust the function's signature in the caller or remove unused parameters.

Investigating stack mismatch

It seems like the issue is a stack mismatch caused by extra arguments being passed. The caller is using __cdecl, meaning it should clean the stack after the call, and the callee will ignore the extra params. This shouldn't cause a crash unless memory access or argument types mismatches occur. The load method for the DLL looks good, though.

Analyzing SEH exception

It looks like memory is allocated with CoTaskMemAlloc in the DLL, and ffree is used to free it. But the issue may arise from using std::vector<float> in managed C++/CLI code built with /clr on memory allocated with a non-C++-compatible allocator. This could lead to memory bounds or access issues causing the SEH exception.

Looking for SEH cause

The user’s code should technically be fine with the fmaf expression, as its operations are valid. However, there might be a slight concern with the std::pair declaration. They're using C++17 and CTAD, so it's okay for the pair, but I wonder if there's something buried deeper in memory handling or stack mismanagement causing the SEH exception. Still, no immediate issues come to mind.

Investigating SEH exception cause

It seems like there are a few factors contributing to SEH exceptions. The most likely suspects include potential mismatches in the function signature or calling convention, especially with the ShekelFunc. Also, the use of xor_rand while mutating the state could lead to issues if current_state becomes zero. Another concern is if the C++ exception is not properly caught in the managed code across the boundary, potentially causing the SEH exception.

Addressing SEH exception cause

The SEH exception likely stems from a mismatch in the function's signature where extra parameters are passed. It’s important to correct this and ensure a consistent calling convention. Additional checks for architecture compatibility and careful handling between native and managed code will further prevent crashes. The logs also indicate that access violations may not be properly captured due to default exception handling settings.

Proposing SEH exception fixes

To address the SEH exceptions, I suggest updating the DLL signature to accept an error buffer or removing excess parameters for a simpler approach. Additionally, you could add __try/__except for logging or compile with /EHa to catch SEH exceptions. Double-check the function signature, calling convention, and architecture mismatch. Adding logging and a quick checklist to narrow down the SEH issue is also recommended.

Thought for 3m 10s

Respuesta

Почти наверняка причина в несовпадении сигнатур при вызове экспортируемой функции.

В DLL у вас экспорт объявлен так:

cpp
extern "C" __declspec(dllexport) int __cdecl Base_LNA_1_2_Mer_AGP_C( uint32_t N, uint32_t global_iterations, float a, float b, float c, float d, float r, bool mode, float epsilon, uint32_t seed, float** out_data, uint32_t* out_len);

А в C++/CLI вы объявляете указатель на функцию с двумя дополнительными параметрами (char*, size_t) и именно так её вызываете:

cpp
typedef int(__cdecl* agp_c)( uint32_t, uint32_t, float, float, float, float, float, bool, float, uint32_t, float**, uint32_t*, char*, size_t); // <- ЛИШНИЕ аргументы ... int rc = f(..., &buf, &len, error_msg, ERROR_MSG_SIZE); // <- передаёте лишние аргументы

На x86 такое несоответствие очень легко приводит к порче стека (если вдруг где-то окажется __stdcall, а не __cdecl — будет 100% краш), а на x64 тоже может кончиться SEH-исключением из-за неверной раскладки параметров/регистров. Именно поэтому в кнопке вы ловите SEHException.

Как починить быстро

  1. Приведите сигнатуры к одному виду. Самый простой путь — убрать лишние параметры в управляемом коде:
cpp
typedef int(__cdecl* agp_c)( uint32_t, uint32_t, float, float, float, float, float, bool, float, uint32_t, float**, uint32_t*); int rc = f(1, 10000, 0.0f, 1.0f, -2.2f, 1.8f, 2.5f, false, 0.0001f, seed, &buf, &len);
  1. Убедитесь, что вызывающая конвенция совпадает:
  • и в DLL, и в объявлении в приложении должно быть __cdecl.
  • Если цель — x86, проверьте экспорт имен: dumpbin /exports TEST_FUNC.dll. Должно быть Base_LNA_1_2_Mer_AGP_C (без декорации типа _@NN, которая указывает на __stdcall).
  1. Для межмодульного ABI лучше избегать bool (размер/ABI может расходиться между компиляторами/настройками). Надёжнее так:

    • В экспортируемой С-функции замените bool mode на uint32_t mode (0/1) и аналогично в объявлении в приложении. (Это рекомендация на будущее; не обязательно для запуска, но повышает устойчивость ABI.)
  2. Если хотите действительно передавать буфер для текста ошибки из DLL — добавьте его и в экспорт и реализуйте заполнение в DLL, а не только в вызывающей стороне. Сейчас вызывающая сторона передаёт лишние аргументы, которые DLL не ожидает.

Пример корректного варианта экспорта с ошибочным сообщением (опционально):

cpp
extern "C" __declspec(dllexport) int __cdecl Base_LNA_1_2_Mer_AGP_C( uint32_t N, uint32_t global_iterations, float a, float b, float c, float d, float r, uint32_t mode, float epsilon, uint32_t seed, float** out_data, uint32_t* out_len, char* err, size_t err_cap) { __try { // ... ваш код ... return 0; } __except(EXCEPTION_EXECUTE_HANDLER) { // поймает SEH (AV и т.д.) if (err && err_cap) _snprintf_s(err, err_cap, _TRUNCATE, "SEH 0x%08X", GetExceptionCode()); return 1; } }

И соответствующий typedef/вызов в кнопке с этими параметрами.

Ещё пара мелочей (не про падение, но полезно)

  • В логах у вас «Before ShekelFunc(a, seed)», а вызывается ShekelFunc(b, seed). Просто чтобы не путаться при диагностике — приведите в соответствие.
  • Для устойчивого логирования SEH в текущей реализации (без __try) можно собрать DLL с /EHa, тогда catch(...) поймает и SEH. Но лучше локально обернуть внешнюю С-обёртку в __try/__except, как в примере выше.
  • Вы правильно используете CoTaskMemAlloc/Free — это безопасно для межмодульной передачи.

С высокой вероятностью устранение несовпадения сигнатур (п.1–2) уберёт ваши SEH-исключения.

Compartir este Q&A