free (): в tcache 2 обнаружена двойная свободная ошибка c realloc
Я пытаюсь сохранить файл слов (максимальная длина 100 символов, но я не знаю, сколько), сохраняя указатели на слова в символе **. Я начинаю с выделения памяти для 100 указателей и подсчета слов, которые я сохраняю. Если в файле более 100 слов, я начинаю перераспределять память с местом для еще одного указателя каждый раз, когда читаю новое слово из файла. Затем я выделяю место для фактических символов слова.
Я проверил код с файлом более 300 слов, и я получаю сообщение об ошибке free(): double free detected in tcache 2 Я думаю, это из-за malloc после realloc? Но я не уверен, как это исправить.
Я изменил цикл на это:
И работает без ошибок. Но меня беспокоит то, что word_pointer после каждого вызова realloc() будет указывать на то, где был список моих слов раньше, верно? Как я могу изменить его, чтобы после вставки, например, 120 слов, происходит realloc, что он указывает на новые mywords + 120, чтобы я мог продолжать вставлять указатели?
2 ответа
Прежде всего, вы игнорируете возвращаемое значение realloc, которое является указателем на выделенную память.
В этом случае realloc может быть расширяющим блоком уже заданной памяти (если это возможно) или, в противном случае, выделить совершенно новый блок памяти и скопировать заданный ввод.
Должен сделать свое дело.
Кроме того, перераспределение, как я уже говорил, не очень оптимально. Обратите внимание, что каждый раз, когда вы сталкиваетесь с новым словом, realloc должен найти место в памяти и скопировать целый блок данных. Итак, предположительно, учитывая файл с 300 словами, ваша программа копирует ваш массив 200 раз.
Я думаю, что было бы намного лучше сначала отсканировать файл, сосчитав все слова, а затем с помощью fseek переместить индикатор в начало. После этого выделите массив для ваших слов и отсканируйте файл.
Сразу после редактирования исходного вопроса я придумал решение. Мне просто нужно было добавить строку word_pointer = mywords + wordcount; под вызовом realloc()
ошибка c++ double free или corruption (out)
Я получаю ошибку «Double free или corruption (out)» после того, как я печатаю свой вывод. Но эта ошибка возникает только для небольших входов. Для больших входных данных программа не выдает эту ошибку. Когда я создаю многомерные массивы внутри main и удаляю их, я не получаю ошибку. Я опубликовал здесь только ту часть кода, которая имеет отношение к этому вопросу. Пожалуйста, объясните, как решить эту проблему.
1 ответ:
Я полагаю, что корень вашей проблемы вызван распределением valueArray и тем фактом, что вы выходите за пределы итерации.
Строка valueArray=new int[value]; инициализирует valueArray массивом размера value , который является неинициализированной переменной. Возможно, вы хотели использовать noItems ?
Также, как указал сонгюаньяо в комментариях, ваши for циклы выглядят как for(int i=1;i<=noItems;i++) , который начинает счетчик в 1 и заканчивается счетчиком в noItems , что является ошибочным. Во многих языках, включая C++ , массивы начинаются с индекса 0 (то есть первый элемент — array[0] , а не array[1] ), а последний элемент-единица минус размер массива (таким образом, последний элемент массива с 5 элементами — array[4] ).
Если вы измените свой цикл for , чтобы начать с 0 и закончить один элемент перед noItems , Вы должны быть золотыми. Это будет for(int i = 0; i < noItems; i++ )
Что, вероятно, происходит с меньшими выделениями, так это то, что различные куски памяти расположены последовательно в одной и той же области кучи памяти, поэтому, когда вы переполняя буфер данными, вы разбиваете бухгалтерские данные new .
Когда у вас есть большие выделения, новая память не может поместиться так же чисто в свободное пространство кучи, поэтому распределитель в конечном итоге оставляет некоторое свободное пространство между выделениями. Таким образом, небольшой перерасход не уничтожает кучу информации.
How to track down a "double free or corruption" error
When I run my (C++) program it crashes with this error.
* glibc detected * ./load: double free or corruption (!prev): 0x0000000000c6ed50 ***
How can I track down the error?
I tried using print ( std::cout ) statements, without success. Could gdb make this easier?
9 Answers 9
If you’re using glibc, you can set the MALLOC_CHECK_ environment variable to 2 , this will cause glibc to use an error tolerant version of malloc , which will cause your program to abort at the point where the double free is done.
You can set this from gdb by using the set environment MALLOC_CHECK_ 2 command before running your program; the program should abort, with the free() call visible in the backtrace.
see the man page for malloc() for more information
There are at least two possible situations:
- you are deleting the same entity twice
- you are deleting something that wasn’t allocated
For the first one I strongly suggest NULL-ing all deleted pointers.
You have three options:
- overload new and delete and track the allocations
- yes, use gdb — then you’ll get a backtrace from your crash, and that’ll probably be very helpful
- as suggested — use Valgrind — it isn’t easy to get into, but it will save you time thousandfold in the future.
You can use gdb, but I would first try Valgrind. See the quick start guide.
Briefly, Valgrind instruments your program so it can detect several kinds of errors in using dynamically allocated memory, such as double frees and writes past the end of allocated blocks of memory (which can corrupt the heap). It detects and reports the errors as soon as they occur, thus pointing you directly to the cause of the problem.
Three basic rules:
- Set pointer to NULL after free
- Check for NULL before freeing.
- Initialise pointer to NULL in the start.
Combination of these three works quite well.
You can use valgrind to debug it.
One possible fix:
Check out the blog on using Valgrind Link
With modern C++ compilers you can use sanitizers to track.
Compile with address sanitizers :
To learn more about sanitizers you can check this or this or any modern c++ compilers (e.g. gcc, clang etc.) documentations.
Are you using smart pointers such as Boost shared_ptr ? If so, check if you are directly using the raw pointer anywhere by calling get() . I’ve found this to be quite a common problem.
For example, imagine a scenario where a raw pointer is passed (maybe as a callback handler, say) to your code. You might decide to assign this to a smart pointer in order to cope with reference counting etc. Big mistake: your code doesn’t own this pointer unless you take a deep copy. When your code is done with the smart pointer it will destroy it and attempt to destroy the memory it points to since it thinks that no-one else needs it, but the calling code will then try to delete it and you’ll get a double free problem.
Of course, that might not be your problem here. At it’s simplest here’s an example which shows how it can happen. The first delete is fine but the compiler senses that it’s already deleted that memory and causes a problem. That’s why assigning 0 to a pointer immediately after deletion is a good idea.
Double Free or Corruption Error in C++
This tutorial will discuss issues that occur in dynamic memory allocations in C++. When using heap memory, we come across many issues that are very important to be addressed while doing heap memory management.
First, we will discuss how we allocate memory and the different methods provided in C++; then, we will move towards the causes and solutions of double free or corruption error in C++.
Dynamic Memory Allocation and Deallocation in C++
C++ allows us to allocate variable or array memory during runtime. This is referred to as dynamic memory allocation.
In other programming languages, such as Java and Python, the compiler maintains variable memory automatically. However, this is not the case in C++.
In C++, we must manually deallocate dynamically allocated memory after we no longer require it. We may allocate and deallocate memory dynamically using the new and delete functions.
There are other two functions, i.e., malloc and free , which are also included in C++ for dynamic memory allocation and deallocation.
Consider an example below demonstrating the use of new and delete functions.
We dynamically allocated memory for an int variable using the’ new’ operator. It’s worth noting that we used the reference variable ptr to allocate memory dynamically.
The new operator returns the memory location’s address. In the case of an array, the new operator returns the address of the array’s first element.
We can deallocate the memory used by a dynamically declared variable after we no longer need to utilize it. The delete operator is used for this.
It gives the memory back to the operating system. This is referred to as memory deallocation.
The next example will show you a demonstration of malloc and free functions.
In C++, the malloc() method assigns a pointer to a block of uninitialized memory. The cstdlib header file defines it.
malloc takes in as a parameter the size of memory you need to allocate and returns a void pointer pointing to the allocated memory block. Hence it can be typecast according to our requirements.
On the other hand, the free() method deallocates the memory allocated using the malloc function. It returns that memory to the operating system and avoids memory leakage issues.
double free or corruption Error in C++
Double-free errors occur when free() is used more than once with the same memory address as an input.
Calling free() on the same variable twice can result in a memory leak. When a software runs free() twice with the same parameter, the memory management data structures in the application get corrupted, allowing a malicious user to write values in any memory area.
This corruption can cause the program to crash or change the execution flow in some cases. An attacker can mislead a program into executing a code of their choice by overwriting specific registers or memory regions, resulting in an interactive shell with elevated rights.
A linked list of free buffers is read when a buffer is free() ’d to reorganize and combine the pieces of free memory (to allocate larger buffers in the future). These chunks are organized in a double-linked list with links to the chunks before and after them.
An attacker might write arbitrary values in memory by unlinking an unused buffer (which happens when free() is invoked), effectively overwriting valuable registers, and launching shellcode from its buffer.
Consider an example below.
In the code snippet above, we have used the free() function twice, which means we are trying to free up the memory that is already free and is no more allocated. This creates a memory leakage issue and is the root cause of crashing the code.
- Error conditions and other unusual situations
- After the memory space has been released, it is used.
- Confusion about which section of the program is in charge of memory freeing
Although some double-free vulnerabilities aren’t much more complex than the preceding example, most of them are distributed across hundreds of lines of code or even multiple files. Programmers appear to be particularly prone to freeing global variables multiple times.
How to Avoid double free or corruption Error in C++
This type of vulnerability can be avoided by assigning NULL to our pointer whenever it becomes free (i.e., the memory pointed by this pointer gets free). Following that, most of the heap managers ignore the free null pointers.
It is recommended to null all deleted pointers and check whether the reference is null or not before freeing it. At the start of our code, we must initialize the null pointer before using that pointer in any case.
Husnain is a professional Software Engineer and a researcher who loves to learn, build, write, and teach. Having worked various jobs in the IT industry, he especially enjoys finding ways to express complex ideas in simple ways through his content. In his free time, Husnain unwinds by thinking about tech fiction to solve problems around him.