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:
parent
14f54d6405
commit
66527bca20
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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] =
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user