可能的缓冲区溢出

时间:2011-11-29 18:57:31

标签: c visual-studio-2010 buffer-overflow

我在这里遇到一个令人愤怒的问题,我正在malloc / calloc / strdup崩溃,我现在假设这是因为某个地方有缓冲区。

我发现这很难找到,我想知道你们中是否有人能帮助我。我会在这里发布代码片段,并链接到完整的源代码。

文件读取和数组操作:(common.c)

Pastebin

char * S6_ReadFileBytes(const char* path)
    FILE * file;
    long length;
    char * bytes = NULL;
    file = fopen(path, "r");
    fseek(file, 0, SEEK_END)
    length = ftell(file);
    fseek(file, 0, 0);
    bytes = (char*)calloc(1, (size_t)length + 1);
    fread(bytes, 1, (size_t)length, file);
    return bytes;

S6_Array * S6_ArrayNew(size_t count, size_t typeSize)
    S6_Array * a = (S6_Array*)malloc(sizeof(S6_Array));
    a->typeSize = typeSize;
    a->Length = count;

void * S6_ArrayGet(S6_Array * a, int idx)
    return &((char*)a->Data)[idx * a->typeSize];

void S6_ArraySet(S6_Array * a, int idx, void * val)
    memcpy(&((char*)a->Data)[idx * a->typeSize], val, a->typeSize);

void S6_ArrayGrow(S6_Array * a, int amount)
    void * data;
    data = realloc(a->Data, (a->Length + amount) * a->typeSize);
    a->Data = data;
    a->Length += amount;

void S6_ArrayPushBack(S6_Array * a, void* val)
    S6_ArrayGrow(a, 1);
    S6_ArraySet(a, a->Length - 1, val);

CSV阅读:(CSV.c)

Pastebin

void S6_CSV_PushRect(S6_Array ** rectangles, S6_Rectangle * rect)
    if( !*rectangles )
        *rectangles = S6_ArrayNew(1, sizeof(S6_Rectangle*));
        S6_ArraySet(*rectangles, 0, &rect);
    else
        S6_ArrayPushBack(*rectangles, &rect);

int S6_CSV_ReadRects(const char* file, S6_Array ** rectangles)
    char * bytes = S6_ReadFileBytes(file);
    char * line;
    char * nameIndex;
    size_t nameLength;
    S6_Rectangle * tempRect;

    line = strtok( bytes , "\n");
    while( line )
        nameIndex = strstr(line, ",");
        tempRect = (S6_Rectangle*)calloc(1, sizeof(S6_Rectangle));

        nameLength = (size_t)(nameIndex - line) + 1;
        strncpy(tempRect->name, line, nameLength-1);
        tempRect->name[nameLength-1] = '\0';

        sscanf(nameIndex, "%*[,]%d%*[,]%d%*[,]%d%*[,]%d", &tempRect->x, &tempRect->y, &tempRect->w, &tempRect->h)

        S6_CSV_PushRect(rectangles , tempRect);
        strtok(NULL, "\n");
    free(bytes);

我修改数组的函数:(BinPacker.c)

Pastebin

int S6_BinPacker_Pack(S6_Array * rectangles, int binSize)
    // This sort appears to be working fine. View pastebin for test.
    qsort(rectangles->Data, rectangles->Length, sizeof(S6_Rectangle*), S6_BinPacker_CompareRects);

CSV写作[CRASH] :(CSV.c)

Pastebin

void S6_CSV_WriteRects(const char* file, S6_Array * rectangles)
    char * bytes = NULL;
    char buffer[128];
    S6_Rectangle * tempRect;
    size_t i;

    for( i = 0; i < rectangles->Length; ++i)
        tempRect = *(S6_Rectangle**)S6_ArrayGet(rectangles, i);
        memset(buffer, '\0', sizeof(buffer));

        sprintf(buffer, 
            "%s,%d,%d,%d,%d\n",
            tempRect->name,
            temprect->x,
            temprect->y,
            temprect->w,
            temprect->h);
        if( bytes )
            bytes = strcat(bytes, _strdup(buffer));
        else
            bytes = _strdup(buffer);

所以我在strcat(bytes, _strdup(buffer))线上崩溃了。当我把它分开时它仍然是字符串重复或我试过的任何类型的分配。

我从visual studio获得以下休息对话框:

Windows has triggered a breakpoint in myapp.exe.

This may be due to a corruption of the heap, which indicates a bug in Slant6.Debug.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while Slant6.Debug.exe has focus.
The output window may have more diagnostic information.

它触发的断点是在tidtable.c上

PFLS_GETVALUE_FUNCTION flsGetValue = FLS_GETVALUE;

strdup没有做任何分配,即使这样做,我也会像疯了一样泄漏。所以而不是:

bytes = strcat(bytes, _strdup(buffer));

在CSV.c中,我用一些手动字符串连接替换它,这对我来说更容易阅读(并记住)。

size_t oldSize = strlen(bytes);
size_t bufferSize = strlen(buffer);
size_t newSize = oldSize + bufferSize ;

char * newMem = (char*)calloc(newSize + 1, 1);

memcpy(newMem, bytes, newSize);
memcpy(&newMem[oldSize], buffer, bufferSize);

free(bytes);
bytes = newMem;

/溶液

1 个答案:

答案 0 :(得分:1)

我在想这一行:

bytes = strcat(bytes, _strdup(buffer));

不按照你的想法行事。

您正在制作字符串(buffer)的副本,然后将其连接到bytes。永远不会释放重复的字符串 bytes仅与上一个_strdup一样大,因此执行strcat会溢出缓冲区。

您需要为strlen(bytes) + strlen(buffer)分配(或重新分配)strcat等。