8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 23:23:04 +01:00

Fix optimizer crasher with too many streams (UCHAR overflow/wrap-around).

This commit is contained in:
tamlin 2003-02-27 16:28:53 +00:00
parent 14f54d6405
commit 66527bca20
4 changed files with 73 additions and 32 deletions

View File

@ -2636,7 +2636,9 @@ static JRD_NOD copy(
node->nod_type = input->nod_type;
node->nod_count = 0;
stream = (USHORT) input->nod_arg[e_agg_stream];
assert(stream <= MAX_STREAMS);
new_stream = (*csb)->csb_n_stream++;
assert(new_stream <= MAX_STREAMS);
node->nod_arg[e_agg_stream] = (JRD_NOD) (SLONG) new_stream;
/* TMN: Here we should really have the following assert */
/* assert(new_stream <= MAX_UCHAR); */
@ -3205,6 +3207,7 @@ static JRD_NOD pass1(
break;
case nod_aggregate:
assert((int)node->nod_arg[e_agg_stream] <= MAX_STREAMS);
(*csb)->csb_rpt[(USHORT) node->nod_arg[e_agg_stream]].csb_flags |=
csb_no_dbkey;
ignore_dbkey(tdbb, *csb, (RSE) node->nod_arg[e_agg_rse], view);
@ -3281,8 +3284,9 @@ static JRD_NOD pass1(
ptr = node->nod_arg;
for (end = ptr + node->nod_count; ptr < end; ptr++)
for (end = ptr + node->nod_count; ptr < end; ptr++) {
*ptr = pass1(tdbb, csb, *ptr, view, view_stream, validate_expr);
}
/* perform any post-processing here */
@ -3596,9 +3600,11 @@ static void pass1_modify(TDBB tdbb, CSB * csb, JRD_NOD node)
}
static RSE pass1_rse(
TDBB tdbb,
CSB * csb, RSE rse, JRD_REL view, USHORT view_stream)
static RSE pass1_rse(TDBB tdbb,
CSB* csb,
RSE rse,
JRD_REL view,
USHORT view_stream)
{
/**************************************
*
@ -3649,9 +3655,11 @@ static RSE pass1_rse(
/* Zip thru rse expanding views and inner joins */
for (arg = rse->rse_relation, end = arg + rse->rse_count; arg < end;
arg++) pass1_source(tdbb, csb, rse, *arg, &boolean, &stack, view,
view_stream);
for (arg = rse->rse_relation, end = arg + rse->rse_count; arg < end; arg++)
{
pass1_source(tdbb, csb, rse, *arg, &boolean, &stack, view,
view_stream);
}
/* Now, rebuild the rse block. If possible, re-use the old block,
otherwise allocate a new one. */
@ -3733,13 +3741,14 @@ static RSE pass1_rse(
}
static void pass1_source(
TDBB tdbb,
CSB * csb,
RSE rse,
JRD_NOD source,
JRD_NOD * boolean,
LLS * stack, JRD_REL parent_view, USHORT view_stream)
static void pass1_source(TDBB tdbb,
CSB* csb,
RSE rse,
JRD_NOD source,
JRD_NOD* boolean,
LLS* stack,
JRD_REL parent_view,
USHORT view_stream)
{
/**************************************
*
@ -3775,15 +3784,14 @@ static void pass1_source(
/* in the case of an rse, it is possible that a new rse will be generated,
so wait to process the source before we push it on the stack (bug 8039) */
if (source->nod_type == nod_rse) {
RSE sub_rse;
if (source->nod_type == nod_rse)
{
/* The addition of the JOIN syntax for specifying inner joins causes an
rse tree to be generated, which is undesirable in the simplest case
where we are just trying to inner join more than 2 streams. If possible,
try to flatten the tree out before we go any further. */
sub_rse = (RSE) source;
RSE sub_rse = (RSE) source;
if (!rse->rse_jointype && !sub_rse->rse_jointype
&& !sub_rse->rse_sorted && !sub_rse->rse_projection
&& !sub_rse->rse_first && !sub_rse->rse_plan) {
@ -3849,6 +3857,7 @@ static void pass1_source(
/* Special case group-by/global aggregates */
if (source->nod_type == nod_aggregate) {
assert((int)source->nod_arg[e_agg_stream] <= MAX_STREAMS);
pass1(tdbb, csb, source, parent_view, view_stream, FALSE);
return;
}
@ -4650,6 +4659,7 @@ static JRD_NOD pass2(TDBB tdbb, CSB csb, JRD_NOD node, JRD_NOD parent)
pass2(tdbb, csb, node->nod_arg[e_agg_map], node);
pass2(tdbb, csb, node->nod_arg[e_agg_group], node);
stream = (USHORT) node->nod_arg[e_agg_stream];
assert(stream <= MAX_STREAMS);
process_map(tdbb, csb, node->nod_arg[e_agg_map],
&csb->csb_rpt[stream].csb_format);
break;
@ -4767,6 +4777,7 @@ static void pass2_rse(TDBB tdbb, CSB csb, RSE rse)
}
else if (node->nod_type == nod_aggregate) {
USHORT stream = (USHORT) node->nod_arg[e_agg_stream];
assert(stream <= MAX_STREAMS);
csb->csb_rpt[stream].csb_flags |= csb_active;
pass2(tdbb, csb, node, (JRD_NOD) rse);
}
@ -5173,6 +5184,7 @@ static RSB post_rse(TDBB tdbb, CSB csb, RSE rse)
}
else if (node->nod_type == nod_aggregate) {
USHORT stream = (USHORT) node->nod_arg[e_agg_stream];
assert(stream <= MAX_STREAMS);
csb->csb_rpt[stream].csb_flags &= ~csb_active;
}
}

View File

@ -380,8 +380,11 @@ RSB OPT_compile(TDBB tdbb,
/* find the stream number and place it at the end of the beds array
(if this is really a stream and not another rse) */
if (node->nod_type != nod_rse) {
if (node->nod_type != nod_rse)
{
stream = (USHORT) node->nod_arg[STREAM_INDEX(node)];
assert(stream <= MAX_UCHAR);
assert(beds[0] < MAX_STREAMS && beds[0] < MAX_UCHAR);
beds[++beds[0]] = (UCHAR) stream;
}
@ -397,16 +400,21 @@ RSB OPT_compile(TDBB tdbb,
rsb =
gen_union(tdbb, opt_, node, key_streams + i + 1,
(USHORT) (key_streams[0] - i));
assert(local_streams[0] < MAX_STREAMS && local_streams[0] < MAX_UCHAR);
local_streams[++local_streams[0]] =
(UCHAR) node->nod_arg[e_uni_stream];
}
else if (node->nod_type == nod_aggregate) {
assert((int)node->nod_arg[e_agg_stream] <= MAX_STREAMS);
assert((int)node->nod_arg[e_agg_stream] <= MAX_UCHAR);
rsb = gen_aggregate(tdbb, opt_, node);
assert(local_streams[0] < MAX_STREAMS && local_streams[0] < MAX_UCHAR);
local_streams[++local_streams[0]] =
(UCHAR) node->nod_arg[e_agg_stream];
}
else if (node->nod_type == nod_procedure) {
rsb = gen_procedure(tdbb, opt_, node);
assert(local_streams[0] < MAX_STREAMS && local_streams[0] < MAX_UCHAR);
local_streams[++local_streams[0]] =
(UCHAR) node->nod_arg[e_prc_stream];
}
@ -473,11 +481,12 @@ RSB OPT_compile(TDBB tdbb,
// TMN: Is the intention really to allow streams[0] to overflow?
// I must assume that is indeed not the intention (not to mention
// it would make code later on fail), so I added the following assert.
assert(streams[0] < MAX_UCHAR);
assert(streams[0] < MAX_STREAMS && streams[0] < MAX_UCHAR);
++streams[0];
*p++ = (UCHAR) stream;
assert(outer_streams[0] < MAX_STREAMS && outer_streams[0] < MAX_UCHAR);
outer_streams[++outer_streams[0]] = stream;
/* if we have seen any booleans or sort fields, we may be able to
@ -1814,6 +1823,7 @@ static void compute_dbkey_streams(CSB csb, JRD_NOD node, UCHAR * streams)
DEV_BLKCHK(node, type_nod);
if (node->nod_type == nod_relation) {
assert(streams[0] < MAX_STREAMS && streams[0] < MAX_UCHAR);
streams[++streams[0]] = (UCHAR) node->nod_arg[e_rel_stream];
}
else if (node->nod_type == nod_union) {
@ -1853,6 +1863,7 @@ static void compute_rse_streams(CSB csb, RSE rse, UCHAR * streams)
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end; ptr++) {
node = *ptr;
if (node->nod_type != nod_rse) {
assert(streams[0] < MAX_STREAMS && streams[0] < MAX_UCHAR);
streams[++streams[0]] = (UCHAR) node->nod_arg[STREAM_INDEX(node)];
}
else {
@ -3280,6 +3291,8 @@ static RSB gen_aggregate(TDBB tdbb, OPT opt, JRD_NOD node)
rsb = FB_NEW_RPT(*tdbb->tdbb_default, 1) Rsb();
rsb->rsb_type = rsb_aggregate;
assert((int)node->nod_arg[e_agg_stream] <= MAX_STREAMS);
assert((int)node->nod_arg[e_agg_stream] <= MAX_UCHAR);
rsb->rsb_stream = (UCHAR) node->nod_arg[e_agg_stream];
rsb->rsb_format = csb->csb_rpt[rsb->rsb_stream].csb_format;
rsb->rsb_next = OPT_compile(tdbb, csb, rse, NULL);

View File

@ -34,7 +34,7 @@
*
*/
/*
$Id: par.cpp,v 1.36 2003-02-19 15:25:26 dimitr Exp $
$Id: par.cpp,v 1.37 2003-02-27 16:28:52 tamlin Exp $
*/
#include "firebird.h"
@ -48,6 +48,7 @@ $Id: par.cpp,v 1.36 2003-02-19 15:25:26 dimitr Exp $
#include "../jrd/align.h"
#include "../jrd/exe.h"
#include "../jrd/lls.h"
#include "../jrd/rse.h" // for MAX_STREAMS
#include "../jrd/scl.h"
#include "../jrd/all.h"
@ -924,7 +925,7 @@ static XCP par_conditions(TDBB tdbb, CSB * csb)
}
static SSHORT par_context(CSB * csb, SSHORT * context_ptr)
static SSHORT par_context(CSB* csb, SSHORT* context_ptr)
{
/**************************************
*
@ -938,13 +939,19 @@ static SSHORT par_context(CSB * csb, SSHORT * context_ptr)
* scratch block.
*
**************************************/
SSHORT context, stream;
csb_repeat *tail;
stream = (*csb)->csb_n_stream++;
context = (unsigned int) BLR_BYTE;
SSHORT stream = (*csb)->csb_n_stream++;
if (stream > MAX_STREAMS) {
// TMN: Someone please review this to verify that
// gds_too_many_contexts is indeed the right error to report.
// "Too many streams" would probably be more correct, but we
/// don't have such an error (yet).
error(*csb, gds_too_many_contexts, 0);
}
assert(stream <= MAX_STREAMS);
SSHORT context = (unsigned int) BLR_BYTE;
CMP_csb_element(csb, stream);
tail = CMP_csb_element(csb, context);
csb_repeat* tail = CMP_csb_element(csb, context);
if (tail->csb_flags & csb_used)
error(*csb, gds_ctxinuse, 0);
@ -959,10 +966,11 @@ static SSHORT par_context(CSB * csb, SSHORT * context_ptr)
}
static void par_dependency(
TDBB tdbb,
CSB * csb,
SSHORT stream, SSHORT id, TEXT * field_name)
static void par_dependency(TDBB tdbb,
CSB* csb,
SSHORT stream,
SSHORT id,
TEXT* field_name)
{
/**************************************
*
@ -2001,6 +2009,7 @@ static JRD_NOD par_relation(
if (parse_context) {
stream = par_context(csb, &context);
assert(stream <= MAX_STREAMS);
node->nod_arg[e_rel_stream] = (JRD_NOD) (SLONG) stream;
node->nod_arg[e_rel_context] = (JRD_NOD) (SLONG) context;
@ -2484,6 +2493,7 @@ static JRD_NOD parse(TDBB tdbb, CSB * csb, USHORT expected)
case blr_aggregate:
node->nod_arg[e_agg_stream] = (JRD_NOD) (SLONG) par_context(csb, 0);
assert((int)node->nod_arg[e_agg_stream] <= MAX_STREAMS);
node->nod_arg[e_agg_rse] = parse(tdbb, csb, TYPE_RSE);
node->nod_arg[e_agg_group] = parse(tdbb, csb, OTHER);
node->nod_arg[e_agg_map] =

View File

@ -309,7 +309,13 @@ typedef srl *SRL;
#define MAX_INDICES MAX_OPT_ITEMS
#define OPT_BITS (MAX_OPT_ITEMS / 32)
#define MAX_STREAMS 256
// Note that MAX_STREAMS currently MUST be <= MAX_UCHAR.
// Here we should really have a compile-time assert, since this hard-coded
// limit is NOT negotiable so long as we use an array of UCHAR, where index 0
// tells how many streams are in the array (and the streams themselves are
// identified by a UCHAR).
#define MAX_STREAMS 255
/* General optimizer block */
class Opt : public pool_alloc<type_opt>