Skip to content

Commit 5eb6d46

Browse files
author
Arun Kuruvila
committed
Bug #17883203 : MYSQL EMBEDDED MYSQL_STMT_EXECUTE RETURN
"MALFORMED COMMUNICATION PACKET" ERROR Description :- C API, "mysql_stmt_execute" fails with an error, "malformed communication packet", even for a simple query when prepared statments are used with libmysqld. Analysis :- The packet size specified in "emb_stmt_execute()" [libmysqld/lib_sql.cc] and "execute() [libmysql/libmysql.c] should be consistent across libraries (libmysqld/libmysql) because "mysql_stmt_execute()" [sql/sql_prepare.cc ] is being called from both functions depending upon the libaries (libmysqld/libmysql) used. Currently the packet size used in "emb_stmt_execute() is 5 and in "execute()" is 9. When the C API, "mysql_stmt_execute", is executed from an application which is linked with libmysqld, it fails in the function "mysql_stmt_execute()" because of incorrect packet size. Another bug also exists in the "Protocol::net_store_data()" [libmysqld/lib_sql.cc] due to dereferencing an undefined "next_field" pointer which results in a segmentation fault. Fix:- (a)The packet size is made consistent across libmysqld and libmysql. (b) For the problem found internally: Functions "prepare_for_resend(), "net_store_data()" (with and without charset conversion) are defined seperately for Protocol_binary class in case of embedded library.
1 parent 51a6239 commit 5eb6d46

4 files changed

Lines changed: 152 additions & 10 deletions

File tree

libmysqld/lib_sql.cc

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) 2000
33
* SWsoft company
44
*
5-
* Modifications copyright (c) 2001, 2014. Oracle and/or its affiliates.
5+
* Modifications copyright (c) 2001, 2015. Oracle and/or its affiliates.
66
* All rights reserved.
77
*
88
* This material is provided "as is", with absolutely no warranty expressed
@@ -327,15 +327,26 @@ static my_bool emb_read_query_result(MYSQL *mysql)
327327
return 0;
328328
}
329329

330+
#define HEADER_SIZE 9
330331
static int emb_stmt_execute(MYSQL_STMT *stmt)
331332
{
332333
DBUG_ENTER("emb_stmt_execute");
333-
uchar header[5];
334+
/*
335+
Header size is made similar to non-embedded library.
336+
It should be consistent across embedded and non-embedded
337+
libraries.
338+
*/
339+
uchar header[HEADER_SIZE];
334340
THD *thd;
335341
my_bool res;
336342

337343
int4store(header, stmt->stmt_id);
338344
header[4]= (uchar) stmt->flags;
345+
/*
346+
Dummy value is stored in the last 4 bytes of the header
347+
to make it consistent with non-embedded library.
348+
*/
349+
int4store(header + 5, 1);
339350
thd= (THD*)stmt->mysql->thd;
340351
thd->client_param_count= stmt->param_count;
341352
thd->client_params= stmt->params;
@@ -1276,6 +1287,14 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err,
12761287
return FALSE;
12771288
}
12781289

1290+
void Protocol_binary::prepare_for_resend()
1291+
{
1292+
MYSQL_DATA *data= thd->cur_data;
1293+
next_mysql_field= data->embedded_info->fields_list;
1294+
packet->length(bit_fields + 1);
1295+
memset(const_cast<char*>(packet->ptr()), 0, 1 + bit_fields);
1296+
field_pos= 0;
1297+
}
12791298

12801299
void Protocol_text::prepare_for_resend()
12811300
{
@@ -1312,6 +1331,78 @@ bool Protocol_text::store_null()
13121331
return false;
13131332
}
13141333

