You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确复用已分配指针?解决double free or corruption (! prev)错误

Fixing "double free or corruption (! prev)" in Your SQLite3 Iteration Code

Let's break down the critical bugs in your code that are causing this memory corruption error—even when you comment out the sqlite3_get_table call. Most issues stem from incorrect string handling and syntax mistakes that trigger undefined behavior.

Key Issues in Your Code

1. Syntax & Type Errors

  • Missing parenthesis in malloc: Your malloc call is missing a closing ), which is a syntax error that can lead to unexpected compilation behavior:
    // Wrong
    char *query = malloc(sizeof(char) * (arr1.length * 10 + 200);
    // Correct
    char *query = malloc(sizeof(char) * (arr1.length * 10 + 200));
    
  • Invalid for loop syntax: 0l is a long integer literal, and you're missing a semicolon in the loop condition:
    // Wrong
    for(i=0l i<arr1.length; i++){
    // Correct
    for(i=0; i<arr1.length; i++){
    }
    
  • Incorrect SQLite handle type: The first parameter to getValues should be a sqlite3* pointer, not sqlite3:
    // Wrong
    void getValues(sqlite3 conn, struct Arr arr1, struct Arr arr2, int *values){
    // Correct
    void getValues(sqlite3 *conn, struct Arr arr1, struct Arr arr2, int *values){
    }
    
  • Missing semicolon after free: free(query) needs a trailing semicolon to avoid syntax errors.

2. Dangerous String Reset

The line sprintf(query, '\0') is the primary culprit for your memory corruption. Here's why:

  • sprintf expects its second argument to be a format string pointer. Passing '\0' (a char with value 0) gets promoted to an integer, which is treated as a NULL pointer. This causes sprintf to attempt reading from NULL, triggering undefined behavior that corrupts heap metadata.
  • Fix: Reset the string safely by setting the first character to the null terminator directly:
    query[0] = '\0';
    

3. Flawed Query Construction Logic

  • Misplaced strcpy: You're calling strcpy(query, "...") inside the i loop but outside the j loop—this means you'll overwrite the query string only once per i iteration, but if the previous query was longer, you might leave leftover characters. Move this strcpy to the start of each i loop to ensure a clean start.
  • Mismatched array length check: You're checking j == arr1.length - 1 when j is iterating over arr2—this will cause incorrect string termination. Use j == arr2.length - 1 instead.
  • Insufficient buffer size: Your buffer and buffer_ don't account for the null terminator. For a number N, the string length is ceil(log10(N+1)), so you need to add 1 to the buffer size to store '\0':
    // Wrong
    char buffer[sizeof(char) * (int)(ceil(log10(arr1.arr_[j]+1)))];
    // Correct
    char buffer[(int)(ceil(log10(arr1.arr_[j]+1)) + 1)];
    

4. Unhandled SQLite3 Result

While you commented out sqlite3_get_table, remember that when you use it, you must free the result array with sqlite3_free_table(res) to avoid memory leaks.

Corrected Code

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

struct Arr{ int length; int *arr_; };

void getValues(sqlite3 *conn, struct Arr arr1, struct Arr arr2, int *values){
    int i, j;
    int state, nrow, ncolumn;
    char **res;
    char *err_msg = 0;
    // Allocate query buffer with enough space
    size_t query_size = sizeof(char) * (arr1.length * 10 + 200);
    char *query = malloc(query_size);
    if (!query) { // Always check malloc success
        fprintf(stderr, "Malloc failed!\n");
        return;
    }

    for(i=0; i<arr1.length; i++){
        // Reset query to empty string at the start of each iteration
        query[0] = '\0';
        // Start building the query
        strcpy(query, "select * from table1 where value1 in (");
        
        for(j=0; j<arr2.length; j++){
            // Calculate buffer size with room for null terminator
            int buf_len = (int)(ceil(log10(arr1.arr_[j]+1)) + 1);
            char buffer[buf_len];
            sprintf(buffer, "%d", arr1.arr_[j]);
            // Use strncat to avoid overflow (optional but safer)
            strncat(query, buffer, query_size - strlen(query) - 1);
            
            if(j == arr2.length - 1){
                strncat(query, " ) and value2 = ", query_size - strlen(query) - 1);
                int buf_len_ = (int)(ceil(log10(arr2.arr_[i]+1)) + 1);
                char buffer_[buf_len_];
                sprintf(buffer_, "%d", arr2.arr_[i]);
                strncat(query, buffer_, query_size - strlen(query) - 1);
                strncat(query, ";", query_size - strlen(query) - 1);
            } else {
                strncat(query, " , ", query_size - strlen(query) - 1);
            }
        }

        printf("query: %s\n", query);
        state = sqlite3_get_table(conn, query, &res, &nrow, &ncolumn, &err_msg);
        if (state != SQLITE_OK) {
            fprintf(stderr, "SQL error: %s\n", err_msg);
            sqlite3_free(err_msg);
        } else {
            // Process your result here
            // ...
            sqlite3_free_table(res); // Don't forget to free the result!
        }
    }

    free(query);
}

Why This Fixes the Error

The sprintf(query, '\0') line was corrupting the heap metadata that malloc/free uses to track allocated blocks. By replacing that with a safe string reset, fixing the buffer overflows, and correcting syntax errors, you eliminate the undefined behavior that was triggering the "double free or corruption" message.

内容的提问来源于stack exchange,提问作者Erwin Zangwill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 17:32:43