From: <di...@us...> - 2015-01-05 16:08:23
|
Revision: 60472 http://sourceforge.net/p/firebird/code/60472 Author: dimitr Date: 2015-01-05 16:08:21 +0000 (Mon, 05 Jan 2015) Log Message: ----------- Slightly refactored the BLR parser routines to avoid crazy error reporting and protect against NULL pointer dereference. The error handling still sucks, but it was the case before me ;-) Modified Paths: -------------- firebird/trunk/src/remote/client/interface.cpp firebird/trunk/src/remote/parse_proto.h firebird/trunk/src/remote/parser.cpp firebird/trunk/src/remote/protocol.cpp Modified: firebird/trunk/src/remote/client/interface.cpp =================================================================== --- firebird/trunk/src/remote/client/interface.cpp 2015-01-03 09:11:24 UTC (rev 60471) +++ firebird/trunk/src/remote/client/interface.cpp 2015-01-05 16:08:21 UTC (rev 60472) @@ -1203,9 +1203,8 @@ RMessage* message = PARSE_messages(blr, blr_length); USHORT max_msg = 0; - for (next = message; next; next = next->msg_next) { + for (next = message; next; next = next->msg_next) max_msg = MAX(max_msg, next->msg_number); - } // Allocate request block Rrq* request = new Rrq(max_msg + 1); @@ -1737,14 +1736,7 @@ // Parse the blr describing the message, if there is any. if (in_blr_length) - { - RMessage* message = PARSE_messages(in_blr, in_blr_length); - if (message != (RMessage*) - 1) - { - statement->rsr_bind_format = (rem_fmt*) message->msg_address; - delete message; - } - } + statement->rsr_bind_format = PARSE_msg_format(in_blr, in_blr_length); // Parse the blr describing the output message. This is not the fetch // message! That comes later. @@ -1754,12 +1746,7 @@ if (!port->port_statement) port->port_statement = new Rsr; - RMessage* message = PARSE_messages(out_blr, out_blr_length); - if (message != (RMessage*) - 1) - { - port->port_statement->rsr_select_format = (rem_fmt*) message->msg_address; - delete message; - } + port->port_statement->rsr_select_format = PARSE_msg_format(out_blr, out_blr_length); if (!port->port_statement->rsr_buffer) { @@ -1932,14 +1919,7 @@ // Parse the blr describing the message, if there is any. if (in_blr_length) - { - RMessage* message = PARSE_messages(in_blr, in_blr_length); - if (message != (RMessage*) -1) - { - statement->rsr_bind_format = (rem_fmt*) message->msg_address; - delete message; - } - } + statement->rsr_bind_format = PARSE_msg_format(in_blr, in_blr_length); RMessage* message = NULL; if (!statement->rsr_buffer) @@ -2113,23 +2093,10 @@ if (in_msg_length || out_msg_length) { if (in_blr_length) - { - RMessage* message = PARSE_messages(in_blr, in_blr_length); - if (message != (RMessage*) - 1) - { - statement->rsr_bind_format = (rem_fmt*) message->msg_address; - delete message; - } - } + statement->rsr_bind_format = PARSE_msg_format(in_blr, in_blr_length); + if (out_blr_length) - { - RMessage* message = PARSE_messages(out_blr, out_blr_length); - if (message != (RMessage*) - 1) - { - statement->rsr_select_format = (rem_fmt*) message->msg_address; - delete message; - } - } + statement->rsr_select_format = PARSE_msg_format(out_blr, out_blr_length); } RMessage* message = 0; @@ -2830,14 +2797,9 @@ { delete statement->rsr_user_select_format; } - RMessage* message = PARSE_messages(blr, blr_length); - if (message != (RMessage*) - 1) - { - statement->rsr_user_select_format = (rem_fmt*) message->msg_address; - delete message; - } - else - statement->rsr_user_select_format = NULL; + + statement->rsr_user_select_format = PARSE_msg_format(blr, blr_length); + if (statement->rsr_flags.test(Rsr::FETCHED)) blr_length = 0; else @@ -5034,36 +4996,31 @@ procedure->rpr_out_format = NULL; RMessage* message = PARSE_messages(blr, blr_length); - if (message != (RMessage*) - 1) + while (message) { - while (message) + switch (message->msg_number) { - switch (message->msg_number) - { - case 0: - procedure->rpr_in_msg = message; - procedure->rpr_in_format = (rem_fmt*) message->msg_address; - message->msg_address = const_cast<unsigned char*>(in_msg); - message = message->msg_next; - procedure->rpr_in_msg->msg_next = NULL; - break; - case 1: - procedure->rpr_out_msg = message; - procedure->rpr_out_format = (rem_fmt*) message->msg_address; - message->msg_address = out_msg; - message = message->msg_next; - procedure->rpr_out_msg->msg_next = NULL; - break; - default: - RMessage* temp = message; - message = message->msg_next; - delete temp; - break; - } + case 0: + procedure->rpr_in_msg = message; + procedure->rpr_in_format = (rem_fmt*) message->msg_address; + message->msg_address = const_cast<unsigned char*>(in_msg); + message = message->msg_next; + procedure->rpr_in_msg->msg_next = NULL; + break; + case 1: + procedure->rpr_out_msg = message; + procedure->rpr_out_format = (rem_fmt*) message->msg_address; + message->msg_address = out_msg; + message = message->msg_next; + procedure->rpr_out_msg->msg_next = NULL; + break; + default: + RMessage* temp = message; + message = message->msg_next; + delete temp; + break; } } - //else - // error PACKET* packet = &rdb->rdb_packet; Modified: firebird/trunk/src/remote/parse_proto.h =================================================================== --- firebird/trunk/src/remote/parse_proto.h 2015-01-03 09:11:24 UTC (rev 60471) +++ firebird/trunk/src/remote/parse_proto.h 2015-01-05 16:08:21 UTC (rev 60472) @@ -25,5 +25,6 @@ #define REMOTE_PARSE_PROTO_H struct RMessage* PARSE_messages(const UCHAR*, size_t); +struct rem_fmt* PARSE_msg_format(const UCHAR*, size_t); #endif // REMOTE_PARSE_PROTO_H Modified: firebird/trunk/src/remote/parser.cpp =================================================================== --- firebird/trunk/src/remote/parser.cpp 2015-01-03 09:11:24 UTC (rev 60471) +++ firebird/trunk/src/remote/parser.cpp 2015-01-05 16:08:21 UTC (rev 60472) @@ -36,7 +36,7 @@ #endif -static RMessage* parse_error(rem_fmt* format, RMessage* mesage); +static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length); RMessage* PARSE_messages(const UCHAR* blr, size_t blr_length) @@ -49,252 +49,313 @@ * * Functional description * Parse the messages of a blr request. For each message, allocate - * a message (msg) and a format (fmt) block. Return the number of - * messages found. If an error occurs, return -1; + * a message (msg) and a format (fmt) block. * **************************************/ - if (blr_length < 2) - return (RMessage*) -1; - blr_length -= 2; + if (blr_length < 3) + return NULL; + blr_length -= 3; const SSHORT version = *blr++; if (version != blr_version4 && version != blr_version5) - return (RMessage*) -1; + return NULL; if (*blr++ != blr_begin) - return 0; + return NULL; RMessage* message = NULL; ULONG net_length = 0; + bool error = false; + while (*blr++ == blr_message) { - if (blr_length < 4) - return parse_error(0, message); - blr_length -= 4; + if (blr_length-- == 0) + { + error = true; + break; + } const USHORT msg_number = *blr++; - USHORT count = *blr++; - count += (*blr++) << 8; - rem_fmt* const format = new rem_fmt(count); -#ifdef DEBUG_REMOTE_MEMORY - printf("PARSE_messages allocate format %x\n", format); -#endif - ULONG offset = 0; - for (dsc* desc = format->fmt_desc.begin(); count; --count, ++desc) + + rem_fmt* const format = parse_format(blr, blr_length); + if (!format) { - if (blr_length-- == 0) - return parse_error(format, message); + error = true; + break; + } - USHORT align = 4; - switch (*blr++) - { - case blr_text: - if (blr_length < 2) - return parse_error(format, message); - blr_length -= 2; - desc->dsc_dtype = dtype_text; - desc->dsc_length = *blr++; - desc->dsc_length += (*blr++) << 8; - align = type_alignments[dtype_text]; - break; + RMessage* next = new RMessage(format->fmt_length); + next->msg_next = message; + message = next; + message->msg_address = reinterpret_cast<UCHAR*>(format); + message->msg_number = msg_number; - case blr_varying: - if (blr_length < 2) - return parse_error(format, message); - blr_length -= 2; - desc->dsc_dtype = dtype_varying; - desc->dsc_length = *blr++ + sizeof(SSHORT); - desc->dsc_length += (*blr++) << 8; - align = type_alignments[dtype_varying]; - break; + if (blr_length-- == 0) + { + error = true; + break; + } + } - case blr_cstring: - if (blr_length < 2) - return parse_error(format, message); - blr_length -= 2; - desc->dsc_dtype = dtype_cstring; - desc->dsc_length = *blr++; - desc->dsc_length += (*blr++) << 8; - align = type_alignments[dtype_cstring]; - break; + if (error) + { + for (RMessage* next = message; next; next = message) + { + message = message->msg_next; + delete next->msg_address; + delete next; + } - // Parse the tagged blr types correctly + return NULL; + } - case blr_text2: - if (blr_length < 4) - return parse_error(format, message); - blr_length -= 4; - desc->dsc_dtype = dtype_text; - desc->dsc_scale = *blr++; - desc->dsc_scale += (*blr++) << 8; - desc->dsc_length = *blr++; - desc->dsc_length += (*blr++) << 8; - align = type_alignments[dtype_text]; - break; + return message; +} - case blr_varying2: - if (blr_length < 4) - return parse_error(format, message); - blr_length -= 4; - desc->dsc_dtype = dtype_varying; - desc->dsc_scale = *blr++; - desc->dsc_scale += (*blr++) << 8; - desc->dsc_length = *blr++ + sizeof(SSHORT); - desc->dsc_length += (*blr++) << 8; - align = type_alignments[dtype_varying]; - break; - case blr_cstring2: - if (blr_length < 4) - return parse_error(format, message); - blr_length -= 4; - desc->dsc_dtype = dtype_cstring; - desc->dsc_scale = *blr++; - desc->dsc_scale += (*blr++) << 8; - desc->dsc_length = *blr++; - desc->dsc_length += (*blr++) << 8; - align = type_alignments[dtype_cstring]; - break; +rem_fmt* PARSE_msg_format(const UCHAR* blr, size_t blr_length) +{ +/************************************** + * + * P A R S E _ m s g _ f o r m a t + * + ************************************** + * + * Functional description + * Parse the message of a blr request and return its format. + * + **************************************/ - case blr_short: - if (blr_length-- == 0) - return parse_error(format, message); - desc->dsc_dtype = dtype_short; - desc->dsc_length = sizeof(SSHORT); - desc->dsc_scale = *blr++; - align = type_alignments[dtype_short]; - break; + if (blr_length < 4) + return NULL; + blr_length -= 4; - case blr_long: - if (blr_length-- == 0) - return parse_error(format, message); - desc->dsc_dtype = dtype_long; - desc->dsc_length = sizeof(SLONG); - desc->dsc_scale = *blr++; - align = type_alignments[dtype_long]; - break; + const SSHORT version = *blr++; + if (version != blr_version4 && version != blr_version5) + return NULL; - case blr_int64: - if (blr_length-- == 0) - return parse_error(format, message); - desc->dsc_dtype = dtype_int64; - desc->dsc_length = sizeof(SINT64); - desc->dsc_scale = *blr++; - align = type_alignments[dtype_int64]; - break; + if (*blr++ != blr_begin) + return NULL; - case blr_quad: - if (blr_length-- == 0) - return parse_error(format, message); - desc->dsc_dtype = dtype_quad; - desc->dsc_length = sizeof(SLONG) * 2; - desc->dsc_scale = *blr++; - align = type_alignments[dtype_quad]; - break; + if (*blr++ != blr_message) + return NULL; - case blr_float: - desc->dsc_dtype = dtype_real; - desc->dsc_length = sizeof(float); - align = type_alignments[dtype_real]; - break; + blr++; // skip message number - case blr_double: - case blr_d_float: - desc->dsc_dtype = dtype_double; - desc->dsc_length = sizeof(double); - align = type_alignments[dtype_double]; - break; + return parse_format(blr, blr_length); +} - // this case cannot occur as switch paramater is char and blr_blob - // is 261. blob_ids are actually passed around as blr_quad. +static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length) +{ + if (blr_length < 2) + return NULL; + blr_length -= 2; - //case blr_blob: - // desc->dsc_dtype = dtype_blob; - // desc->dsc_length = sizeof (SLONG) * 2; - // align = type_alignments [dtype_blob]; - // break; + USHORT count = *blr++; + count += (*blr++) << 8; - case blr_blob2: - { - if (blr_length < 4) - return parse_error(format, message); - blr_length -= 4; - desc->dsc_dtype = dtype_blob; - desc->dsc_length = sizeof(SLONG) * 2; - desc->dsc_sub_type = *blr++; - desc->dsc_sub_type += (*blr++) << 8; + Firebird::AutoPtr<rem_fmt> format(new rem_fmt(count)); - USHORT textType = *blr++; - textType += (*blr++) << 8; - desc->setTextType(textType); + ULONG net_length = 0; + ULONG offset = 0; - align = type_alignments[dtype_blob]; - } - break; + for (dsc* desc = format->fmt_desc.begin(); count; --count, ++desc) + { + if (blr_length-- == 0) + return NULL; - case blr_timestamp: - desc->dsc_dtype = dtype_timestamp; + USHORT align = 4; + switch (*blr++) + { + case blr_text: + if (blr_length < 2) + return NULL; + blr_length -= 2; + desc->dsc_dtype = dtype_text; + desc->dsc_length = *blr++; + desc->dsc_length += (*blr++) << 8; + align = type_alignments[dtype_text]; + break; + + case blr_varying: + if (blr_length < 2) + return NULL; + blr_length -= 2; + desc->dsc_dtype = dtype_varying; + desc->dsc_length = *blr++ + sizeof(SSHORT); + desc->dsc_length += (*blr++) << 8; + align = type_alignments[dtype_varying]; + break; + + case blr_cstring: + if (blr_length < 2) + return NULL; + blr_length -= 2; + desc->dsc_dtype = dtype_cstring; + desc->dsc_length = *blr++; + desc->dsc_length += (*blr++) << 8; + align = type_alignments[dtype_cstring]; + break; + + // Parse the tagged blr types correctly + + case blr_text2: + if (blr_length < 4) + return NULL; + blr_length -= 4; + desc->dsc_dtype = dtype_text; + desc->dsc_scale = *blr++; + desc->dsc_scale += (*blr++) << 8; + desc->dsc_length = *blr++; + desc->dsc_length += (*blr++) << 8; + align = type_alignments[dtype_text]; + break; + + case blr_varying2: + if (blr_length < 4) + return NULL; + blr_length -= 4; + desc->dsc_dtype = dtype_varying; + desc->dsc_scale = *blr++; + desc->dsc_scale += (*blr++) << 8; + desc->dsc_length = *blr++ + sizeof(SSHORT); + desc->dsc_length += (*blr++) << 8; + align = type_alignments[dtype_varying]; + break; + + case blr_cstring2: + if (blr_length < 4) + return NULL; + blr_length -= 4; + desc->dsc_dtype = dtype_cstring; + desc->dsc_scale = *blr++; + desc->dsc_scale += (*blr++) << 8; + desc->dsc_length = *blr++; + desc->dsc_length += (*blr++) << 8; + align = type_alignments[dtype_cstring]; + break; + + case blr_short: + if (blr_length-- == 0) + return NULL; + desc->dsc_dtype = dtype_short; + desc->dsc_length = sizeof(SSHORT); + desc->dsc_scale = *blr++; + align = type_alignments[dtype_short]; + break; + + case blr_long: + if (blr_length-- == 0) + return NULL; + desc->dsc_dtype = dtype_long; + desc->dsc_length = sizeof(SLONG); + desc->dsc_scale = *blr++; + align = type_alignments[dtype_long]; + break; + + case blr_int64: + if (blr_length-- == 0) + return NULL; + desc->dsc_dtype = dtype_int64; + desc->dsc_length = sizeof(SINT64); + desc->dsc_scale = *blr++; + align = type_alignments[dtype_int64]; + break; + + case blr_quad: + if (blr_length-- == 0) + return NULL; + desc->dsc_dtype = dtype_quad; + desc->dsc_length = sizeof(SLONG) * 2; + desc->dsc_scale = *blr++; + align = type_alignments[dtype_quad]; + break; + + case blr_float: + desc->dsc_dtype = dtype_real; + desc->dsc_length = sizeof(float); + align = type_alignments[dtype_real]; + break; + + case blr_double: + case blr_d_float: + desc->dsc_dtype = dtype_double; + desc->dsc_length = sizeof(double); + align = type_alignments[dtype_double]; + break; + + // this case cannot occur as switch paramater is char and blr_blob + // is 261. blob_ids are actually passed around as blr_quad. + + //case blr_blob: + // desc->dsc_dtype = dtype_blob; + // desc->dsc_length = sizeof (SLONG) * 2; + // align = type_alignments [dtype_blob]; + // break; + + case blr_blob2: + { + if (blr_length < 4) + return NULL; + blr_length -= 4; + desc->dsc_dtype = dtype_blob; desc->dsc_length = sizeof(SLONG) * 2; - align = type_alignments[dtype_timestamp]; - break; + desc->dsc_sub_type = *blr++; + desc->dsc_sub_type += (*blr++) << 8; - case blr_sql_date: - desc->dsc_dtype = dtype_sql_date; - desc->dsc_length = sizeof(SLONG); - align = type_alignments[dtype_sql_date]; - break; + USHORT textType = *blr++; + textType += (*blr++) << 8; + desc->setTextType(textType); - case blr_sql_time: - desc->dsc_dtype = dtype_sql_time; - desc->dsc_length = sizeof(ULONG); - align = type_alignments[dtype_sql_time]; - break; + align = type_alignments[dtype_blob]; + } + break; - case blr_bool: - desc->dsc_dtype = dtype_boolean; - desc->dsc_length = sizeof(UCHAR); - align = type_alignments[dtype_boolean]; - break; + case blr_timestamp: + desc->dsc_dtype = dtype_timestamp; + desc->dsc_length = sizeof(SLONG) * 2; + align = type_alignments[dtype_timestamp]; + break; - default: - fb_assert(FALSE); - return parse_error(format, message); - } - if (desc->dsc_dtype == dtype_varying) - net_length += 4 + ((desc->dsc_length - 2 + 3) & ~3); - else - net_length += (desc->dsc_length + 3) & ~3; - if (align > 1) - offset = FB_ALIGN(offset, align); - desc->dsc_address = (UCHAR*) (IPTR) offset; - offset += desc->dsc_length; + case blr_sql_date: + desc->dsc_dtype = dtype_sql_date; + desc->dsc_length = sizeof(SLONG); + align = type_alignments[dtype_sql_date]; + break; + + case blr_sql_time: + desc->dsc_dtype = dtype_sql_time; + desc->dsc_length = sizeof(ULONG); + align = type_alignments[dtype_sql_time]; + break; + + case blr_bool: + desc->dsc_dtype = dtype_boolean; + desc->dsc_length = sizeof(UCHAR); + align = type_alignments[dtype_boolean]; + break; + + default: + fb_assert(false); + return NULL; } - format->fmt_length = offset; - format->fmt_net_length = net_length; - RMessage* next = new RMessage(format->fmt_length); -#ifdef DEBUG_REMOTE_MEMORY - printf("PARSE_messages allocate message %x\n", next); -#endif - next->msg_next = message; - message = next; - message->msg_address = reinterpret_cast<UCHAR*>(format); - message->msg_number = msg_number; - } - return message; -} + if (desc->dsc_dtype == dtype_varying) + net_length += 4 + ((desc->dsc_length - 2 + 3) & ~3); + else + net_length += (desc->dsc_length + 3) & ~3; + if (align > 1) + offset = FB_ALIGN(offset, align); -static RMessage* parse_error(rem_fmt* format, RMessage* message) -{ - delete format; - for (RMessage* next = message; next; next = message) - { - message = message->msg_next; - delete next->msg_address; - delete next; + desc->dsc_address = (UCHAR*) (IPTR) offset; + offset += desc->dsc_length; } - return (RMessage*) -1; + + format->fmt_length = offset; + format->fmt_net_length = net_length; + + return format.release(); } Modified: firebird/trunk/src/remote/protocol.cpp =================================================================== --- firebird/trunk/src/remote/protocol.cpp 2015-01-03 09:11:24 UTC (rev 60471) +++ firebird/trunk/src/remote/protocol.cpp 2015-01-05 16:08:21 UTC (rev 60472) @@ -1544,14 +1544,7 @@ // setting up a format if (blr->cstr_length) - { - RMessage* temp_msg = (RMessage*) PARSE_messages(blr->cstr_address, blr->cstr_length); - if (temp_msg != (RMessage*) -1) - { - *fmt_ptr = (rem_fmt*) temp_msg->msg_address; - delete temp_msg; - } - } + *fmt_ptr = PARSE_msg_format(blr->cstr_address, blr->cstr_length); } // If we know the length of the message, make sure there is a buffer @@ -1781,38 +1774,33 @@ procedure->rpr_out_format = NULL; RMessage* message = PARSE_messages(blr->cstr_address, blr->cstr_length); - if (message != (RMessage*) -1) + while (message) { - while (message) + switch (message->msg_number) { - switch (message->msg_number) + case 0: + procedure->rpr_in_msg = message; + procedure->rpr_in_format = (rem_fmt*) message->msg_address; + message->msg_address = message->msg_buffer; + message = message->msg_next; + procedure->rpr_in_msg->msg_next = NULL; + break; + case 1: + procedure->rpr_out_msg = message; + procedure->rpr_out_format = (rem_fmt*) message->msg_address; + message->msg_address = message->msg_buffer; + message = message->msg_next; + procedure->rpr_out_msg->msg_next = NULL; + break; + default: { - case 0: - procedure->rpr_in_msg = message; - procedure->rpr_in_format = (rem_fmt*) message->msg_address; - message->msg_address = message->msg_buffer; + RMessage* temp = message; message = message->msg_next; - procedure->rpr_in_msg->msg_next = NULL; - break; - case 1: - procedure->rpr_out_msg = message; - procedure->rpr_out_format = (rem_fmt*) message->msg_address; - message->msg_address = message->msg_buffer; - message = message->msg_next; - procedure->rpr_out_msg->msg_next = NULL; - break; - default: - { - RMessage* temp = message; - message = message->msg_next; - delete temp; - } - break; + delete temp; } + break; } } - else - fb_assert(FALSE); return TRUE; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |