Обсуждение: BUG #17152: ERROR: AddressSanitizer: SEGV on iso-8859-1 address

Поиск
Список
Период
Сортировка

BUG #17152: ERROR: AddressSanitizer: SEGV on iso-8859-1 address

От
PG Bug reporting form
Дата:
The following bug has been logged on the website:

Bug reference:      17152
Logged by:          Zhiyong Wu
Email address:      253540651@qq.com
PostgreSQL version: 14beta2
Operating system:   Linux version 5.13.0-1-MANJARO (builduser@LEGION)
Description:

PoC:
CREATE TEMP TABLE v0 ( v2 SMALLINT NOT NULL DEFAULT - - 90 , DATA TEXT , v1
REAL CONSTRAINT XMLFOREST NULL ) ;
 INSERT INTO v0 VALUES ( - - - - 0 , - - - - -1 ) , ( - - ( ( ( SELECT (
SELECT LEAST ( v1 ) x FROM v0 WHERE - - - 43 >= v1 ) FROM v0 AS v2 ( OVERLAY
, v2 , v1 ) ) ) UNION SELECT - - - 22 ) , - - - - - - 2147483647 ) , ( - - -
-128 , - - - -2147483648 ) , ( - - - - 36 , - - - - - - - -128 ) , ( - - - -
9 , - - - - - -128 ) ON CONFLICT DO NOTHING ;
 ;
 SELECT - - 11 + v2 AS x FROM v0 WHERE v2 = ( SELECT LEAST ( ( ( ( SELECT -
127 FROM ( SELECT 0 FROM ( VALUES ( - 16 ) , ( -2147483648 ) , ( - - - - -1
) ) v2 ( v2 ) GROUP BY ( + - - 72 ) / - - 18 ) AS SMALLINT ) ) UNION SELECT
MODE ( ) WITHIN GROUP ( ORDER BY v2 DESC ) FILTER ( WHERE MODE ( ) WITHIN
GROUP ( ORDER BY v1 = CASE WHEN v1 IS NULL THEN v1 ELSE - - 91 END DESC ) )
NULL ) ) FROM v0 ) ;
 COMMIT TRANSACTION ;
 DELETE FROM v0 WHERE v2 = - - - - - - 38 ;
 ;

Asan Report:
AddressSanitizer:DEADLYSIGNAL
=================================================================
==52==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc
0x000000c6428a bp 0x7ffcd1914310 sp 0x7ffcd1914040 T0)
==52==The signal is caused by a READ memory access.
==52==Hint: address points to the zero page.
    #0 0xc64289 in ExecInterpExpr
/home/postgres/postgres/bld/../src/backend/executor/execExprInterp.c:1532:20
    #1 0xce2658 in ExecEvalExprSwitchContext
/home/postgres/postgres/bld/../src/include/executor/executor.h:339:13
    #2 0xce2658 in advance_aggregates
/home/postgres/postgres/bld/../src/backend/executor/nodeAgg.c:842
    #3 0xce2658 in agg_retrieve_direct
/home/postgres/postgres/bld/../src/backend/executor/nodeAgg.c:2450
    #4 0xce2658 in ExecAgg
/home/postgres/postgres/bld/../src/backend/executor/nodeAgg.c:2175
    #5 0xd80380 in ExecProcNode
/home/postgres/postgres/bld/../src/include/executor/executor.h:257:9
    #6 0xd80380 in ExecSetParamPlan
/home/postgres/postgres/bld/../src/backend/executor/nodeSubplan.c:1118
    #7 0xc66f2b in ExecEvalParamExec
/home/postgres/postgres/bld/../src/backend/executor/execExprInterp.c:2414:3
    #8 0xc66f2b in ExecInterpExpr
/home/postgres/postgres/bld/../src/backend/executor/execExprInterp.c:1062
    #9 0xcb09f2 in ExecEvalExprSwitchContext
/home/postgres/postgres/bld/../src/include/executor/executor.h:339:13
    #10 0xcb09f2 in ExecQual
