Skip to content

Commit ee626ad

Browse files
author
Rahul Priyadarshi
committed
Segfault due to INTERNED strings in PHP-5.4.x
1 parent 9cfa917 commit ee626ad

File tree

2 files changed

+159
-40
lines changed

2 files changed

+159
-40
lines changed

ibm_db2.c

Lines changed: 158 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ static void _php_db2_assign_options( void* handle, int type, char* opt_key, zval
4949
static int _php_db2_parse_options( zval* options, int type, void* handle TSRMLS_DC );
5050
static void _php_db2_clear_conn_err_cache(TSRMLS_D);
5151
static void _php_db2_clear_stmt_err_cache(TSRMLS_D);
52+
static void _php_db2_clear_exec_many_err_cache(void* handle);
5253
static void _php_db2_set_decfloat_rounding_mode_client(void* handle TSRMLS_DC);
5354
static char * _php_db2_instance_name;
5455
static int is_ios, is_zos; /* 1 == TRUE; 0 == FALSE; */
@@ -402,6 +403,7 @@ static void _php_db2_free_result_struct(stmt_handle* handle)
402403
param_node *curr_ptr = NULL, *prev_ptr = NULL;
403404

404405
if ( handle != NULL ) {
406+
_php_db2_clear_exec_many_err_cache(handle);
405407
/* Free param cache list */
406408
curr_ptr = handle->head_cache_list;
407409
prev_ptr = handle->head_cache_list;
@@ -1976,11 +1978,11 @@ static void _php_db2_clear_stmt_err_cache(TSRMLS_D)
19761978

19771979
/* {{{ static void _php_db2_clear_exec_many_err_cache (TSRMLS_D)
19781980
*/
1979-
static void _php_db2_clear_exec_many_err_cache( stmt_handle *stmt )
1981+
static void _php_db2_clear_exec_many_err_cache( void *stmt )
19801982
{
1981-
if ( stmt->exec_many_err_msg != NULL ) {
1982-
efree(stmt->exec_many_err_msg);
1983-
stmt->exec_many_err_msg = NULL;
1983+
if ( ((stmt_handle*)stmt)->exec_many_err_msg != NULL ) {
1984+
efree(((stmt_handle*)stmt)->exec_many_err_msg);
1985+
((stmt_handle*)stmt)->exec_many_err_msg = NULL;
19841986
}
19851987
}
19861988
/* }}} */
@@ -3703,6 +3705,9 @@ static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **b
37033705
}
37043706
if (curr->param_type == DB2_PARAM_OUT || curr->param_type == DB2_PARAM_INOUT) {
37053707
int origlen = Z_STRLEN_PP(bind_data);
3708+
if (IS_INTERNED((*bind_data)->value.str.val)) {
3709+
Z_STRVAL_PP(bind_data) = estrndup(Z_STRVAL_PP(bind_data), origlen);
3710+
}
37063711
if (Z_STRLEN_PP(bind_data) < curr->param_size+nullterm) {
37073712
Z_STRVAL_PP(bind_data) = erealloc(Z_STRVAL_PP(bind_data), curr->param_size+nullterm);
37083713
if (Z_STRVAL_PP(bind_data) == NULL ) {
@@ -3712,8 +3717,11 @@ static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **b
37123717
if (curr->param_type == DB2_PARAM_INOUT)
37133718
#endif
37143719
memset(Z_STRVAL_PP(bind_data)+origlen,0x20, curr->param_size-origlen);
3715-
if (nullterm) Z_STRVAL_PP(bind_data)[origlen] = '\0';
3716-
Z_STRLEN_PP(bind_data) = curr->param_size;
3720+
if (nullterm) {
3721+
Z_STRVAL_PP(bind_data)[origlen] = '\0';
3722+
Z_STRVAL_PP(bind_data)[curr->param_size] = '\0';
3723+
}
3724+
Z_STRLEN_PP(bind_data) = curr->param_size;
37173725
}
37183726
#ifdef PASE /* help out PHP script trunc trailing chars -- LUW too? */
37193727
else if (Z_STRLEN_PP(bind_data) > curr->param_size) {
@@ -3723,6 +3731,9 @@ static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **b
37233731
}
37243732
#ifdef PASE /* zero length valueType = SQL_C_CHAR bad for i5/OS SQLBindParameter */
37253733
else if (Z_STRLEN_PP(bind_data) == 0) {
3734+
if (IS_INTERNED((*bind_data)->value.str.val)) {
3735+
Z_STRVAL_PP(bind_data) = estrndup(Z_STRVAL_PP(bind_data), Z_STRLEN_PP(bind_data));
3736+
}
37263737
Z_TYPE_PP(bind_data) = IS_STRING;
37273738
Z_STRVAL_PP(bind_data) = erealloc(Z_STRVAL_PP(bind_data), curr->param_size+nullterm);
37283739
memset(Z_STRVAL_PP(bind_data), 0x20, curr->param_size+nullterm);
@@ -3761,6 +3772,9 @@ static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **b
37613772
case SQL_TYPE_TIMESTAMP:
37623773
if (curr->param_type == DB2_PARAM_OUT || curr->param_type == DB2_PARAM_INOUT) {
37633774
int origlen = Z_STRLEN_PP(bind_data);
3775+
if (IS_INTERNED((*bind_data)->value.str.val)) {
3776+
Z_STRVAL_PP(bind_data) = estrndup(Z_STRVAL_PP(bind_data), Z_STRLEN_PP(bind_data));
3777+
}
37643778
if (Z_STRLEN_PP(bind_data) < curr->param_size + 1) {
37653779
Z_STRVAL_PP(bind_data) = erealloc(Z_STRVAL_PP(bind_data), curr->param_size + 1);
37663780
if (Z_STRVAL_PP(bind_data) == NULL ) {
@@ -3774,6 +3788,9 @@ static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **b
37743788
}
37753789
#ifdef PASE /* zero length valueType = SQL_C_CHAR bad for i5/OS SQLBindParameter */
37763790
else if (Z_STRLEN_PP(bind_data) == 0) {
3791+
if (IS_INTERNED((*bind_data)->value.str.val)) {
3792+
Z_STRVAL_PP(bind_data) = estrndup(Z_STRVAL_PP(bind_data), Z_STRLEN_PP(bind_data));
3793+
}
37773794
Z_STRVAL_PP(bind_data) = erealloc(Z_STRVAL_PP(bind_data), curr->param_size + 1);
37783795
memset(Z_STRVAL_PP(bind_data), 0x20, curr->param_size + 1);
37793796
Z_STRVAL_PP(bind_data)[curr->param_size] = '\0';
@@ -3789,7 +3806,7 @@ static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **b
37893806

37903807
/* copy data over from bind_data */
37913808
*(curr->value) = **bind_data;
3792-
zval_copy_ctor(curr->value);
3809+
zval_copy_ctor(curr->value);
37933810
INIT_PZVAL(curr->value);
37943811

37953812
/* Have to use SQLBindFileToParam if PARAM is type DB2_PARAM_FILE */
@@ -3932,9 +3949,10 @@ static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **b
39323949

39333950
case IS_NULL:
39343951
Z_LVAL_P(curr->value) = SQL_NULL_DATA;
3952+
Z_TYPE_P(curr->value) = IS_NULL;
39353953
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num,
39363954
curr->param_type, SQL_C_DEFAULT, curr->data_type, curr->param_size,
3937-
curr->scale, &(curr->value), 0, &((curr->value)->value.lval));
3955+
curr->scale, &(curr->value), 0, (SQLLEN *)&((curr->value)->value.lval));
39383956
if ( rc == SQL_ERROR ) {
39393957
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1 TSRMLS_CC);
39403958
}
@@ -4056,6 +4074,41 @@ static int _php_db2_execute_helper(stmt_handle *stmt_res, zval **data, int bind_
40564074
}
40574075
/* }}} */
40584076

4077+
/* {{{ static void _free_param_cache_list(stmt_handle *stmt_res)
4078+
*/
4079+
static void _free_param_cache_list(stmt_handle *stmt_res) {
4080+
param_node *prev_ptr = NULL, *curr_ptr = NULL;
4081+
4082+
curr_ptr = stmt_res->head_cache_list;
4083+
prev_ptr = stmt_res->head_cache_list;
4084+
/* Free param cache list */
4085+
while (curr_ptr != NULL) {
4086+
curr_ptr = curr_ptr->next;
4087+
4088+
/* Free Values */
4089+
if (prev_ptr->value != NULL) {
4090+
if ( Z_TYPE_P(prev_ptr->value) == IS_STRING ) {
4091+
if((prev_ptr->value)->value.str.val != NULL || (prev_ptr->value)->value.str.len != 0) {
4092+
if (!IS_INTERNED((prev_ptr->value)->value.str.val)) {
4093+
efree((prev_ptr->value)->value.str.val);
4094+
}
4095+
}
4096+
}
4097+
4098+
if( prev_ptr->param_type != DB2_PARAM_OUT && prev_ptr->param_type != DB2_PARAM_INOUT ){
4099+
efree(prev_ptr->value);
4100+
}
4101+
}
4102+
efree(prev_ptr);
4103+
4104+
prev_ptr = curr_ptr;
4105+
}
4106+
4107+
stmt_res->head_cache_list = NULL;
4108+
stmt_res->num_params = 0;
4109+
}
4110+
/* }}} */
4111+
40594112
/* {{{ proto bool db2_execute(resource stmt [, array parameters_array])
40604113
Executes a prepared SQL statement */
40614114
PHP_FUNCTION(db2_execute)
@@ -4229,31 +4282,7 @@ PHP_FUNCTION(db2_execute)
42294282
/* cleanup dynamic bindings if present */
42304283
if ( bind_params == 1 ) {
42314284
/* Free param cache list */
4232-
curr_ptr = stmt_res->head_cache_list;
4233-
prev_ptr = stmt_res->head_cache_list;
4234-
4235-
while (curr_ptr != NULL) {
4236-
curr_ptr = curr_ptr->next;
4237-
4238-
/* Free Values */
4239-
if (prev_ptr->value != NULL) {
4240-
if ( Z_TYPE_P(prev_ptr->value) == IS_STRING ) {
4241-
if((prev_ptr->value)->value.str.val != NULL || (prev_ptr->value)->value.str.len != 0) {
4242-
efree((prev_ptr->value)->value.str.val);
4243-
}
4244-
}
4245-
4246-
if( prev_ptr->param_type != DB2_PARAM_OUT && prev_ptr->param_type != DB2_PARAM_INOUT ){
4247-
efree(prev_ptr->value);
4248-
}
4249-
}
4250-
efree(prev_ptr);
4251-
4252-
prev_ptr = curr_ptr;
4253-
}
4254-
4255-
stmt_res->head_cache_list = NULL;
4256-
stmt_res->num_params = 0;
4285+
_free_param_cache_list(stmt_res);
42574286
} else {
42584287
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3
42594288
/* ADC - PHP changed general behavior 5.3+ */
@@ -6847,7 +6876,7 @@ PHP_FUNCTION( db2_execute_many )
68476876
error_msg_node *head_error_list = NULL;
68486877

68496878
int rc;
6850-
int i = 0;
6879+
int i = 0, j = 0;
68516880
SQLSMALLINT numOpts = 0;
68526881
int numOfRows = 0;
68536882
int numOfParam = 0;
@@ -6874,6 +6903,7 @@ PHP_FUNCTION( db2_execute_many )
68746903
}
68756904

68766905
ZEND_FETCH_RESOURCE(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
6906+
_php_db2_clear_exec_many_err_cache(stmt_res);
68776907

68786908
/* Free any cursor that might have been allocated in a previous call to SQLExecute */
68796909
SQLFreeStmt((SQLHSTMT)stmt_res->hstmt, SQL_CLOSE);
@@ -6883,12 +6913,17 @@ PHP_FUNCTION( db2_execute_many )
68836913
rc = SQLNumParams((SQLHSTMT)stmt_res->hstmt, (SQLSMALLINT*)&numOpts);
68846914
data_type = (SQLSMALLINT*)ecalloc(numOpts, sizeof(SQLSMALLINT));
68856915
array_data_type = (SQLSMALLINT*)ecalloc(numOpts, sizeof(SQLSMALLINT));
6916+
for ( i = 0; i < numOpts; i++) {
6917+
array_data_type[i] = -1;
6918+
}
68866919
if ( numOpts != 0 ) {
68876920
for ( i = 0; i < numOpts; i++ ) {
68886921
rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, i + 1, (SQLSMALLINT*)(data_type + i), &precision, (SQLSMALLINT*)&scale, (SQLSMALLINT*)&nullable);
68896922
if ( rc == SQL_ERROR ) {
68906923
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Describe Param %d Failed", i + 1);
68916924
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1 TSRMLS_CC);
6925+
efree(array_data_type);
6926+
efree(data_type);
68926927
RETURN_FALSE;
68936928
}
68946929
_php_db2_build_list( stmt_res, i + 1, data_type[i], precision, scale, nullable );
@@ -6900,7 +6935,7 @@ PHP_FUNCTION( db2_execute_many )
69006935
zend_hash_internal_pointer_reset(Z_ARRVAL_P(params));
69016936
head_error_list = (error_msg_node*)ecalloc(1, sizeof(error_msg_node));
69026937
head_error_list->next = NULL;
6903-
if ( numOfRows != 0 ) {
6938+
if ( numOfRows > 0 ) {
69046939
for ( i = 0; i < numOfRows; i++ ) {
69056940
param_node *curr = NULL;
69066941
zval **params_array = NULL;
@@ -6944,18 +6979,88 @@ PHP_FUNCTION( db2_execute_many )
69446979
}
69456980

69466981
if ( chaining_start ) {
6947-
if ( array_data_type[curr->param_num -1] != Z_TYPE_PP(data) ) {
6982+
if ( ( Z_TYPE_PP(data) != IS_NULL ) && ( array_data_type[curr->param_num -1] != Z_TYPE_PP(data) ) ) {
69486983
sprintf(error, "Value parameters array %d is not homogeneous with privious parameters array", i + 1);
69496984
_build_client_err_list(head_error_list, error);
69506985
err_count++;
69516986
break;
69526987
}
69536988
} else {
6954-
array_data_type[curr->param_num -1] = Z_TYPE_PP(data);
6989+
if ( Z_TYPE_PP(data) != IS_NULL ) {
6990+
array_data_type[curr->param_num -1] = Z_TYPE_PP(data);
6991+
j++;
6992+
} else {
6993+
int tmp_j = 0;
6994+
zend_hash_move_forward(Z_ARRVAL_P(params));
6995+
while ( zend_hash_get_current_data(Z_ARRVAL_P(params), (void **)&params_array) == SUCCESS ) {
6996+
zend_hash_internal_pointer_reset(Z_ARRVAL_PP(params_array));
6997+
for ( tmp_j = 0; tmp_j <= j; tmp_j++ ) {
6998+
zend_hash_move_forward(Z_ARRVAL_PP(params_array));
6999+
}
7000+
zend_hash_get_current_data(Z_ARRVAL_PP(params_array), (void**)&data);
7001+
if ( ( data != NULL ) && ( Z_TYPE_PP(data) != IS_NULL ) ) {
7002+
array_data_type[curr->param_num -1] = Z_TYPE_PP(data);
7003+
j++;
7004+
break;
7005+
} else {
7006+
zend_hash_move_forward(Z_ARRVAL_P(params));
7007+
continue;
7008+
}
7009+
}
7010+
if ( array_data_type[curr->param_num -1] == -1 ) {
7011+
array_data_type[curr->param_num -1] = IS_NULL;
7012+
}
7013+
zend_hash_internal_pointer_reset(Z_ARRVAL_P(params));
7014+
zend_hash_get_current_data(Z_ARRVAL_P(params), (void **)&params_array);
7015+
zend_hash_internal_pointer_reset(Z_ARRVAL_PP(params_array));
7016+
for ( tmp_j = 0; tmp_j < j; tmp_j++ ) {
7017+
zend_hash_move_forward(Z_ARRVAL_PP(params_array));
7018+
}
7019+
zend_hash_get_current_data(Z_ARRVAL_PP(params_array), (void**)&data);
7020+
}
69557021
}
69567022

69577023
curr->data_type = data_type[curr->param_num -1];
6958-
rc = _php_db2_bind_data(stmt_res, curr, data TSRMLS_CC);
7024+
if ( Z_TYPE_PP(data) != IS_NULL ) {
7025+
rc = _php_db2_bind_data(stmt_res, curr, data TSRMLS_CC);
7026+
} else {
7027+
SQLSMALLINT valueType = 0;
7028+
switch ( array_data_type[curr->param_num -1] ) {
7029+
case IS_BOOL:
7030+
case IS_LONG:
7031+
if ( curr->data_type == SQL_BIGINT ) {
7032+
valueType = SQL_C_CHAR;
7033+
} else {
7034+
valueType = SQL_C_LONG;
7035+
}
7036+
break;
7037+
case IS_DOUBLE:
7038+
valueType = SQL_C_DOUBLE;
7039+
break;
7040+
case IS_STRING:
7041+
switch ( curr->data_type ) {
7042+
case SQL_BLOB:
7043+
case SQL_BINARY:
7044+
case SQL_LONGVARBINARY:
7045+
case SQL_VARBINARY:
7046+
case SQL_XML:
7047+
valueType = SQL_C_BINARY;
7048+
break;
7049+
case SQL_CLOB:
7050+
case SQL_DBCLOB:
7051+
case SQL_VARCHAR:
7052+
case SQL_BIGINT:
7053+
default:
7054+
valueType = SQL_C_CHAR;
7055+
}
7056+
break;
7057+
case IS_NULL:
7058+
valueType = SQL_C_DEFAULT;
7059+
}
7060+
Z_LVAL_P(curr->value) = SQL_NULL_DATA;
7061+
Z_TYPE_P(curr->value) = IS_NULL;
7062+
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num, curr->param_type, valueType, curr->data_type, curr->param_size, curr->scale, &(curr->value), 0, (SQLLEN *)&((curr->value)->value.lval));
7063+
}
69597064
if ( rc == SQL_ERROR ) {
69607065
sprintf(error, "Binding Error1 : %s", IBM_DB2_G(__php_stmt_err_msg));
69617066
_build_client_err_list(head_error_list, error);
@@ -6965,12 +7070,20 @@ PHP_FUNCTION( db2_execute_many )
69657070
zend_hash_move_forward(Z_ARRVAL_PP(params_array));
69667071
curr = curr->next;
69677072
}
6968-
69697073
if ( !chaining_start && (error[0] == '\0' ) ) {
69707074
/* Set statement attribute SQL_ATTR_CHAINING_BEGIN */
69717075
rc = _ibm_db_chaining_flag(stmt_res, SQL_ATTR_CHAINING_BEGIN, NULL, 0 TSRMLS_CC);
69727076
chaining_start = 1;
69737077
if ( rc != SQL_SUCCESS ) {
7078+
error_msg_node *tmp_err_node;
7079+
while ( head_error_list != NULL ) {
7080+
tmp_err_node = head_error_list;
7081+
head_error_list = head_error_list->next;
7082+
efree(tmp_err_node);
7083+
}
7084+
_free_param_cache_list(stmt_res);
7085+
efree(array_data_type);
7086+
efree(data_type);
69747087
RETURN_FALSE;
69757088
}
69767089
}
@@ -6980,12 +7093,18 @@ PHP_FUNCTION( db2_execute_many )
69807093
}
69817094
zend_hash_move_forward(Z_ARRVAL_P(params));
69827095
}
7096+
} else {
7097+
RETURN_LONG(0);
69837098
}
7099+
_free_param_cache_list(stmt_res);
7100+
efree(array_data_type);
7101+
efree(data_type);
69847102

69857103
/* Set statement attribute SQL_ATTR_CHAINING_END */
69867104
rc = SQL_ERROR;
69877105
if ( chaining_start ) {
69887106
rc = _ibm_db_chaining_flag(stmt_res, SQL_ATTR_CHAINING_END, head_error_list->next, err_count TSRMLS_CC);
7107+
efree(head_error_list);
69897108
}
69907109

69917110
if ( rc != SQL_SUCCESS || err_count != 0 ) {

php_ibm_db2.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
$Id$
2424
*/
2525

26-
#define PHP_IBM_DB2_VERSION "1.9.4"
26+
#define PHP_IBM_DB2_VERSION "1.9.5"
2727

2828
#ifndef PHP_IBM_DB2_H
2929
#define PHP_IBM_DB2_H

0 commit comments

Comments
 (0)