Search code examples
mysqlcmemcpyreallocstrcat

C Realloc Append String MySQL Connector


I am attempting to loop through each database result, and have a single field from each row comma separated in a final string. I am aware that this is possible to do in MySQL alone, but I need to run functions on each result so that is not possible with the mysql only method.

Every few runs, I will get a segment fault, unwanted characters are added to the output, such as "^H^G" or Hex code (08 and 07) inside of Linux. It compiles properly, I just wish I could have consistent results. This code is inside a thread, but all variables are local to the current thread.

Final String should be the userstring char.

This is the latest code I've tried to work with.

MYSQL dbh;
MYSQL *dbh_p;
MYSQL_RES *res;
MYSQL_ROW row;
char *userstring = NULL;
char *userstring_r;
size_t userstringsize = 0;
size_t rowsize = 0;

/* Database Connect Code Here [Connects Successfully] */

if(mysql_query(dbh_p,query) == 0) {
    res = mysql_store_result(dbh_p);
    if(mysql_num_rows(res) > 0) {
        while((row = mysql_fetch_row(res))) {
            rowsize = strlen(row[0]) * sizeof(char);
            userstringsize += rowsize + 1;
            userstring_r = (char *) realloc(userstring,userstringsize + 1);

            printf("%d %d %p\n", rowsize, userstringsize, userstring_r);
            if(userstring_r != NULL) {
                /* Where the Issue Is */
                userstring = userstring_r;
                strcat(userstring,row[0]);
                strcat(userstring,",");
            }else{
                free(userstring);
                printf("Error With Realloc\n");
                mysql_thread_end();
                pthread_exit(NULL);
            }
        }
    }
    mysql_free_result(res);
}else{
    printf("Query Error: %s\n",mysql_error(&dbh));
}

-- EDIT -- Output:

9 10 0x7fe5f4014d90
14 25 0x7fe5f4014d90
9 35 0x7fe5f4014d90
11 47 0x7fe5f4014d90
... (same format and pointer value);
*** glibc detected *** ./pthread: realloc(): invalid next size: 0x00007fe5f4014d90 ***

This is the result even when I limit the threads to only 1.

Thank you for any help, or possible issues. I don't require full code, just tips / hints and possible fixes. I have tried strncat, memcpy, and changing various sizes without any luck.


Solution

  • Ok I think I know what's wrong:

    The first time userstring is allocated, it isn't initialised to being an empty string! Basically strcat has been putting the new data wherever it finds the first \0 byte, which could be anywhere.

    You need to somehow check whether it's the first time, and initialise it. Something like:

    if (userstringsize == 0)  // First time
    {
        userstringsize += rowsize + 1;
        userstring_r = (char *) malloc(userstringsize + 1);
        strcpy(userstring_r, "");  // Initialise to empty string
    }
    else
    {
        userstringsize += rowsize + 1;
        userstring_r = (char *) realloc(userstring,userstringsize + 1);
    }