/home/postgres/postgres/bld/../src/include/executor/executor.h:408
    #11 0xcb09f2 in ExecScan
/home/postgres/postgres/bld/../src/backend/executor/execScan.c:227
    #12 0xc89648 in ExecProcNode
/home/postgres/postgres/bld/../src/include/executor/executor.h:257:9
    #13 0xc89648 in ExecutePlan
/home/postgres/postgres/bld/../src/backend/executor/execMain.c:1551
    #14 0xc89648 in standard_ExecutorRun
/home/postgres/postgres/bld/../src/backend/executor/execMain.c:361
    #15 0xc89061 in ExecutorRun
/home/postgres/postgres/bld/../src/backend/executor/execMain.c:305:3
    #16 0x13ca6af in PortalRunSelect
/home/postgres/postgres/bld/../src/backend/tcop/pquery.c:919:4
    #17 0x13c974d in PortalRun
/home/postgres/postgres/bld/../src/backend/tcop/pquery.c:763:18
    #18 0x13c52d5 in exec_simple_query
/home/postgres/postgres/bld/../src/backend/tcop/postgres.c:1214:10
    #19 0x13be613 in PostgresMain
/home/postgres/postgres/bld/../src/backend/tcop/postgres.c
    #20 0xe073fd in main
/home/postgres/postgres/bld/../src/backend/main/main.c:205:3
    #21 0x7f61369f6bf6 in __libc_start_main
/build/glibc-S9d2JN/glibc-2.27/csu/../csu/libc-start.c:310
    #22 0x499889 in _start (/usr/local/pgsql/bin/postgres+0x499889)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV
/home/postgres/postgres/bld/../src/backend/executor/execExprInterp.c:1532:20
in ExecInterpExpr
==52==ABORTING


Re: BUG #17152: ERROR: AddressSanitizer: SEGV on iso-8859-1 address

От
Bruce Momjian
Дата:
On Wed, Aug 18, 2021 at 02:56:00AM +0000, PG Bug reporting form wrote:
> The following bug has been logged on the website:
> 
> Bug reference:      17152
> Logged by:          Zhiyong Wu
> Email address:      253540651@qq.com
> PostgreSQL version: 14beta2
> Operating system:   Linux version 5.13.0-1-MANJARO (builduser@LEGION)
> Description:        
> 
> PoC:
> CREATE TEMP TABLE v0 ( v2 SMALLINT NOT NULL DEFAULT - - 90 , DATA TEXT , v1
> REAL CONSTRAINT XMLFOREST NULL ) ;
>  INSERT INTO v0 VALUES ( - - - - 0 , - - - - -1 ) , ( - - ( ( ( SELECT (
> SELECT LEAST ( v1 ) x FROM v0 WHERE - - - 43 >= v1 ) FROM v0 AS v2 ( OVERLAY
> , v2 , v1 ) ) ) UNION SELECT - - - 22 ) , - - - - - - 2147483647 ) , ( - - -
> -128 , - - - -2147483648 ) , ( - - - - 36 , - - - - - - - -128 ) , ( - - - -
> 9 , - - - - - -128 ) ON CONFLICT DO NOTHING ;
>  ;
>  SELECT - - 11 + v2 AS x FROM v0 WHERE v2 = ( SELECT LEAST ( ( ( ( SELECT -
> 127 FROM ( SELECT 0 FROM ( VALUES ( - 16 ) , ( -2147483648 ) , ( - - - - -1
> ) ) v2 ( v2 ) GROUP BY ( + - - 72 ) / - - 18 ) AS SMALLINT ) ) UNION SELECT
> MODE ( ) WITHIN GROUP ( ORDER BY v2 DESC ) FILTER ( WHERE MODE ( ) WITHIN
> GROUP ( ORDER BY v1 = CASE WHEN v1 IS NULL THEN v1 ELSE - - 91 END DESC ) )
> NULL ) ) FROM v0 ) ;
>  COMMIT TRANSACTION ;
>  DELETE FROM v0 WHERE v2 = - - - - - - 38 ;
>  ;

