无法在C中找到内存泄漏

问题描述 投票:1回答:1

我发现某个地方存在内存泄漏/错误后,已经坐了几个小时来检查这段代码那个泄漏在哪里?如何解决?这是Dr.Memory报告:

Dr. Memory version 2.3.0
         Running "C:\Users\Beni\source\repos\Magshimim_EX8\Debug\Magshimim_EX8.exe"
         Using system call file C:\Users\Beni\AppData\Roaming\Dr. Memory\symcache\syscalls_wow64.txt

         Error #1: UNADDRESSABLE ACCESS: reading 1 byte(s)
         replace_strlen 
             d:\drmemory_package\drmemory\replace.c(412):
         Magshimim_EX8.exe!?                
             ??:0
         Magshimim_EX8.exe!?                
             ??:0
         Magshimim_EX8.exe!?                
             ??:0
         Magshimim_EX8.exe!?                
             ??:0
         Magshimim_EX8.exe!?                
             ??:0
         KERNEL32.dll!BaseThreadInitThunk
             ??:0

         ERRORS FOUND:
               1 unique,     1 total unaddressable access(es)
               0 unique,     0 total uninitialized access(es)
               0 unique,     0 total invalid heap argument(s)
               0 unique,     0 total GDI usage error(s)
               0 unique,     0 total handle leak(s)
               0 unique,     0 total warning(s)
               0 unique,     0 total,      0 byte(s) of leak(s)
               0 unique,     0 total,      0 byte(s) of possible leak(s)
         Details: C:\Users\Beni\AppData\Roaming\Dr. Memory\DrMemory-Magshimim_EX8.exe.5208.000\results.txt
         WARNING: application exited with abnormal code 0xc0000005
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>

#define FALSE 0
#define TRUE !FALSE
#define FIRST_TWO_FILES 2
#define FIRST_TWENTY_PRECENTS 1
#define MIDDLE_SIXTY_PRECENTS 2
#define LAST_TWENTY_PRECENTS 3

long findLenOfFile(FILE * file);
char* readFile(FILE* f, char* dest, long len);
char menu(char* scanFolder, char* virusSignature);
char** writeFilesFromFolder(char* scanFolder, char ** filesList, int* len);
char* writePart(char* src, char* dest, int length, int* newLen, int part);
int findSignature(char* virusSignature, char* buffer, int sigLen, int bufferLen);
void scanFiles(char* scanFolder, char** filesList, int amountOfFiles, char* virusSignature, long virusLength, char option);


int main(int argc, char* argv[])
{
    char* log = malloc(sizeof(char)*strlen(argv[1]) + sizeof(char)*strlen("\\Log.txt") + 4);
    FILE* virusSignatureFile = fopen(argv[2], "rb");
    long virusLength = 0;
    char** filesList = (char**)malloc(sizeof(char) * 0);
    char* virusSignature = 0;
    int amountOfFiles = 0;
    char option = 0;
    int i = 0;

    virusLength = findLenOfFile(virusSignatureFile);

    // get the virusSignature as a string and write the files to check into the filesList
    virusSignature = readFile(virusSignatureFile, virusSignature, virusLength);
    filesList = writeFilesFromFolder(argv[1], filesList, &amountOfFiles);

    // create log file
    strcpy(log, "");
    strcat(log, argv[1]);
    strcat(log, "\\Log.txt");
    FILE * logFile = fopen(log, "w");
    fprintf(logFile, "Anti-virus began! Welcome!\n\nFolder to scan:\n%s\nVirus signature:\n%s\n\nScanning option:\n", argv[1], argv[2]);

    // get scanning option (normal or quick) and continue accordingly
    option = menu(argv[1], argv[2]);
    if (option == '0') {
        fprintf(logFile, "Normal Scan\n\n");
    }
    else {
        fprintf(logFile, "Quick Scan\n\n");
    }
    fprintf(logFile, "Results:\n");
    fclose(logFile);

    // initiate scan
    scanFiles(argv[1], filesList, amountOfFiles, virusSignature, virusLength, option);

    fclose(virusSignatureFile);
    free(log);
    free(filesList);
    free(virusSignature);
    getchar();
    return 0;
}



/*
This function will print the scanning folder path and signature path, also will print the option menu to the user of quick or normal scan,
after that function will return user option(0, or other key)
input: scanFolder path (string), virus signature path (also string)
output: user option (char: '0', or other key)
*/
char menu(char * scanFolder, char * virusSignature)
{
    char userOption = '\0';
    printf("Welcome to my Virus Scan!\n\nFolder to scan: %s\nVirus signature: %s\n\nPress 0 for a norman scan or any other key for a quick scan: ", scanFolder, virusSignature);
    userOption = getchar();
    printf("Scanning began...\nThis process may take several minutes...\n\n");
    return userOption;
}