1334+
bool Protocol_binary::net_store_data(const uchar *from, size_t length)
1335+
{
1336+
if (!thd->mysql) // bootstrap file handling
1337+
return 0;
1338+
1339+
ulong packet_length= packet->length();
1340+
/*
1341+
The +9 comes from that strings of length longer than 16M require
1342+
9 bytes to be stored (see net_store_length).
1343+
*/
1344+
if (packet_length + 9 + length > packet->alloced_length() &&
1345+
packet->realloc(packet_length + 9 + length))
1346+
return 1;
1347+
uchar *to= net_store_length((uchar*)packet->ptr() + packet_length, length);
1348+
memcpy(to, from, length);
1349+
packet->length((uint)(to + length - (uchar*)packet->ptr()));
1350+
if (next_mysql_field->max_length < length)
1351+
next_mysql_field->max_length= length;
1352+
++next_mysql_field;
1353+
return 0;
1354+
}
1355+
1356+
bool Protocol_binary::net_store_data(const uchar *from, size_t length,
1357+
const CHARSET_INFO *from_cs,
1358+
const CHARSET_INFO *to_cs)
1359+
{
1360+
uint dummy_errors;
1361+
/* Calculate maxumum possible result length */
1362+
uint conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen;
1363+
1364+
if (!thd->mysql) // bootstrap file handling
1365+
return 0;
1366+
1367+
if (conv_length > 250)
1368+
{
1369+
/*
1370+
For strings with conv_length greater than 250 bytes
1371+
we don't know how many bytes we will need to store length: one or two,
1372+
because we don't know result length until conversion is done.
1373+
For example, when converting from utf8 (mbmaxlen=3) to latin1,
1374+
conv_length=300 means that the result length can vary between 100 to 300.
1375+
length=100 needs one byte, length=300 needs to bytes.
1376+
1377+
Thus conversion directly to "packet" is not worthy.
1378+
Let's use "convert" as a temporary buffer.
1379+
*/
1380+
return (convert->copy((const char*)from, length, from_cs,
1381+
to_cs, &dummy_errors) ||
1382+
net_store_data((const uchar*)convert->ptr(), convert->length()));
1383+
}
1384+
1385+
ulong packet_length= packet->length();
1386+
ulong new_length= packet_length + conv_length + 1;
1387+
1388+
if (new_length > packet->alloced_length() && packet->realloc(new_length))
1389+
return 1;
1390+
1391+
char *length_pos= (char*) packet->ptr() + packet_length;
1392+
char *to= length_pos + 1;
1393+
1394+
to+= length= copy_and_convert(to, conv_length, to_cs,
1395+
(const char*)from, length, from_cs,
1396+
&dummy_errors);
1397+
1398+
net_store_length((uchar*)length_pos, to - length_pos - 1);
1399+
packet->length((uint)(to - packet->ptr()));
1400+
if (next_mysql_field->max_length < length)
1401+
next_mysql_field->max_length= length;
1402+
++next_mysql_field;
1403+
return 0;
1404+
}
1405+
13151406
bool Protocol::net_store_data(const uchar *from, size_t length)
13161407
{
13171408
char *field_buf;

sql/protocol.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -42,9 +42,6 @@ static bool write_eof_packet(THD *, NET *, uint, uint);
4242

4343
#ifndef EMBEDDED_LIBRARY
4444
bool Protocol::net_store_data(const uchar *from, size_t length)
45-
#else
46-
bool Protocol_binary::net_store_data(const uchar *from, size_t length)
47-
#endif
4845
{
4946
ulong packet_length=packet->length();
5047
/*
@@ -59,7 +56,7 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
5956
packet->length((uint) (to+length-(uchar*) packet->ptr()));
6057
return 0;
6158
}
62-
59+
#endif
6360

6461

6562

@@ -1244,12 +1241,14 @@ bool Protocol_binary::prepare_for_send(uint num_columns)
12441241
}
12451242

12461243

1244+
#ifndef EMBEDDED_LIBRARY
12471245
void Protocol_binary::prepare_for_resend()
12481246
{
12491247
packet->length(bit_fields+1);
12501248
memset(const_cast<char*>(packet->ptr()), 0, 1+bit_fields);
12511249
field_pos=0;
12521250
}
1251+
#endif
12531252

12541253

12551254
bool Protocol_binary::store(const char *from, size_t length,

sql/protocol.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef PROTOCOL_INCLUDED
22
#define PROTOCOL_INCLUDED
33

4-
/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
4+
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
55
66
This program is free software; you can redistribute it and/or modify
77
it under the terms of the GNU General Public License as published by
@@ -45,8 +45,9 @@ class Protocol
4545
MYSQL_FIELD *next_mysql_field;
4646
MEM_ROOT *alloc;
4747
#endif
48-
bool net_store_data(const uchar *from, size_t length,
49-
const CHARSET_INFO *fromcs, const CHARSET_INFO *tocs);
48+
virtual bool net_store_data(const uchar *from, size_t length,
49+
const CHARSET_INFO *fromcs,
50+
const CHARSET_INFO *tocs);
5051
bool store_string_aux(const char *from, size_t length,
5152
const CHARSET_INFO *fromcs, const CHARSET_INFO *tocs);
5253

@@ -178,6 +179,9 @@ class Protocol_binary :public Protocol
178179
#ifdef EMBEDDED_LIBRARY
179180
virtual bool write();
180181
bool net_store_data(const uchar *from, size_t length);
182+
bool net_store_data(const uchar *from, size_t length,
183+
const CHARSET_INFO *fromcs,
184+
const CHARSET_INFO *tocs);
181185
#endif
182186
virtual bool store_null();
183187
virtual bool store_tiny(longlong from);

tests/mysql_client_test.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19441,6 +19441,53 @@ static void test_bug20810928()
1944119441
}
1944219442

1944319443

19444+
/*
19445+
BUG#17883203: MYSQL EMBEDDED MYSQL_STMT_EXECUTE RETURN
19446+
"MALFORMED COMMUNICATION PACKET" ERROR
19447+
*/
19448+
#define BUG17883203_STRING_SIZE 50
19449+
19450+
static void test_bug17883203()
19451+
{
19452+
MYSQL_STMT *stmt;
19453+
MYSQL_BIND bind;
19454+
char str_data[BUG17883203_STRING_SIZE];
19455+
my_bool is_null;
19456+
my_bool error;
19457+
unsigned long length;
19458+
const char stmt_text[] ="SELECT VERSION()";
19459+
int rc;
19460+
19461+
myheader("test_bug17883203");
19462+
19463+
stmt = mysql_stmt_init(mysql);
19464+
check_stmt(stmt);
19465+
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
19466+
check_execute(stmt, rc);
19467+
rc= mysql_stmt_execute(stmt);
19468+
check_execute(stmt, rc);
19469+
memset(&bind, 0, sizeof(bind));
19470+
19471+
bind.buffer_type= MYSQL_TYPE_STRING;
19472+
bind.buffer= (char *)str_data;
19473+
bind.buffer_length= BUG17883203_STRING_SIZE;
19474+
bind.is_null= &is_null;
19475+
bind.length= &length;
19476+
bind.error= &error;
19477+
19478+
rc= mysql_stmt_bind_result(stmt, &bind);
19479+
check_execute(stmt, rc);
19480+
rc= mysql_stmt_fetch(stmt);
19481+
check_execute(stmt, rc);
19482+
19483+
if (!opt_silent)
19484+
{
19485+
fprintf(stdout, "\n Version: %s", str_data);
19486+
}
19487+
mysql_stmt_close(stmt);
19488+
}
19489+
19490+
1944419491
static struct my_tests_st my_tests[]= {
1944519492
{ "disable_query_logs", disable_query_logs },
1944619493
{ "test_view_sp_list_fields", test_view_sp_list_fields },
@@ -19717,6 +19764,7 @@ static struct my_tests_st my_tests[]= {
1971719764
#endif
1971819765
{ "test_bug17512527", test_bug17512527},
1971919766
{ "test_bug20810928", test_bug20810928 },
19767+
{ "test_bug17883203", test_bug17883203 },
1972019768
{ 0, 0 }
1972119769
};
1972219770

0 commit comments

Comments
 (0)