ctypes python3.11 access violation reading 0x00000206196E7050, 0x00000206194E2168, 0x000002067FF23088
столкнулся с проблемой, что моя дллка(собранная release x64) не хочет работать с моим кодом на питоне. Вроде бы все правильно объявил, но в определенном моменте программа падает.
Падает и ноль ошибок "access violation reading 0x..."
либо
Прога падает с 3+ ошибками "access violation reading 0x...".
либо
Иногда не падает и завершает работу до конца, но с ошибками "access violation reading 0x..." и неправильно выполнив поставленную задачу.
py
import ctypes
lib = ctypes.PyDLL(r"тут длл")
# Объявляем сигнатуру calc_weight_sim_c
lib.calc_weight_sim_c.argtypes = [
ctypes.POINTER(ctypes.c_char_p),
ctypes.c_int,
ctypes.POINTER(ctypes.c_char_p),
ctypes.c_int
]
lib.calc_weight_sim_c.restype = ctypes.c_double
def readFiles(filePath):
sql_code = None
for encoding in ['utf-8', 'cp1251', 'latin1']:
try:
with open(filePath, 'r', encoding=encoding) as sql_file:
sql_code = sql_file.read()
break
except UnicodeDecodeError:
continue
if not sql_code:
return []
return [line for line in sql_code.split('\n')]
def calcWeightSim(block1, block2):
block1_bytes = [s.encode('utf-8', errors='replace') for s in block1]
block2_bytes = [s.encode('utf-8', errors='replace') for s in block2]
# Создаём массив (c_char_p * N), сразу инициализируя его контентом
arr1 = (ctypes.c_char_p * len(block1_bytes))(*block1_bytes)
arr2 = (ctypes.c_char_p * len(block2_bytes))(*block2_bytes)
try:
score = lib.calc_weight_sim_c(arr1, len(block1), arr2, len(block2))
return score * 100.0
except Exception as e:
print("Ошибка при вызове DLL:", e)
return 0.0
def test_simple_calc():
block1 = readFiles("E:\\codding\\py\\SSC\\sql\\test\\file1.txt")
block2 = readFiles("E:\\codding\\py\\SSC\\sql\\test\\file2.txt")
sim = calcWeightSim(block1, block2)
print("TEST SIM =", sim)
if __name__ == '__main__':
test_simple_calc()
cpp
#include <Eigen/Dense>
#include <vector>
#include <string>
#include <sstream>
#include <unordered_map>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "Boshka.h"
#include <cstring>
// -----------------------------------------------------------------------------
// Вспомогательные функции
// -----------------------------------------------------------------------------
// Разбиваем строку на токены (слова), приводя её к нижнему регистру
static std::vector<std::string> tokenize(const std::string& text)
{
std::vector<std::string> tokens;
if (text.empty())
return tokens;
// Просто разбиваем по пробелам вручную (без tolower)
std::stringstream ss(text);
std::string token;
while (ss >> token) {
tokens.push_back(token);
}
return tokens;
}
// Косинусная близость двух векторов Eigen
static double cosine_similarity(const Eigen::VectorXd& v1, const Eigen::VectorXd& v2) {
if (v1.norm() == 0 || v2.norm() == 0) {
return 0.0;
}
if (v1.size() != v2.size()) {
std::cerr << "[cosine_similarity] size mismatch: "
<< v1.size() << " vs " << v2.size() << "\n";
return 0.0;
}
double dot = v1.dot(v2);
double norm_prod = v1.norm() * v2.norm();
if (norm_prod == 0.0) {
std::cerr << "[cosine_similarity] norm_prod=0 => return 0\n";
return 0.0;
}
return dot / norm_prod;
}
// Считаем TF-IDF для набора строк
static void computeTfIdf(
const std::vector<std::string>& lines,
std::unordered_map<std::string, size_t>& vocabulary,
Eigen::MatrixXd& tfidfMatrix
) {
if (lines.empty()) {
std::cerr << "[computeTfIdf] #3: The line list is empty => TF-IDF matrix empty.\n";
return;
}
// 1) Собираем словарь
for (auto& line : lines) {
auto tokens = tokenize(line);
for (auto& token : tokens) {
if (!vocabulary.count(token)) {
vocabulary[token] = vocabulary.size();
}
}
}
const size_t vocabSize = vocabulary.size();
const size_t nLines = lines.size();
std::cerr << "[computeTfIdf] nLines=" << nLines
<< " vocabSize=" << vocabSize << "\n";
if (vocabSize == 0) {
std::cerr << "[computeTfIdf] #4: The vocabulary is empty.\n";
return;
}
Eigen::MatrixXd tfMatrix = Eigen::MatrixXd::Zero(nLines, vocabSize);
std::vector<size_t> docCountForTerm(vocabSize, 0);
// 2) Подсчитываем TF
for (size_t i = 0; i < nLines; i++) {
auto tokens = tokenize(lines[i]);
for (auto& token : tokens) {
auto it = vocabulary.find(token);
if (it != vocabulary.end()) {
size_t termID = it->second;
tfMatrix(i, termID) += 1.0;
}
}
}
// 3) Считаем, в скольких документах встречается каждый термин
for (size_t termID = 0; termID < vocabSize; termID++) {
for (size_t i = 0; i < nLines; i++) {
if (tfMatrix(i, termID) > 0.0) {
docCountForTerm[termID]++;
}
}
}
// 4) IDF
Eigen::VectorXd idfVec(vocabSize);
for (size_t termID = 0; termID < vocabSize; termID++) {
double val = std::log((1.0 + double(nLines)) / (1.0 + double(docCountForTerm[termID]))) + 1.0;
idfVec(termID) = val;
}
// 5) Формируем итоговую матрицу TF-IDF
tfidfMatrix = Eigen::MatrixXd::Zero(nLines, vocabSize);
for (size_t i = 0; i < nLines; i++) {
for (size_t termID = 0; termID < vocabSize; termID++) {
tfidfMatrix(i, termID) = tfMatrix(i, termID) * idfVec(termID);
}
}
std::cerr << "[computeTfIdf] => built matrix "
<< nLines << " x " << vocabSize << "\n";
}
// Реализует "взвешенную косинусную схожесть"
static double calc_weight_sim_impl(
const std::vector<std::string>& block1,
const std::vector<std::string>& block2
) {
if (block1.empty() && block2.empty()) {
std::cerr << "[calc_weight_sim_impl] Both blocks empty => 0.\n";
return 0.0;
}
if (block1.empty() || block2.empty()) {
std::cerr << "[calc_weight_sim_impl] One block empty => 0.\n";
return 0.0;
}
// Собираем все строки
std::vector<std::string> allLines;
allLines.reserve(block1.size() + block2.size());
for (auto& s : block1) {
allLines.push_back(s);
}
for (auto& s : block2) {
allLines.push_back(s);
}
// TF-IDF
std::unordered_map<std::string, size_t> vocabulary;
Eigen::MatrixXd tfidfMatrix;
computeTfIdf(allLines, vocabulary, tfidfMatrix);
if (tfidfMatrix.size() == 0) {
std::cerr << "[calc_weight_sim_impl] TF-IDF is empty => 0.\n";
return 0.0;
}
// Считаем суммарную длину символов
size_t lenBlock1 = 0;
for (auto& s : block1) {
lenBlock1 += s.size();
}
size_t lenBlock2 = 0;
for (auto& s : block2) {
lenBlock2 += s.size();
}
double denom = double(lenBlock1 + lenBlock2);
if (denom == 0.0) {
std::cerr << "[calc_weight_sim_impl] denom=0 => 0.\n";
return 0.0;
}
// Вычисляем взвешенную косинусную похожесть
double weightedSim = 0.0;
size_t minSize = std::min(block1.size(), block2.size());
for (size_t i = 0; i < minSize; i++) {
double weight = double(block1[i].size() + block2[i].size()) / denom;
size_t idx2 = block1.size() + i;
Eigen::VectorXd vec1 = tfidfMatrix.row(i);
Eigen::VectorXd vec2 = tfidfMatrix.row(idx2);
double simRatio = cosine_similarity(vec1, vec2);
// Отладочный вывод по желанию
/*
std::cerr << "[calc_weight_sim_impl] i=" << i
<< " line1='" << block1[i] << "' (" << block1[i].size() << " chars)"
<< " line2='" << block2[i] << "' (" << block2[i].size() << " chars)"
<< " simRatio=" << simRatio
<< " weight=" << weight << "\n";
*/
weightedSim += simRatio * weight;
}
std::cerr << "[calc_weight_sim_impl] => weightedSim=" << weightedSim << "\n";
return weightedSim;
}
// -----------------------------------------------------------------------------
// safeCopy: Дополняем отладочным выводом realLen
// -----------------------------------------------------------------------------
static std::string safeCopy(const char* p, size_t maxLen = 65536)
{
if (!p) {
std::cerr << "[safeCopy] p==nullptr => return empty.\n";
return std::string();
}
size_t realLen = strnlen(p, maxLen);
// Чтобы не засорять лог в случае очень больших строк, выведем только часть
std::string preview(p, (realLen > 200 ? 200 : realLen)); // максимум 200 символов
std::cerr << "[safeCopy] realLen=" << realLen
<< " preview='" << preview << "'\n";
return std::string(p, realLen);
}
// -----------------------------------------------------------------------------
// Экспортируемая функция, точка входа для Python
// -----------------------------------------------------------------------------
extern "C" __declspec(dllexport)
double calc_weight_sim_c(
const char** block1, int sizeB1,
const char** block2, int sizeB2
)
{
std::cerr << "\n[calc_weight_sim_c] => start. sizeB1=" << sizeB1
<< " sizeB2=" << sizeB2 << "\n";
std::vector<std::string> vecB1;
vecB1.reserve(sizeB1);
for (int i = 0; i < sizeB1; i++) {
if (!block1[i]) {
std::cerr << "[calc_weight_sim_c] WARNING: block1[" << i
<< "] == nullptr\n";
vecB1.emplace_back("");
}
else {
// Для отладки: выведем адрес указателя
std::cerr << "[calc_weight_sim_c] block1[" << i << "] ptr="
<< (const void*)block1[i] << "\n";
// Копируем
vecB1.emplace_back(safeCopy(block1[i], 1000000));
}
}
std::vector<std::string> vecB2;
vecB2.reserve(sizeB2);
for (int i = 0; i < sizeB2; i++) {
if (!block2[i]) {
std::cerr << "[calc_weight_sim_c] WARNING: block2[" << i
<< "] == nullptr\n";
vecB2.emplace_back("");
}
else {
std::cerr << "[calc_weight_sim_c] block2[" << i << "] ptr="
<< (const void*)block2[i] << "\n";
vecB2.emplace_back(safeCopy(block2[i], 1000000));
}
}
if (vecB1.empty() && vecB2.empty()) {
std::cerr << "[calc_weight_sim_c] #10 => both blocks empty =>0.\n";
return 0.0;
}
double result = 0.0;
try {
result = calc_weight_sim_impl(vecB1, vecB2);
}
catch (std::exception& ex) {
std::cerr << "[calc_weight_sim_c] EXCEPTION: "
<< ex.what() << "\n";
return 0.0;
}
catch (...) {
std::cerr << "[calc_weight_sim_c] UNKNOWN EXCEPTION.\n";
return 0.0;
}
std::cerr << "[calc_weight_sim_c] => result=" << result << "\n";
return result;
}
Boshka.h
#pragma once
#ifndef CALC_WEIGHT_SIM_H
#define CALC_WEIGHT_SIM_H
#ifdef _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif
#ifdef __cplusplus
#endif
extern "C" __declspec(dllexport) double calc_weight_sim_c(
const char** block1, int sizeB1,
const char** block2, int sizeB2
);
#ifdef __cplusplus
#endif
#endif // CALC_WEIGHT_SIM_H
все собрано правильно. Кучу форумов облазил чтобы найти решение этой проблемы и ничего не помогает.
Ответы (1 шт):
Невозможно проверить Ваш код, поскольку в нем что-то вызывается и, возможно, там и падает. Начинайте постепенно усложнять рабочий (у меня по крайней мере) код, примерно тот, который дает для питона GigaChat:
import ctypes
lib = ctypes.CDLL(r'C:\Users\Alex\PycharmProjects\SO_tests\pydll1.dll')
lib.calc_weight_sim_c.argtypes = (ctypes.POINTER(ctypes.c_char_p), ctypes.c_int)
lib.calc_weight_sim_c.restype = ctypes.c_double
py_strings = ["Hello ", "World! ", "На фига? "]
c_strings = (ctypes.c_char_p * len(py_strings))()
for i, string in enumerate(py_strings):
c_strings[i] = string.encode('utf-8')
print(lib.calc_weight_sim_c(c_strings,3))
cpp:
#include <iostream>
extern "C" __declspec(dllexport) double calc_weight_sim_c(const char **pp, int n)
{
for (int i = 0; i < n; i++, pp++)
std::cout << *pp;
return 3.1415;
}