/*
This function writes all files name from folder to the filesList
input: the scanning folder path
output: amount of files
*/
char** writeFilesFromFolder(char * scanFolder, char ** filesList, int* len)
{
    DIR *d = 0;

    struct dirent *dir;
    d = opendir(scanFolder);
    int i = 0;

    if (d)
    {
        while ((dir = readdir(d)) != NULL)
        {
            if (i > 1)
            {
                filesList = (char**)realloc(filesList, sizeof(filesList) + sizeof(char*) + 4);
                *(filesList + (i - FIRST_TWO_FILES)) = (char*)malloc(sizeof(char) * strlen(dir->d_name) + 1);
                strcpy(*(filesList + (i - FIRST_TWO_FILES)), (dir->d_name));
            }
            i++;
        }
        closedir(d);
    }
    *len = i - FIRST_TWO_FILES; //first two names is "." and ".."
    return filesList;
}

/*
This function will read the contents of a file into a string
input: a file (FILE *) to read from
output: char* with the contents of the file
*/
char* readFile(FILE* f, char * dest, long len)
{
    dest = (char*)malloc(sizeof(char) * len);
    fread(dest, 1, len, f);
    return dest;
}


void scanFiles(char * scanFolder, char ** filesList, int amountOfFiles, char * virusSignature, long virusLength, char option)
{
    char* log = malloc(sizeof(char)*strlen(scanFolder) + sizeof(char)*strlen("\\Log.txt") + 1);
    char * buffer = (char*)malloc(sizeof(char) * 0);
    char* subBuffer = 0;
    char* slash = "\\";
    long length = 0;
    char* name = 0;
    int subLen = 0;
    int i = 0;
    FILE * f;

    // reopen log file and append to it
    strcpy(log, "");
    strcat(log, scanFolder);
    strcat(log, "\\Log.txt");
    FILE * logFile = fopen(log, "a");

    // iterate over each file
    for (i = 0; i < amountOfFiles; i++)
    {
        name = (char*)malloc(sizeof(char) * strlen(scanFolder) + 1 + sizeof(char) * strlen(slash) + sizeof(char) * strlen(*(filesList + i)) + 20);

        // open current file
        strcpy(name, "");
        strcat(name, scanFolder);
        strcat(name, slash);
        strcat(name, *(filesList + i));
        f = fopen(name, "rb");

        length = findLenOfFile(f);

        if (f != NULL) // if file can be accessed
        {
            buffer = readFile(f, buffer, length);
            if (option == '0') { // Normal Mode
                if (findSignature(virusSignature, buffer, virusLength, length))
                {
                    printf("%s - Infected!\n", name);
                    fprintf(logFile, "%s - Infected!\n", name);
                }
                else
                {
                    printf("%s - Clean\n", name);
                    fprintf(logFile, "%s - Clean\n", name);
                }
            }
            else { // Quick Mode
                subBuffer = writePart(buffer, subBuffer, length, &subLen, FIRST_TWENTY_PRECENTS); // get first 20%
                if (findSignature(virusSignature, subBuffer, virusLength, subLen))
                {
                    printf("%s - infected! (first 20%%)\n", name);
                    fprintf(logFile, "%s - infected! (first 20%%)\n", name);
                }
                else {
                    free(subBuffer);
                    subBuffer = writePart(buffer, subBuffer, length, &subLen, LAST_TWENTY_PRECENTS); // get last 20%
                    if (findSignature(virusSignature, subBuffer, virusLength, subLen))
                    {

                        printf("%s - Infected! (last 20%%)\n", name);
                        fprintf(logFile, "%s - Infected! (last 20%%)\n", name);
                    }
                    else {
                        subBuffer = writePart(buffer, subBuffer, length, &subLen, MIDDLE_SIXTY_PRECENTS); // get the 60% left in the middle
                        if (findSignature(virusSignature, subBuffer, virusLength, subLen))
                        {
                            printf("%s - Infected!\n", name);
                            fprintf(logFile, "%s - Infected!\n", name);
                        }
                        else {
                            printf("%s - clean\n", name);
                            fprintf(logFile, "%s - Clean\n", name);
                        }
                    }
                }
                free(subBuffer);
            }
            fclose(f);
        }
        else
        {
            printf("No file found\n");
        }
        free(*(filesList + i));
        free(name);
    }
    fclose(logFile);
    free(log);
    free(buffer);
    getchar();
}


