webmcp

changeset 408:fd5880964d99

Hack to avoid cumulating memory leaks in case of (caught) out-of-memory errors
author jbe
date Thu Jan 07 01:23:08 2016 +0100 (2016-01-07)
parents 0e641ac76647
children ebe9416db4e0
files libraries/mondelefant/mondelefant_native.c
line diff
     1.1 --- a/libraries/mondelefant/mondelefant_native.c	Wed Jan 06 22:59:39 2016 +0100
     1.2 +++ b/libraries/mondelefant/mondelefant_native.c	Thu Jan 07 01:23:08 2016 +0100
     1.3 @@ -28,10 +28,24 @@
     1.4  typedef struct {
     1.5    PGconn *pgconn;
     1.6    int server_encoding;
     1.7 +  void *todo_PQfreemem;
     1.8 +  PGresult *todo_PQclear;
     1.9  } mondelefant_conn_t;
    1.10  #define MONDELEFANT_SERVER_ENCODING_ASCII 0
    1.11  #define MONDELEFANT_SERVER_ENCODING_UTF8  1
    1.12  
    1.13 +// hack to avoid cumulating memory leaks in case of out-of-memory errors
    1.14 +static void mondelefant_cleanup(mondelefant_conn_t *conn) {
    1.15 +  if (conn->todo_PQfreemem) {
    1.16 +    PQfreemem(conn->todo_PQfreemem);
    1.17 +    conn->todo_PQfreemem = NULL;
    1.18 +  }
    1.19 +  if (conn->todo_PQclear) {
    1.20 +    PQclear(conn->todo_PQclear);
    1.21 +    conn->todo_PQclear = NULL;
    1.22 +  }
    1.23 +}
    1.24 +
    1.25  // transform codepoint-position to byte-position for a given UTF-8 string:
    1.26  static size_t utf8_position_to_byte(const char *str, size_t utf8pos) {
    1.27    size_t bytepos;
    1.28 @@ -598,14 +612,23 @@
    1.29    conn = mondelefant_get_conn(L, 1);
    1.30    // get second argument, which must be a string:
    1.31    input = luaL_checklstring(L, 2, &input_len);
    1.32 +  // avoid cumulating memory leaks in case of previous out-of-memory errors:
    1.33 +  mondelefant_cleanup(conn);
    1.34    // call PQescapeByteaConn, which allocates memory itself:
    1.35    output = (char *)PQescapeByteaConn(
    1.36      conn->pgconn, (const unsigned char *)input, input_len, &output_len
    1.37    );
    1.38 -  // if PQescapeByteaConn returned NULL, then throw error:
    1.39    if (!output) {
    1.40 -    return luaL_error(L, "Could not allocate memory for binary quoting.");
    1.41 +    lua_gc(L, LUA_GCCOLLECT, 0);
    1.42 +    output = (char *)PQescapeByteaConn(
    1.43 +      conn->pgconn, (const unsigned char *)input, input_len, &output_len
    1.44 +    );
    1.45 +    if (!output) {
    1.46 +      return luaL_error(L, "Could not allocate memory for binary quoting.");
    1.47 +    }
    1.48    }
    1.49 +  // ensure call of PQfreemem in case of unexpected out-of-memory error:
    1.50 +  conn->todo_PQfreemem = output;
    1.51    // create Lua string enclosed by single quotes:
    1.52    luaL_buffinit(L, &buf);
    1.53    luaL_addchar(&buf, '\'');
    1.54 @@ -614,6 +637,8 @@
    1.55    luaL_pushresult(&buf);
    1.56    // free memory allocated by PQescapeByteaConn:
    1.57    PQfreemem(output);
    1.58 +  // avoid double call of PQfreemem later:
    1.59 +  conn->todo_PQfreemem = NULL;
    1.60    // return Lua string:
    1.61    return 1;
    1.62  }
    1.63 @@ -783,6 +808,7 @@
    1.64              lua_remove(L, -2);
    1.65              // Lua stack contains: ..., <buffer>, raw-value
    1.66              // branch according to type of value:
    1.67 +            // NOTE: Lua automatically converts numbers to strings
    1.68              if (lua_isnil(L, -1)) {  // value is nil
    1.69                // push string "NULL" to stack:
    1.70                lua_pushliteral(L, "NULL");
    1.71 @@ -790,9 +816,8 @@
    1.72                // push strings "TRUE" or "FALSE" to stack:
    1.73                lua_pushstring(L, lua_toboolean(L, -1) ? "TRUE" : "FALSE");
    1.74              } else if (lua_isstring(L, -1)) {  // value is string or number
    1.75 -              // NOTE: In this version of lua a number will be converted
    1.76 -              // push output of "quote_string" method of database
    1.77 -              // connection to stack:
    1.78 +              // push output of "quote_string" method of database connection
    1.79 +              // to stack:
    1.80                lua_tostring(L, -1);
    1.81                lua_pushcfunction(L, mondelefant_conn_quote_string);
    1.82                lua_pushvalue(L, 1);
    1.83 @@ -908,6 +933,8 @@
    1.84      mode = modes[command_idx];
    1.85      // if PQsendQuery call was successful, then fetch result data:
    1.86      if (sent_success) {
    1.87 +      // avoid cumulating memory leaks in case of previous out-of-memory errors:
    1.88 +      mondelefant_cleanup(conn);
    1.89        // NOTE: PQgetResult called one extra time. Break only, if all
    1.90        // queries have been processed and PQgetResult returned NULL.
    1.91        res = PQgetResult(conn->pgconn);
    1.92 @@ -916,6 +943,8 @@
    1.93          pgstatus = PQresultStatus(res);
    1.94          rows = PQntuples(res);
    1.95          cols = PQnfields(res);
    1.96 +        // ensure eventual call of PQclear in case of unexpected Lua errors:
    1.97 +        conn->todo_PQclear = res;
    1.98        }
    1.99      }
   1.100      // handle errors:
   1.101 @@ -1041,6 +1070,8 @@
   1.102          if (res) {
   1.103            PQclear(res);
   1.104            while ((res = PQgetResult(conn->pgconn))) PQclear(res);
   1.105 +          // avoid double call of PQclear later:
   1.106 +          conn->todo_PQclear = NULL;
   1.107          }
   1.108        }
   1.109        if (lua_toboolean(L, 3)) {
   1.110 @@ -1185,6 +1216,8 @@
   1.111      if (lua_gettop(L) != 4) abort();  // should not happen
   1.112      // free memory acquired by libpq:
   1.113      PQclear(res);
   1.114 +    // avoid double call of PQclear later:
   1.115 +    conn->todo_PQclear = NULL;
   1.116    }
   1.117    // trace callback at stack position 3
   1.118    // result at stack position 4 (top of stack)

Impressum / About Us