Skip to content

Commit 3010485

Browse files
committed
Handle OOM cases, in case of persistent connections this is real
and the Zend MM won't help.
1 parent e6ee260 commit 3010485

File tree

2 files changed

+75
-18
lines changed

2 files changed

+75
-18
lines changed

ext/mysqlnd/mysqlnd.c

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ PHPAPI const char * const mysqlnd_old_passwd = "mysqlnd cannot connect to MySQL
6161

6262
PHPAPI const char * const mysqlnd_server_gone = "MySQL server has gone away";
6363
PHPAPI const char * const mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now";
64+
PHPAPI const char * const mysqlnd_out_of_memory = "Out of memory";
6465

6566
PHPAPI MYSQLND_STATS *mysqlnd_global_stats = NULL;
6667
static zend_bool mysqlnd_library_initted = FALSE;
@@ -524,16 +525,25 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
524525

525526
transport_len = spprintf(&transport, 0, "tcp://%s:%d", host, port);
526527
}
528+
if (!transport) {
529+
goto err; /* OOM */
530+
}
527531
DBG_INF_FMT("transport=%s", transport);
528532
conn->scheme = mnd_pestrndup(transport, transport_len, conn->persistent);
529533
conn->scheme_len = transport_len;
530534
efree(transport); /* allocated by spprintf */
531535
transport = NULL;
536+
if (!conn->scheme) {
537+
goto err; /* OOM */
538+
}
532539
}
533540

534541
greet_packet = conn->protocol->m.get_greet_packet(conn->protocol, FALSE TSRMLS_CC);
535542
auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
536543
ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
544+
if (!greet_packet || !auth_packet || !ok_packet) {
545+
goto err; /* OOM */
546+
}
537547

538548
if (FAIL == conn->net->m.connect(conn->net, conn->scheme, conn->scheme_len, conn->persistent, &errstr, &errcode TSRMLS_CC)) {
539549
goto err;
@@ -602,6 +612,9 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
602612
auth_packet->client_flags= mysql_flags;
603613

604614
conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent);
615+
if (!conn->scramble) {
616+
goto err; /* OOM */
617+
}
605618
memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH);
606619

607620
if (!PACKET_WRITE(auth_packet, conn)) {
@@ -668,20 +681,35 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
668681
conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent);
669682
conn->connect_or_select_db_len = db_len;
670683

