0

I'm using g++.

Implemented some wrapper for my convenience to work with libmysql. Also making C/C++ compatible code.

static MYSQL_RES *db_query(MYSQL *db, const char *query, va_list params) {
    char q[500];
    vsprintf(q, query, params);
    va_end(params);
    if (mysql_query(db, q)) {
        fprintf(stderr, "%s\n", mysql_error(db));
        return NULL;
    }

    MYSQL_RES *res = mysql_use_result(db);
    return res;
}

MYSQL_ROW* db_query_all(MYSQL *db, const char* query, ...) {
        va_list params;
    MYSQL_RES *res = db_query(db, query, params);

    int count = mysql_num_rows(res);

    MYSQL_ROW rows[count];
    for (int i = 0; i<count; i++) 
    {
        rows[i] = mysql_fetch_row(res);
    }

    mysql_free_result(res);
    return rows;
}

And getting warning during compilation:

warning: address of local variable ‘rows’ returned [-Wreturn-local-addr]
     MYSQL_ROW rows[count];

Please help me to find what's the problem there. I can't google something relevant to my particular case.

xercool
  • 883
  • 1
  • 8
  • 24
  • `MYSQL_ROW rows[count];` will be allocated on the stack, you need to allocate it on the heap via `malloc`/`calloc`, if it remain on the stack, the content of the variable would be undefined once you exit the function – dvhh Oct 11 '19 at 06:26

3 Answers3

2

A more C++ way to do it is to define a movable buffer type:

struct Buf {
  Buf(size_t size) : mPtr(std::make_unique<MYSQL_ROW[]>(size)), mSize(size) {}

  std::unique_ptr<MYSQL_ROW[]> mPtr;
  size_t mSize;
};

Then you can implement the function like this:

Buf db_query_all(MYSQL *db, const char* query, ...) {
        va_list params;
    MYSQL_RES *res = db_query(db, query, params);

    int count = mysql_num_rows(res);

    Buf rows(count);
    for (int i = 0; i<count; i++) 
    {
        rows.mPtr[i] = mysql_fetch_row(res);
    }

    mysql_free_result(res);
    return std::move(rows);
}

The big upside of this approach is that you don't have to do manual memory handling.

Pibben
  • 1,876
  • 14
  • 28
  • Wow. That looks cool. But why didn't you use `std::string` tho? Anyway I need C-compatible code in order of better performance but thank you shared this snippet too – xercool Oct 11 '19 at 07:39
  • 1
    "C-compatible code" will not automatically give you better performance. – Pibben Oct 11 '19 at 07:44
1

rows is local array to db_query_all function and will be destroyed once control exits the function thus it is undefined behavior to return reference of it.

You can dynamically allocate the memory and return reference to it.

MYSQL_ROW* db_query_all(MYSQL *db, const char* query, ...) {
        va_list params;
    MYSQL_RES *res = db_query(db, query, params);

    int count = mysql_num_rows(res);

    MYSQL_ROW *rows = malloc(sizeof(*rows)*count);
    for (int i = 0; i<count; i++) 
    {
        rows[i] = mysql_fetch_row(res);
    }

    mysql_free_result(res);
    return rows;
}

Note you need to free the memory once done processing.

kiran Biradar
  • 12,700
  • 3
  • 19
  • 44
1

Your error message comes from this line:

MYSQL_ROW rows[count];

which means that rows will be allocated on the stack, meaning that once your function exit the content of your variable will be undefined.

You need to either :

  • allocate the variable on heap (recommended)
MYSQL_ROW rows[] = calloc(count,sizeof(MYSQL_ROW));

don't forget to free the result once you no further need it

  • pass rows from upstream as an argument
    which would require you to get the count at another step
dvhh
  • 4,724
  • 27
  • 33
  • Is it necessary to use `calloc` instead of `malloc`. I know basically the difference but what about this particular thing? – xercool Oct 11 '19 at 06:34
  • no real difference, you might squeeze more perfomance by using `malloc` as `calloc` is zeroing the allocated memory. – dvhh Oct 11 '19 at 06:41
  • 1
    Since the question is asked in a C++ context, you should use new/delete instead of malloc()/free(). – Pibben Oct 11 '19 at 07:10
  • 1
    @Pibben I asked about C/C++ context. That means I write C program for C++ compiler which has more strict rules. I like I have a gap for refactoring completely to C++ eventually but now I love to work with C instead :) – xercool Oct 11 '19 at 07:16
  • @Pibben to be fair I answer from a C perspective due to the C tag – dvhh Oct 11 '19 at 07:52