У меня есть простая функция, использующая привязки gmp C ++:
#include <inttypes.h>
#include <memory>
#include <gmpxx.h>
mpz_class f(uint64_t n){
std::unique_ptr<mpz_class[]> m = std::make_unique<mpz_class[]>(n + 1);
m[0] = 0;
m[1] = 1;
for(uint64_t i = 2; i <= n; ++i){
m[i] = m[i-1] + m[i-2];
}
return m[n];
}
int main(){
mpz_class fn;
for(uint64_t n = 0;; n += 1){
fn = f(n);
}
}
Предположительно make_unique
должен выделить массив fre sh и освободить его, когда функция вернется, поскольку уникальный указатель, которому она принадлежит, имеет свой конец жизни. Предположительно, возвращаемый объект mpz_class
должен быть копией и не подвержен удалению этого массива. Программа вылетает с ошибкой:
realloc(): invalid next size
, и если я смотрю дамп ядра в gdb, я получаю трассировку стека:
#0 raise()
#1 abort()
#2 __libc_message()
#3 malloc_printerr()
#4 _int_realloc()
#5 realloc()
#6 __gmp_default_reallocate()
#7 __gmpz_realloc()
#8 __gmpz_add()
#9 __gmp_binary_plus::eval(v, w, z)
#10 __gmp_expr<...>::eval(this, this, p)
#11 __gmp_set_expr<...>(expr, z)
#12 __gmp_expr<...>::operator=<...>(expr, this)
#13 f(n)
#14 main(argc, argv)
Это мне не полезно, кроме что это говорит о том, что, возможно, проблема исходит от gmpxx с использованием шаблонов выражений (стековые фреймы 9-12 указывают на это, valgrind и стековый фрейм 12 помещают последнюю строку моего кода перед ошибкой m[1] = 1;
). Вэлгринд говорит, что в этой строке есть недопустимое чтение размера 8, но перечисляет записи стека, соответствующие остальной части трассы после него, а затем говорит, что в следующей инструкции есть недопустимая запись. Недопустимое чтение составляет 8 байт после «блока размером 24 allo c 'd [by make_unique
]», в то время как недопустимая запись равна нулю. Очевидно, что эта строка также не должна вызывать, поскольку она должна только читать указатель и затем записывать в часть буфера, на который он указывает, который определенно не имеет адреса 0x0. Я решил использовать привязки C ++, хотя я всегда использую gmp из C, потому что думал, что писать будет быстрее, но эта ошибка гарантировала, что это не так. Это проблема с gmp или я неправильно распределяю массив? Я получаю похожие ошибки, если я использовал new
и delete
напрямую или если я вручную встроил вызов функции. Я чувствую, что проблема может быть связана с mpz_class
, на самом деле хранящим шаблон выражения, а не с конкретным значением.
Я использую G CC 9.2.0 с g++ -std=c++17 -O2 -g -Wall ...
и GMP 6.1. 2-3. Ни Clang, ни G CC не сообщают об ошибках.