diff options
author | Adam Baratz <adambaratz@php.net> | 2017-11-10 13:29:14 -0500 |
---|---|---|
committer | Adam Baratz <adambaratz@php.net> | 2017-11-10 13:29:14 -0500 |
commit | 01f2427b838d55f8b6837585dadeb16edf4ed02b (patch) | |
tree | e2160572c1867b4cb337f8c902ae7dbb9919f36e /ext/pdo_dblib/dblib_stmt.c | |
parent | ca1f07b6d733c2f422cb99ffb0e6122b2d5f8b5e (diff) | |
download | php-git-01f2427b838d55f8b6837585dadeb16edf4ed02b.tar.gz |
More robust handling of stringified column data
- Use at least the FreeTDS maximum when converting datetime data
- Pass buffer length to dbconvert()
- Use dbconvert() return value to set string lengths or handle errors
- Move shared code into shared function
Diffstat (limited to 'ext/pdo_dblib/dblib_stmt.c')
-rw-r--r-- | ext/pdo_dblib/dblib_stmt.c | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index 175cb30332..3e4625ee67 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -260,7 +260,7 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno) return 1; } -static int pdo_dblib_stmt_stringify_col(pdo_stmt_t *stmt, int coltype) +static int pdo_dblib_stmt_should_stringify_col(pdo_stmt_t *stmt, int coltype) { pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; pdo_dblib_db_handle *H = S->H; @@ -305,6 +305,48 @@ static int pdo_dblib_stmt_stringify_col(pdo_stmt_t *stmt, int coltype) return 0; } +static void pdo_dblib_stmt_stringify_col(int coltype, LPBYTE data, DBINT data_len, zval **ptr) +{ + DBCHAR *tmp_data; + DBINT tmp_data_len; + zval *zv; + + /* FIXME: We allocate more than we need here */ + tmp_data_len = 32 + (2 * (data_len)); + + switch (coltype) { + case SQLDATETIME: + case SQLDATETIM4: { + if (tmp_data_len < DATETIME_MAX_LEN) { + tmp_data_len = DATETIME_MAX_LEN; + } + break; + } + } + + tmp_data = emalloc(tmp_data_len); + data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, tmp_data_len); + + zv = emalloc(sizeof(zval)); + if (data_len > 0) { + /* to prevent overflows, tmp_data_len is provided as a dest len for dbconvert() + * this code previously passed a dest len of -1 + * the FreeTDS impl of dbconvert() does an rtrim with that value, so replicate that behavior + */ + while (data_len > 0 && tmp_data[data_len - 1] == ' ') { + data_len--; + } + + ZVAL_STRINGL(zv, tmp_data, data_len); + } else { + ZVAL_EMPTY_STRING(zv); + } + + efree(tmp_data); + + *ptr = zv; +} + static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong *len, int *caller_frees) { @@ -323,15 +365,8 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, data_len = dbdatlen(H->link, colno+1); if (data_len != 0 || data != NULL) { - if (pdo_dblib_stmt_stringify_col(stmt, coltype) && dbwillconvert(coltype, SQLCHAR)) { - tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */ - tmp_data = emalloc(tmp_data_len); - data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, -1); - - zv = emalloc(sizeof(zval)); - ZVAL_STRING(zv, tmp_data); - - efree(tmp_data); + if (pdo_dblib_stmt_should_stringify_col(stmt, coltype) && dbwillconvert(coltype, SQLCHAR)) { + pdo_dblib_stmt_stringify_col(coltype, data, data_len, &zv); } if (!zv) { @@ -438,7 +473,6 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zv = emalloc(sizeof(zval)); ZVAL_STRINGL(zv, tmp_data, data_len); efree(tmp_data); - } else { /* 16-byte binary representation */ zv = emalloc(sizeof(zval)); @@ -449,14 +483,7 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, default: { if (dbwillconvert(coltype, SQLCHAR)) { - tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */ - tmp_data = emalloc(tmp_data_len); - data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, -1); - - zv = emalloc(sizeof(zval)); - ZVAL_STRING(zv, tmp_data); - - efree(tmp_data); + pdo_dblib_stmt_stringify_col(coltype, data, data_len, &zv); } break; |