8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 18:43:02 +01:00

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 ;-)

This commit is contained in:
dimitr 2015-01-05 16:08:21 +00:00
parent bf8ed546e4
commit 5d3fd3dbe0
4 changed files with 333 additions and 326 deletions

View File

@ -1203,9 +1203,8 @@ Firebird::IRequest* Attachment::compileRequest(IStatus* status,
RMessage* message = PARSE_messages(blr, blr_length); RMessage* message = PARSE_messages(blr, blr_length);
USHORT max_msg = 0; 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); max_msg = MAX(max_msg, next->msg_number);
}
// Allocate request block // Allocate request block
Rrq* request = new Rrq(max_msg + 1); Rrq* request = new Rrq(max_msg + 1);
@ -1737,14 +1736,7 @@ Firebird::ITransaction* Statement::execute(IStatus* status, Firebird::ITransacti
// Parse the blr describing the message, if there is any. // Parse the blr describing the message, if there is any.
if (in_blr_length) if (in_blr_length)
{ statement->rsr_bind_format = PARSE_msg_format(in_blr, 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;
}
}
// Parse the blr describing the output message. This is not the fetch // Parse the blr describing the output message. This is not the fetch
// message! That comes later. // message! That comes later.
@ -1754,12 +1746,7 @@ Firebird::ITransaction* Statement::execute(IStatus* status, Firebird::ITransacti
if (!port->port_statement) if (!port->port_statement)
port->port_statement = new Rsr; port->port_statement = new Rsr;
RMessage* message = PARSE_messages(out_blr, out_blr_length); port->port_statement->rsr_select_format = PARSE_msg_format(out_blr, out_blr_length);
if (message != (RMessage*) - 1)
{
port->port_statement->rsr_select_format = (rem_fmt*) message->msg_address;
delete message;
}
if (!port->port_statement->rsr_buffer) if (!port->port_statement->rsr_buffer)
{ {
@ -1932,14 +1919,7 @@ ResultSet* Statement::openCursor(IStatus* status, Firebird::ITransaction* apiTra
// Parse the blr describing the message, if there is any. // Parse the blr describing the message, if there is any.
if (in_blr_length) if (in_blr_length)
{ statement->rsr_bind_format = PARSE_msg_format(in_blr, 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;
}
}
RMessage* message = NULL; RMessage* message = NULL;
if (!statement->rsr_buffer) if (!statement->rsr_buffer)
@ -2113,23 +2093,10 @@ ITransaction* Attachment::execute(IStatus* status, ITransaction* apiTra,
if (in_msg_length || out_msg_length) if (in_msg_length || out_msg_length)
{ {
if (in_blr_length) if (in_blr_length)
{ statement->rsr_bind_format = PARSE_msg_format(in_blr, 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;
}
}
if (out_blr_length) if (out_blr_length)
{ statement->rsr_select_format = PARSE_msg_format(out_blr, 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;
}
}
} }
RMessage* message = 0; RMessage* message = 0;
@ -2830,14 +2797,9 @@ int ResultSet::fetchNext(IStatus* status, void* buffer)
{ {
delete statement->rsr_user_select_format; delete statement->rsr_user_select_format;
} }
RMessage* message = PARSE_messages(blr, blr_length);
if (message != (RMessage*) - 1) statement->rsr_user_select_format = PARSE_msg_format(blr, blr_length);
{
statement->rsr_user_select_format = (rem_fmt*) message->msg_address;
delete message;
}
else
statement->rsr_user_select_format = NULL;
if (statement->rsr_flags.test(Rsr::FETCHED)) if (statement->rsr_flags.test(Rsr::FETCHED))
blr_length = 0; blr_length = 0;
else else
@ -5034,36 +4996,31 @@ void Attachment::transactRequest(IStatus* status, ITransaction* apiTra,
procedure->rpr_out_format = NULL; procedure->rpr_out_format = NULL;
RMessage* message = PARSE_messages(blr, blr_length); 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;
case 0: procedure->rpr_in_format = (rem_fmt*) message->msg_address;
procedure->rpr_in_msg = message; message->msg_address = const_cast<unsigned char*>(in_msg);
procedure->rpr_in_format = (rem_fmt*) message->msg_address; message = message->msg_next;
message->msg_address = const_cast<unsigned char*>(in_msg); procedure->rpr_in_msg->msg_next = NULL;
message = message->msg_next; break;
procedure->rpr_in_msg->msg_next = NULL; case 1:
break; procedure->rpr_out_msg = message;
case 1: procedure->rpr_out_format = (rem_fmt*) message->msg_address;
procedure->rpr_out_msg = message; message->msg_address = out_msg;
procedure->rpr_out_format = (rem_fmt*) message->msg_address; message = message->msg_next;
message->msg_address = out_msg; procedure->rpr_out_msg->msg_next = NULL;
message = message->msg_next; break;
procedure->rpr_out_msg->msg_next = NULL; default:
break; RMessage* temp = message;
default: message = message->msg_next;
RMessage* temp = message; delete temp;
message = message->msg_next; break;
delete temp;
break;
}
} }
} }
//else
// error
PACKET* packet = &rdb->rdb_packet; PACKET* packet = &rdb->rdb_packet;

View File

@ -25,5 +25,6 @@
#define REMOTE_PARSE_PROTO_H #define REMOTE_PARSE_PROTO_H
struct RMessage* PARSE_messages(const UCHAR*, size_t); struct RMessage* PARSE_messages(const UCHAR*, size_t);
struct rem_fmt* PARSE_msg_format(const UCHAR*, size_t);
#endif // REMOTE_PARSE_PROTO_H #endif // REMOTE_PARSE_PROTO_H

View File

@ -36,7 +36,7 @@
#endif #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) RMessage* PARSE_messages(const UCHAR* blr, size_t blr_length)
@ -49,252 +49,313 @@ RMessage* PARSE_messages(const UCHAR* blr, size_t blr_length)
* *
* Functional description * Functional description
* Parse the messages of a blr request. For each message, allocate * Parse the messages of a blr request. For each message, allocate
* a message (msg) and a format (fmt) block. Return the number of * a message (msg) and a format (fmt) block.
* messages found. If an error occurs, return -1;
* *
**************************************/ **************************************/
if (blr_length < 2) if (blr_length < 3)
return (RMessage*) -1; return NULL;
blr_length -= 2; blr_length -= 3;
const SSHORT version = *blr++; const SSHORT version = *blr++;
if (version != blr_version4 && version != blr_version5) if (version != blr_version4 && version != blr_version5)
return (RMessage*) -1; return NULL;
if (*blr++ != blr_begin) if (*blr++ != blr_begin)
return 0; return NULL;
RMessage* message = NULL; RMessage* message = NULL;
ULONG net_length = 0; ULONG net_length = 0;
bool error = false;
while (*blr++ == blr_message) while (*blr++ == blr_message)
{ {
if (blr_length < 4) if (blr_length-- == 0)
return parse_error(0, message); {
blr_length -= 4; error = true;
break;
}
const USHORT msg_number = *blr++; const USHORT msg_number = *blr++;
USHORT count = *blr++;
count += (*blr++) << 8; rem_fmt* const format = parse_format(blr, blr_length);
rem_fmt* const format = new rem_fmt(count); if (!format)
#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)
{ {
if (blr_length-- == 0) error = true;
return parse_error(format, message); 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;
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;
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;
// Parse the tagged blr types correctly
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;
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;
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;
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;
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;
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;
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 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;
USHORT textType = *blr++;
textType += (*blr++) << 8;
desc->setTextType(textType);
align = type_alignments[dtype_blob];
}
break;
case blr_timestamp:
desc->dsc_dtype = dtype_timestamp;
desc->dsc_length = sizeof(SLONG) * 2;
align = type_alignments[dtype_timestamp];
break;
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 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;
} }
format->fmt_length = offset;
format->fmt_net_length = net_length;
RMessage* next = new RMessage(format->fmt_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; next->msg_next = message;
message = next; message = next;
message->msg_address = reinterpret_cast<UCHAR*>(format); message->msg_address = reinterpret_cast<UCHAR*>(format);
message->msg_number = msg_number; message->msg_number = msg_number;
if (blr_length-- == 0)
{
error = true;
break;
}
}
if (error)
{
for (RMessage* next = message; next; next = message)
{
message = message->msg_next;
delete next->msg_address;
delete next;
}
return NULL;
} }
return message; return message;
} }
static RMessage* parse_error(rem_fmt* format, RMessage* message) rem_fmt* PARSE_msg_format(const UCHAR* blr, size_t blr_length)
{ {
delete format; /**************************************
for (RMessage* next = message; next; next = message) *
{ * P A R S E _ m s g _ f o r m a t
message = message->msg_next; *
delete next->msg_address; **************************************
delete next; *
} * Functional description
return (RMessage*) -1; * Parse the message of a blr request and return its format.
*
**************************************/
if (blr_length < 4)
return NULL;
blr_length -= 4;
const SSHORT version = *blr++;
if (version != blr_version4 && version != blr_version5)
return NULL;
if (*blr++ != blr_begin)
return NULL;
if (*blr++ != blr_message)
return NULL;
blr++; // skip message number
return parse_format(blr, blr_length);
}
static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
{
if (blr_length < 2)
return NULL;
blr_length -= 2;
USHORT count = *blr++;
count += (*blr++) << 8;
Firebird::AutoPtr<rem_fmt> format(new rem_fmt(count));
ULONG net_length = 0;
ULONG offset = 0;
for (dsc* desc = format->fmt_desc.begin(); count; --count, ++desc)
{
if (blr_length-- == 0)
return NULL;
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;
desc->dsc_sub_type = *blr++;
desc->dsc_sub_type += (*blr++) << 8;
USHORT textType = *blr++;
textType += (*blr++) << 8;
desc->setTextType(textType);
align = type_alignments[dtype_blob];
}
break;
case blr_timestamp:
desc->dsc_dtype = dtype_timestamp;
desc->dsc_length = sizeof(SLONG) * 2;
align = type_alignments[dtype_timestamp];
break;
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;
}
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;
}
format->fmt_length = offset;
format->fmt_net_length = net_length;
return format.release();
} }

View File

@ -1544,14 +1544,7 @@ static bool_t xdr_sql_blr(XDR* xdrs,
// setting up a format // setting up a format
if (blr->cstr_length) if (blr->cstr_length)
{ *fmt_ptr = PARSE_msg_format(blr->cstr_address, 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;
}
}
} }
// If we know the length of the message, make sure there is a buffer // If we know the length of the message, make sure there is a buffer
@ -1781,38 +1774,33 @@ static bool_t xdr_trrq_blr(XDR* xdrs, CSTRING* blr)
procedure->rpr_out_format = NULL; procedure->rpr_out_format = NULL;
RMessage* message = PARSE_messages(blr->cstr_address, blr->cstr_length); 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: RMessage* temp = message;
procedure->rpr_in_msg = message;
procedure->rpr_in_format = (rem_fmt*) message->msg_address;
message->msg_address = message->msg_buffer;
message = message->msg_next; message = message->msg_next;
procedure->rpr_in_msg->msg_next = NULL; delete temp;
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;
} }
break;
} }
} }
else
fb_assert(FALSE);
return TRUE; return TRUE;
} }