我正在编写一个程序,该程序使用动态内存分配来获取几行文本作为输入,然后将这些行向后写,并将单词向后写。当 realloc 函数中没有错误时,就没有内存泄漏,但是当函数遇到任何 reallocs 错误时,1 个块中仍有 1024 个字节仍然可以访问,并且有一个 free() 比 reallocs 少。
rand_malloc.h 是我们的教授用来使 realloc 崩溃并返回 NULL
的文件代码:
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include "rand_malloc.h"
#include <stdbool.h>
int get_length_of_line(const char* line)
{
if (line == NULL)
{
return 0;
}
int size = 0;
while (line[size] != 10 && line[size])
{
size += 1;
}
return size + 1;
}
void print_line_backwards(char* line)
{
size_t size_of_line = get_length_of_line(line);
for (int i = size_of_line; i >= 0; i--)
{
if (line[i] == '\n')
{
i--;
}
if (line[i] == ' ')
{
int j = i + 1;
while (line[j] != ' ' && line[j] != '\n')
{
printf("%c", line[j]);
j++;
}
printf(" ");
}
if (i == 0)
{
int j = i;
while (line[j] != ' ' && line[j] != '\n')
{
printf("%c", line[j]);
j++;
}
}
}
printf("\n");
}
char* get_line(bool* is_fail)
{
char* line = NULL;
int character_input;
size_t size = 0;
size_t bufsize = 0;
while ((character_input = getchar()) != EOF)
{
if (size >= bufsize)
{
char* newbuf;
if (bufsize == 0)
{
bufsize = 2;
}
else if (bufsize <= ((size_t)-1) / 2)
{
bufsize = 2 * size;
}
else
{
*is_fail = true;
free(line);
return NULL;
}
newbuf = realloc(line, bufsize);
if (newbuf == NULL)
{
*is_fail = true;
free(line);
return NULL;
}
line = newbuf;
}
line[size++] = character_input;
if (character_input == '\n')
{
break;
}
}
if ((character_input == EOF) && size == 0)
{
return NULL;
}
if (size >= bufsize)
{
char* newbuf;
if (size < (size_t)-1)
{
bufsize = size + 1;
}
else
{
*is_fail = true;
free(line);
return NULL;
}
newbuf = realloc(line, bufsize);
if (newbuf == NULL)
{
*is_fail = true;
free(line);
return NULL;
}
line = newbuf;
}
line[size++] = '\0';
return line;
}
void** read_lines()
{
bool is_fail_get_line = false;
char** lines = NULL;
char* line;
size_t bufsize_line = 0;
size_t line_count = 0;
while ((line = get_line(&is_fail_get_line)))
{
if (line_count >= bufsize_line)
{
char** newbuf;
if (bufsize_line == 0)
{
bufsize_line = 2;
}
else if (bufsize_line <= ((size_t)-1) / 2 / sizeof(char*))
{
bufsize_line = 2 * line_count;
}
else
{
goto ERROR;
}
newbuf = realloc(lines, bufsize_line * sizeof(char*));
if (newbuf == NULL)
{
goto ERROR;
}
lines = newbuf;
}
lines[line_count++] = line;
}
if (is_fail_get_line)
{
goto ERROR;
}
if (!is_fail_get_line)
{
printf("\nNormal output:\n");
for (int i = 0; i < line_count; i++)
{
printf("%s", lines[i]);
}
printf("\n\n\n");
printf("Backwards output :\n");
for (int i = line_count - 1; i >= 0; i--)
{
print_line_backwards(lines[i]);
free(lines[i]);
}
free(lines);
return 0;
}
ERROR:
//printf("\nerror_state: %d\n", is_fail_get_line);
for (int i = line_count - 1; i >= 0; i--)
{
free(lines[i]);
}
free(lines);
free(line);
abort();
return 0;
}
int main(int argc, char* argv[])
{
read_lines();
return 0;
}
Valgrind 输出:
==22043== Memcheck, a memory error detector
==22043== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22043== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==22043== Command: ./test
==22043==
1 2 3 4
==22043==
==22043== Process terminating with default action of signal 6 (SIGABRT)
==22043== at 0x4901A7C: __pthread_kill_implementation (pthread_kill.c:44)
==22043== by 0x4901A7C: __pthread_kill_internal (pthread_kill.c:78)
==22043== by 0x4901A7C: pthread_kill@@GLIBC_2.34 (pthread_kill.c:89)
==22043== by 0x48AD475: raise (raise.c:26)
==22043== by 0x48937F2: abort (abort.c:79)
==22043== by 0x109825: read_lines (test.c:188)
==22043== by 0x109849: main (test.c:194)
==22043==
==22043== HEAP SUMMARY:
==22043== in use at exit: 1,024 bytes in 1 blocks
==22043== total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated
==22043==
==22043== 1,024 bytes in 1 blocks are still reachable in loss record 1 of 1
==22043== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==22043== by 0x48E9C23: _IO_file_doallocate (filedoalloc.c:101)
==22043== by 0x48F8D5F: _IO_doallocbuf (genops.c:347)
==22043== by 0x48F7D5B: _IO_file_underflow@@GLIBC_2.2.5 (fileops.c:485)
==22043== by 0x48F8E15: _IO_default_uflow (genops.c:362)
==22043== by 0x109528: get_line (test.c:60)
==22043== by 0x1096BA: read_lines (test.c:133)
==22043== by 0x109849: main (test.c:194)
==22043==
==22043== LEAK SUMMARY:
==22043== definitely lost: 0 bytes in 0 blocks
==22043== indirectly lost: 0 bytes in 0 blocks
==22043== possibly lost: 0 bytes in 0 blocks
==22043== still reachable: 1,024 bytes in 1 blocks
==22043== suppressed: 0 bytes in 0 blocks
==22043==
==22043== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Aborted (core dumped)
我用过 valgrind 和 gbd,但我仍然不明白问题出在哪里。
编辑
rand_malloc.h:
#pragma once
#include <stddef.h>
#define malloc(x) rand_malloc(x)
#define calloc(x, y) rand_calloc(x, y)
#define realloc(x, y) rand_realloc(x, y)
void* rand_malloc(size_t size);
void* rand_calloc(size_t num, size_t size);
void* rand_realloc(void* ptr, size_t size);
rand_malloc.c:
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
/** Rate of random error injection. Acceptable values: 0-100 */
unsigned const ALLOCATION_ERROR_RATE = 10;
bool randomness_initialized = false;
bool check_whether_to_call_real_function()
{
if (!randomness_initialized) {
srand(time(NULL));
randomness_initialized = true;
}
int r = rand() % 100;
return r >= ALLOCATION_ERROR_RATE;
}
void* rand_malloc(size_t size)
{
if (check_whether_to_call_real_function()) {
return malloc(size);
}
return NULL;
}
void* rand_calloc(size_t num, size_t size)
{
if (check_whether_to_call_real_function()) {
return calloc(num, size);
}
return NULL;
}
void* rand_realloc(void* ptr, size_t size)
{
if (check_whether_to_call_real_function()) {
return realloc(ptr, size);
}
return NULL;
}
程序对任何一种输入都有问题,例如: ,,1 1 1 1 1 1 1 1 11 1 1 1 1"