/*
This function will write part of the file (beginning, middle or end) to a string
input: source (string) to take the information from, destination (string) to write a part of the source to it,
       length (int) of the source string, a pointer (int*) to store the new length of the destination string and
       part of the file to write from (int) 1,2 or 3: first 20%, 60% in the middle and last 20% accordingly
output: string containing the desired part of the source string
*/
char* writePart(char *src, char *dest, int length, int *newLen, int part) {
    int i = 0;
    int percentedLength = 0;
    int count = 0;
    percentedLength = (int)(length / 5); // this len is 20% of the entire file's length


    if (part == FIRST_TWENTY_PRECENTS) // return beginning
    {
        dest = (char*)malloc(sizeof(char) * percentedLength);
        *newLen = percentedLength;

        for (i = 0; i < percentedLength; i++)
        {
            *(dest + i) = *(src + i);
        }
    }
    else if (part == MIDDLE_SIXTY_PRECENTS)  // return middle
    {
        // allocate space for the middle: The entire file size minus 20% from the start and 20% from the end
        dest = (char*)malloc(sizeof(char) * (length - 2 * percentedLength));
        *newLen = length - 2 * percentedLength;

        for (i = percentedLength; i < length - percentedLength; i++) {
            *(dest + count) = *(src + i);
            count++;
        }
    }
    else if (part == LAST_TWENTY_PRECENTS) // return end
    {
        dest = (char*)malloc(sizeof(char) * percentedLength);
        *newLen = percentedLength;

        for (i = length - percentedLength; i < length; i++)
        {
            *(dest + count) = *(src + i);
            count++;
        }
    }
    return dest;
}

/*
function that finds the length of a file
input: file (FILE *)
output: the file's length (long)
*/
long findLenOfFile(FILE * file)
{
    long length = 0;
    fseek(file, 0, SEEK_END);
    length = ftell(file);
    fseek(file, 0, SEEK_SET);
    return length;
}

/*
function checks whether a file contains the virusSignature. It iterates over each letter of the file and checks
if it is the same as the first letter in the virusSignature. If it is, it checks the rest of the characters and
returns True if a match is found. if not it continues the same process until the end of the file is reached.
input: The virusSignature (string), a buffer with the content of a file (string), the signature's length (int)
       and the buffer's length (int)
output: True if signature is in file, False otherwise
*/
int findSignature(char* virusSignature, char* buffer, int sigLen, int bufferLen)
{
    int found = 0;
    int i = 0;
    int j = 0;

    for (i = 0; i < bufferLen - (sigLen - 1); i++) {
        if (*(buffer + i) == *virusSignature) // check if a letter is the same as first letter in virusSignature
        {
            found = TRUE;
            // check if the rest of the letters match the signature and stop if one doesn't
            for (j = 1; (j < sigLen) && found; j++) {
                if (*(buffer + (i + j)) != *(virusSignature + j)) {
                    found = FALSE;
                }
            }
            if (found) {
                return TRUE; // if we got a match, return true!
            }
        }
    }
    return FALSE;
}
c arrays pointers memory-leaks heap-memory
1个回答
0
投票

realloc中的writeFilesFromFolder调用有错误。

它是:

filesList = (char **) realloc(filesList, sizeof(filesList) + sizeof(char *) + 4);

注意,为filesList分配的空间为恒定。当添加新元素时,它[会增长,因此您具有未定义的行为。

这是

不是

检测到该工具的内存泄漏。内存泄漏意味着您无法free超出范围的指针。相反,您存储的数据超出了分配的区域的末端,浪费了其中的任何内容,这可能是malloc等的[隐藏]链指针区域。等用于跟踪分配。

我不确定sizeof中的任何一个因素如何,但是filesList是一个指针,所以sizeof(filesList)是常数[在32位计算机上为4或在64位计算机上为8]。

分配的空间必须与i成比例增加。

顺便说一句,不要投射mallocDo I cast the result of malloc?


这里是该函数的重构版本,修复了该错误并进行了一些简化和清理:

/* This function writes all files name from folder to the filesList input: the scanning folder path output: amount of files */ char ** writeFilesFromFolder(char *scanFolder, char **filesList, int *len) { DIR *d = 0; struct dirent *dir; d = opendir(scanFolder); int i = -FIRST_TWO_FILES; if (d) { while ((dir = readdir(d)) != NULL) { if (i >= 0) { filesList = realloc(filesList,sizeof(*filesList) * (i + 1)); filesList[i] = strdup(dir->d_name); } i++; } closedir(d); } *len = i; // first two names is "." and ".." return filesList; }

© www.soinside.com 2019 - 2024. All rights reserved.