I can also confirm this failure on git master.

-- 
  Bruce Momjian  <bruce@momjian.us>        https://momjian.us
  EDB                                      https://enterprisedb.com

  If only the physical world exists, free will is an illusion.




Re: BUG #17152: ERROR: AddressSanitizer: SEGV on iso-8859-1 address

От
Tom Lane
Дата:
PG Bug reporting form <noreply@postgresql.org> writes:
> [ unreadable example ]

This can be boiled down to

CREATE TEMP TABLE v0 ( v2 int );
INSERT INTO v0 VALUES (1);

SELECT (
 SELECT
  MODE ( ) WITHIN GROUP ( ORDER BY v2 )
    FILTER ( WHERE MODE ( ) WITHIN GROUP ( ORDER BY v2 > 0 ) )
)
FROM v0;

It seems fairly clear to me that this ought to be rejected as invalid,
because we don't allow aggregates within the arguments of aggregates.
That does happen without the sub-select:

regression=# SELECT
regression-#   MODE ( ) WITHIN GROUP ( ORDER BY v2 )
regression-#     FILTER ( WHERE MODE ( ) WITHIN GROUP ( ORDER BY v2 > 0 ) )
regression-# FROM v0;
ERROR:  aggregate functions are not allowed in FILTER
LINE 3:     FILTER ( WHERE MODE ( ) WITHIN GROUP ( ORDER BY v2 > 0 )...
                           ^

So somehow the fact that outer references are involved is misleading that
error check.  I've not traced it further than that.

            regards, tom lane



Re: BUG #17152: ERROR: AddressSanitizer: SEGV on iso-8859-1 address

От
Tom Lane
Дата:
I wrote:
> So somehow the fact that outer references are involved is misleading that
> error check.  I've not traced it further than that.

Actually, it's simpler than that.  The patch that added FILTER
taught check_agg_arguments to check the FILTER argument like this:

    (void) expression_tree_walker((Node *) filter,
                                  check_agg_arguments_walker,
                                  (void *) &context);

which was a blind copy-and-paste of what it does for the "args"
list.  However, that coding for "args" includes an undocumented
optimization: "args" is a List, and check_agg_arguments_walker
doesn't care about Lists, so it's okay to recurse directly to
expression_tree_walker without invoking the walker on the top-level
List node.  This is completely NOT okay for the "filter" argument,
which could be directly a Var or Aggref.  Hence, the check completely
misses a top-level Var or Aggref in FILTER.

It would be enough to convert this one call to

    (void) check_agg_arguments_walker((Node *) filter, &context);

but in the attached I just converted all three of check_agg_arguments'
invocations to look that way.  The few nanoseconds shaved by the
other coding don't justify the risk of more copy-and-paste bugs.

An interesting nearby issue is that check_agglevels_and_constraints is
not really handling this correctly either.  It supposes that once it's
identified the agglevelsup for an Aggref node, it can look that many
levels up in the parse stack to see whether it's inside a relevant
FILTER expression.  This is wrong, because we've not yet determined
the semantic level of the surrounding aggregate if any, so we've
certainly not set p_expr_kind in the relevant outer pstate level.
That explains why you get

regression=# CREATE TEMP TABLE v0 ( v2 int );
CREATE TABLE
regression=#                                 
 SELECT
  MODE ( ) WITHIN GROUP ( ORDER BY v2 )
    FILTER ( WHERE MODE ( ) WITHIN GROUP ( ORDER BY v2 > 0 ) )
FROM v0;
ERROR:  aggregate functions are not allowed in FILTER
LINE 3:     FILTER ( WHERE MODE ( ) WITHIN GROUP ( ORDER BY v2 > 0 )...
                           ^

while (after this patch) the outer-level case gives

regression=# SELECT (                        
 SELECT
  MODE ( ) WITHIN GROUP ( ORDER BY v2 )
    FILTER ( WHERE MODE ( ) WITHIN GROUP ( ORDER BY v2 > 0 ) )
)
FROM v0;
ERROR:  aggregate function calls cannot be nested
LINE 4:     FILTER ( WHERE MODE ( ) WITHIN GROUP ( ORDER BY v2 > 0 )...
                           ^

check_agglevels_and_constraints doesn't complain at the lower
Aggref, so it's left to the upper one to whine.

I'm not too concerned about this cosmetic difference, but I wonder
if there are any cases where check_agglevels_and_constraints will
throw an error when it shouldn't.  Right offhand I can't see any,
but I may just lack imagination today.

Regardless of that, we certainly need the attached patch (and,
probably, some more regression tests).

            regards, tom lane

diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 24268eb502..7d829a05a9 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -627,13 +627,8 @@ check_agg_arguments(ParseState *pstate,
     context.min_agglevel = -1;
     context.sublevels_up = 0;
 
-    (void) expression_tree_walker((Node *) args,
-                                  check_agg_arguments_walker,
-                                  (void *) &context);
-
-    (void) expression_tree_walker((Node *) filter,
-                                  check_agg_arguments_walker,
-                                  (void *) &context);
+    (void) check_agg_arguments_walker((Node *) args, &context);
+    (void) check_agg_arguments_walker((Node *) filter, &context);
 
     /*
      * If we found no vars nor aggs at all, it's a level-zero aggregate;
@@ -680,9 +675,7 @@ check_agg_arguments(ParseState *pstate,
     {
         context.min_varlevel = -1;
         context.min_agglevel = -1;
-        (void) expression_tree_walker((Node *) directargs,
-                                      check_agg_arguments_walker,
-                                      (void *) &context);
+        (void) check_agg_arguments_walker((Node *) directargs, &context);
         if (context.min_varlevel >= 0 && context.min_varlevel < agglevel)
             ereport(ERROR,
                     (errcode(ERRCODE_GROUPING_ERROR),

Re: BUG #17152: ERROR: AddressSanitizer: SEGV on iso-8859-1 address

От
Tom Lane
Дата:
I wrote:
> I'm not too concerned about this cosmetic difference, but I wonder
> if there are any cases where check_agglevels_and_constraints will
> throw an error when it shouldn't.  Right offhand I can't see any,
> but I may just lack imagination today.

After further study I've more or less convinced myself that that
isn't an issue.  We may consider these cases:

1. We are parsing an aggregate call that's inside a FILTER clause
of the current query level.

1a. If we identify the aggregate as being of the current query level,
we will look at the current pstate, see p_expr_kind ==
EXPR_KIND_FILTER, and throw an error.  That is correct, because the
existence of this aggregate would constrain the surrounding aggregate
to also have the current query level as semantic level.

1b. If we identify the aggregate as being of some outer query level,
we will look at that outer pstate and probably not see
EXPR_KIND_FILTER (see #2 for the case where we do see that).  In
this case check_agglevels_and_constraints will not throw an error,
which is fine because we can't yet know the semantic levels of
surrounding aggregate(s).  It's left to check_agg_arguments, when
it checks the surrounding aggregate, to throw an error if needed.

2. We are parsing an aggregate call that's inside a FILTER clause
of some outer query level (i.e., the current aggregate is inside
a sub-SELECT inside FILTER).

2a. If we identify the aggregate as being of that same outer
query level, we will see EXPR_KIND_FILTER and throw error.
As in #1a, the error is correct since we'd ultimately assign
that outer aggregate to its own syntactic level.  (It clearly
can't have a semantic level lower than its syntactic level,
and again the existence of this aggregate within its arguments
prevents it from being assigned to any higher level.)

2b. If we identify the aggregate as being of some other query level
where there is not an open FILTER clause, we will not throw error.
As in #1b, it's up to check_agg_arguments to do so if needed.

So I think the patch I presented is sufficient.  I added some
test cases and pushed it.

Thanks for the report!

            regards, tom lane