如何找到指针错误的来源

How do I find the source of the pointer error

提问人:user12645705 提问时间:9/4/2023 更新时间:9/5/2023 访问量:79

问:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "splitter.h"

#define FOUR_K 4096

SplitResult split_join(int argc, char *argv[]) 
{
    SplitResult rs = E_NO_ACTION;

    if (argc < 7) 
    {
        return rs;
    }

    char* spiltOrJoin = argv[1];
    char* isSpiltOrJoin = spiltOrJoin;

    if (strcmp(isSpiltOrJoin, "-s") != 0 && strcmp(isSpiltOrJoin, "-j") != 0) 
    {
        return rs;
    }

    if (strcmp(isSpiltOrJoin, "-s") == 0) 
    {
        int smallChunkSize = atoi(argv[2]);

        const char* inputFileName = argv[6];
        const char* outputFilePrefix = argv[4];

        FILE* input = fopen(inputFileName, "rb");
        if (input != NULL) 
        {
            fseek(input, 0, SEEK_END);
            long fileSize = ftell(input);
            fseek(input, 0, SEEK_SET);

            int numChunks = (fileSize + smallChunkSize - 1) / smallChunkSize;

            char buffer[FOUR_K];

            int numOfPiecesOfChunk = smallChunkSize / sizeof(buffer);

            for (int i = 0; i < numChunks; i++) 
            {
                char outputFileName[256];
                snprintf(outputFileName, sizeof(outputFileName), "%s%s%d", outputFilePrefix, "000", i + 1);
                FILE* output = fopen(outputFileName, "wb");

                if (output == NULL)
                {
                    rs = E_BAD_DESTINATION;
                    fclose(input);
                    return rs;
                }

                char* chunkBuffer = (char*)malloc(FOUR_K);

                if (chunkBuffer == NULL)
                {
                    rs = E_NO_MEMORY;
                    fclose(input);
                    fclose(output);
                    return rs;
                }

                if (numOfPiecesOfChunk > 0)
                {
                    for (int j = 0; j < numOfPiecesOfChunk; j++)
                    {
                        size_t bytesRead = fread(chunkBuffer, 1, sizeof(buffer), input);
                        fwrite(chunkBuffer, 1, bytesRead, output);
                    }

                    int remainingBytesOfChunk = smallChunkSize - (sizeof(chunkBuffer) * numOfPiecesOfChunk);
                    size_t bytesRead = fread(chunkBuffer, 1, remainingBytesOfChunk, input);
                    fwrite(chunkBuffer, 1, bytesRead, output);
                }
                else
                {
                    size_t bytesRead = fread(chunkBuffer, 1, smallChunkSize, input);
                    fwrite(chunkBuffer, 1, bytesRead, output);
                }

                fclose(output); //Problem statement

                FILE* checkInput = fopen(outputFileName, "rb");

                if (checkInput == NULL)
                {
                    rs = E_BAD_DESTINATION;
                    free(chunkBuffer);
                    fclose(input);
                    return rs;
                }

                fseek(checkInput, 0, SEEK_END);
                long fileSize = ftell(checkInput);
                fseek(checkInput, 0, SEEK_SET);

                if (fileSize <= 0)
                {
                    rs = E_SMALL_SIZE;
                    free(chunkBuffer);
                    fclose(input);
                    fclose(checkInput);
                    return rs;
                }

                fclose(checkInput);

                free(chunkBuffer);
            }

            fclose(input);
            rs = E_SPLIT_SUCCESS;
        }
        else 
        {
            rs = E_BAD_SOURCE;
            return rs;
        }
    }
    else 
    {
        char* outputFile = argv[3];
        char* title = outputFile;
        int numOfFiles = argc - 5;
        FILE* output = fopen(title, "wb");

        if (output != NULL) 
        {
            for (int i = 0; i < numOfFiles; i++) 
            {
                FILE* chunkFile = fopen(argv[i + 5], "rb");

                if (chunkFile == NULL) 
                {
                    rs = E_BAD_SOURCE;
                    return rs;
                }

                fseek(chunkFile, 0, SEEK_END);
                long fileSize = ftell(chunkFile);
                int sizeOfFile = (int)fileSize;
                fseek(chunkFile, 0, SEEK_SET);

                int numOfFilePieces = 0;

                char* buffer = (char*)malloc(FOUR_K);

                if (buffer == NULL)
                {
                    rs = E_NO_MEMORY;
                    fclose(chunkFile);
                    fclose(output);
                    return rs;
                }

                if (sizeOfFile > sizeof(buffer)) 
                {
                    numOfFilePieces = sizeOfFile / sizeof(buffer);
                }

                if (chunkFile != NULL) {
                    if (numOfFilePieces > 0) 
                    {
                        for (int i = 0; i < numOfFilePieces; i++) 
                        {
                            size_t bytesRead = fread(buffer, 1, sizeof(buffer), chunkFile);
                            fwrite(buffer, 1, bytesRead, output);
                        }

                        int remainingBytesOfChunk = sizeOfFile - (sizeof(buffer) * numOfFilePieces);
                        size_t bytesRead = fread(buffer, 1, remainingBytesOfChunk, chunkFile);
                        fwrite(buffer, 1, bytesRead, output);
                    }
                    else 
                    {
                        size_t bytesRead = fread(buffer, 1, sizeOfFile, chunkFile);
                        fwrite(buffer, 1, bytesRead, output);
                    }

                    fclose(chunkFile);
                }

                free(buffer);
            }

            rs = E_JOIN_SUCCESS;

            fclose(output);
        }
        else if (output == NULL) 
        {
            rs = E_BAD_DESTINATION;
            return rs;
        }
    }

    return rs;
}