671-
if (!unix_socket) {
684+
if (!conn->user || !conn->passwd || !conn->connect_or_select_db) {
685+
goto err; /* OOM */
686+
}
672687

688+
if (!unix_socket) {
673689
conn->host = mnd_pestrdup(host, conn->persistent);
690+
if (!conn->host) {
691+
goto err; /* OOM */
692+
}
674693
conn->host_len = strlen(conn->host);
675694
{
676695
char *p;
677696
spprintf(&p, 0, "%s via TCP/IP", conn->host);
697+
if (!p) {
698+
goto err; /* OOM */
699+
}
678700
conn->host_info = mnd_pestrdup(p, conn->persistent);
679701
efree(p); /* allocated by spprintf */
702+
if (!conn->host_info) {
703+
goto err; /* OOM */
704+
}
680705
}
681706
} else {
682707
conn->unix_socket = mnd_pestrdup(socket, conn->persistent);
683-
conn->unix_socket_len = strlen(conn->unix_socket);
684708
conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent);
709+
if (!conn->unix_socket || !conn->host_info) {
710+
goto err; /* OOM */
711+
}
712+
conn->unix_socket_len = strlen(conn->unix_socket);
685713
}
686714
conn->client_flag = auth_packet->client_flags;
687715
conn->max_packet_size = auth_packet->max_packet_size;
@@ -720,14 +748,16 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
720748
unsigned int current_command = 0;
721749
for (; current_command < conn->options.num_commands; ++current_command) {
722750
const char * const command = conn->options.init_commands[current_command];
723-
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT);
724-
if (PASS != conn->m->query(conn, command, strlen(command) TSRMLS_CC)) {
725-
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT);
726-
goto err;
727-
}
728-
if (conn->last_query_type == QUERY_SELECT) {
729-
MYSQLND_RES * result = conn->m->use_result(conn TSRMLS_CC);
730-
result->m.free_result(result, TRUE TSRMLS_CC);
751+
if (command) {
752+
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT);
753+
if (PASS != conn->m->query(conn, command, strlen(command) TSRMLS_CC)) {
754+
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT);
755+
goto err;
756+
}
757+
if (conn->last_query_type == QUERY_SELECT) {
758+
MYSQLND_RES * result = conn->m->use_result(conn TSRMLS_CC);
759+
result->m.free_result(result, TRUE TSRMLS_CC);
760+
}
731761
}
732762
}
733763
}
@@ -782,6 +812,7 @@ PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn,
782812
if (!conn) {
783813
self_alloced = TRUE;
784814
if (!(conn = mysqlnd_init(FALSE))) {
815+
/* OOM */
785816
DBG_RETURN(NULL);
786817
}
787818
}
@@ -1110,7 +1141,8 @@ MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND * conn, const char *table, con
11101141
result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
11111142
result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
11121143
if (!result->unbuf) {
1113-
DBG_ERR("OOM");
1144+
/* OOM */
1145+
SET_OOM_ERROR(conn->error_info);
11141146
result->m.free_result(result, TRUE TSRMLS_CC);
11151147
DBG_RETURN(NULL);
11161148
}
@@ -1252,6 +1284,11 @@ MYSQLND_METHOD(mysqlnd_conn, select_db)(MYSQLND * const conn, const char * const
12521284
}
12531285
conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent);
12541286
conn->connect_or_select_db_len = db_len;
1287+
if (!conn->connect_or_select_db) {
1288+
/* OOM */
1289+
SET_OOM_ERROR(conn->error_info);
1290+
ret = FAIL;
1291+
}
12551292
}
12561293
DBG_RETURN(ret);
12571294
}
@@ -1860,10 +1897,16 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
18601897
}
18611898
}
18621899
if (ret == PASS) {
1863-
mnd_pefree(conn->user, conn->persistent);
1900+
if (conn->user) {
1901+
mnd_pefree(conn->user, conn->persistent);
1902+
}
18641903
conn->user = mnd_pestrndup(user, user_len, conn->persistent);
1865-
mnd_pefree(conn->passwd, conn->persistent);
1904+
1905+
if (conn->passwd) {
1906+
mnd_pefree(conn->passwd, conn->persistent);
1907+
}
18661908
conn->passwd = mnd_pestrdup(passwd, conn->persistent);
1909+
18671910
if (conn->last_message) {
18681911
mnd_pefree(conn->last_message, conn->persistent);
18691912
conn->last_message = NULL;
@@ -1896,6 +1939,7 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
18961939
const char * const value
18971940
TSRMLS_DC)
18981941
{
1942+
enum_func_status ret = PASS;
18991943
DBG_ENTER("mysqlnd_conn::set_client_option");
19001944
DBG_INF_FMT("conn=%llu option=%d", conn->thread_id, option);
19011945
switch (option) {
@@ -1915,7 +1959,7 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
19151959
case MYSQL_OPT_CONNECT_TIMEOUT:
19161960
case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
19171961
case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
1918-
conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC);
1962+
ret = conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC);
19191963
break;
19201964
#if PHP_MAJOR_VERSION >= 6
19211965
case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE:
@@ -1943,11 +1987,11 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
19431987
conn->options.init_commands = mnd_perealloc(conn->options.init_commands, sizeof(char *) * (conn->options.num_commands + 1),
19441988
conn->persistent);
19451989
if (!conn->options.init_commands) {
1946-
DBG_RETURN(FAIL);
1990+
goto oom;
19471991
}
19481992
conn->options.init_commands[conn->options.num_commands] = mnd_pestrdup(value, conn->persistent);
19491993
if (!conn->options.init_commands[conn->options.num_commands]) {
1950-
DBG_RETURN(FAIL);
1994+
goto oom;
19511995
}
19521996
++conn->options.num_commands;
19531997
break;
@@ -1966,6 +2010,9 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
19662010
conn->options.charset_name = NULL;
19672011
}
19682012
conn->options.charset_name = mnd_pestrdup(value, conn->persistent);
2013+
if (!conn->options.charset_name) {
2014+
goto oom;
2015+
}
19692016
DBG_INF_FMT("charset=%s", conn->options.charset_name);
19702017
break;
19712018
#ifdef WHEN_SUPPORTED_BY_MYSQLI
@@ -1990,9 +2037,12 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
19902037
/* not sure, todo ? */
19912038
#endif
19922039
default:
1993-
DBG_RETURN(FAIL);
2040+
ret = FAIL;
19942041
}
1995-
DBG_RETURN(PASS);
2042+
DBG_RETURN(ret);
2043+
oom:
2044+
SET_OOM_ERROR(conn->error_info);
2045+
DBG_RETURN(FAIL);
19962046
}
19972047
/* }}} */
19982048

@@ -2176,6 +2226,9 @@ PHPAPI MYSQLND * _mysqlnd_init(zend_bool persistent TSRMLS_DC)
21762226

21772227
DBG_ENTER("mysqlnd_init");
21782228
DBG_INF_FMT("persistent=%d", persistent);
2229+
if (!ret) {
2230+
DBG_RETURN(NULL);
2231+
}
21792232

21802233
ret->persistent = persistent;
21812234
ret->m = mysqlnd_conn_methods;

ext/mysqlnd/mysqlnd_priv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@
127127
strlcpy(error_info.error, (c), sizeof(error_info.error)); \
128128
}
129129

130+
#define SET_OOM_ERROR(error_info) SET_CLIENT_ERROR(error_info, CR_OUT_OF_MEMORY, UNKNOWN_SQLSTATE, mysqlnd_out_of_memory)
131+
132+
130133
#define SET_STMT_ERROR(stmt, a, b, c) SET_CLIENT_ERROR(stmt->error_info, a, b, c)
131134

132135

@@ -157,6 +160,7 @@ extern struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST +
157160
PHPAPI extern const char * const mysqlnd_old_passwd;
158161
PHPAPI extern const char * const mysqlnd_out_of_sync;
159162
PHPAPI extern const char * const mysqlnd_server_gone;
163+
PHPAPI extern const char * const mysqlnd_out_of_memory;
160164

161165
enum_func_status mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC);
162166

0 commit comments

Comments
 (0)