我正在尝试编写一个 C 程序,将文件分成较小的文件,然后将较小的文件合并为较大的文件。当我尝试运行程序时,我收到一个 munmap_chunk(): invalid pointer 错误,导致行 fclose(output)(由问题语句指示)。为什么会这样?

起初我以为 malloc 会导致某些变量具有相同名称的问题,但事实并非如此。

C 文件 指针 错误处理 malloc

评论

0赞 Retired Ninja 9/4/2023
sizeof(buffer)是指针的大小,可能是 8,而不是它指向的分配的大小。尝试将使用它的任何地方替换为 .FOUR_K
2赞 Retired Ninja 9/4/2023
@TedLyngmo啊,也许我把它和所以这可能是不正确的混淆了。这很可能是我最初打算复制的那一行,而是抓住了上面几行的那行。char* chunkBuffer = (char*)malloc(FOUR_K);int remainingBytesOfChunk = smallChunkSize - (sizeof(chunkBuffer) * numOfPiecesOfChunk);
1赞 Retired Ninja 9/5/2023
至于如何找到内存损坏的根源,AddressSanitizer经常创造奇迹。
1赞 Ted Lyngmo 9/5/2023
@RetiredNinja哦,我没有走那么远:-)
1赞 Ted Lyngmo 9/5/2023
@user12645705 如果您需要调试帮助,您需要向我们提供我们可以编译的代码。请阅读有关如何创建最小可重现示例的信息。

答:

0赞 Fe2O3 9/5/2023 #1

此代码的“拆分”部分长度为 100 行(不带注释)。难怪有一个看不见的错误(@RetiredNinja指出)。太多的代码和太多的变量!为什么在堆外分配另一个缓冲区 () 时处于未使用状态?这毫无意义。buffer[FOUR_K]chunkBuffer

下面是对函数的“拆分”部分的未经测试的重写。“加入”部分是愚蠢的,什么时候可以完成这项工作。cat

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stat.h> // new
#include "splitter.h"

SplitResult splitOne( FILE *ifp, size_t smallChunkSize, int idx, char *prefix ) {
    FILE *ofp = NULL;
    size_t want = smallChunkSize; // size of each output file

    char ofn[256];
    snprintf( ofn, sizeof(ofn), "%s%06d", prefix, idx );
    if( ( ofp = fopen( ofn, "wb" ) ) == NULL ) // start a new file
        return E_BAD_DESTINATION;

    while( want ) { // while batch incomplete
        char buf[FOUR_K];

        // the minimum of buffer size or remaining in batch
        size_t maxToRead = min( sizeof buf, want );
        size_t got = fread( buf, 1, maxToRead, ifp );
        // Should test for unexpected EOF
        // N.B. Last read of source likely to be < expected.

        fwrite( buf, 1, got, ofp ); // obvious

        want -= got; // reduce count remaining for this batch
    }
    fclose( ofp );

    return E_SPLIT_SUCCESS;
}

SplitResult split( int argc, char *argv[] ) {
    int smallChunkSize = atoi(argv[2]);
    char *ifn = argv[6];
    char *prefix = argv[4];

    if ( ( ifp = fopen( ifn, "rb" ) ) == NULL)
        return E_BAD_SOURCE;

    // Correct way to get a file's byte count
    struct stat finfo;
    if( fstat( fileno( ifp ), &finfo ) != 0 ) {
        fclose( ifp );
        return E_BAD_SOURCE;
    }

    int i = 1; // for unique output filenames
    size_t remain = finfo.st_size; // remain in source file
    SplitResult rs = E_NO_ACTION; // a default initial value

    while( remain // while source file not exhausted
    && ( rs = splitOne( ifp, smallChunkSize, i++, prefix ) ) == E_SPLIT_SUCCESS ) // want a batch of this size
        remain -= smallChunkSize; // shrink remaining in source file

    fclose( ifp );

    return rs;
}

SplitResult split_join( int argc, char *argv[] ) {
    if (argc < 7)
        return E_NO_ACTION;

    if( strcmp( split_join, "-s" ) == 0 ) return split( argc, argv );

    if( strcmp( split_join, "-j" ) == 0 ) return join( argc, argv ); // not done

    return E_NO_ACTION;
}

调用堆栈中的每个函数都执行其操作,为调用下一个函数做准备。不要试图在一个整体函数中完成所有操作。

(请注意:没有可能失败的动态分配。