Re: server crash: displaying sqlerrm in exception block - Mailing list pgsql-bugs

From Tom Lane
Subject Re: server crash: displaying sqlerrm in exception block
Date
Msg-id 27059.1170897457@sss.pgh.pa.us
Whole thread Raw
In response to server crash: displaying sqlerrm in exception block  ("Asif Ali" <asifalirehman@gmail.com>)
List pgsql-bugs
"Asif Ali" <asifalirehman@gmail.com> writes:
> I have compiled postgres 8.2.1 with gcc 4.1. and when executed this function
> it crashes the server.

The attached patch (against HEAD) fixes your test case, but please see
whether it fixes your original problem; I'm not 100% confident in it
yet.  There seem to be two different bugs here...

            regards, tom lane

? libplpgsql.sl.1
Index: gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v
retrieving revision 1.97
diff -c -r1.97 gram.y
*** gram.y    1 Feb 2007 19:10:29 -0000    1.97
--- gram.y    8 Feb 2007 01:06:24 -0000
***************
*** 272,278 ****
                          $$.label      = $1;
                          $$.n_initvars = 0;
                          $$.initvarnos = NULL;
-                         plpgsql_add_initdatums(NULL);
                      }
                  | opt_block_label decl_start
                      {
--- 272,277 ----
***************
*** 280,286 ****
                          $$.label      = $1;
                          $$.n_initvars = 0;
                          $$.initvarnos = NULL;
-                         plpgsql_add_initdatums(NULL);
                      }
                  | opt_block_label decl_start decl_stmts
                      {
--- 279,284 ----
***************
*** 289,300 ****
--- 287,302 ----
                              $$.label = $3;
                          else
                              $$.label = $1;
+                         /* Remember variables declared in decl_stmts */
                          $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
                      }
                  ;

  decl_start        : K_DECLARE
                      {
+                         /* Forget any variables created before block */
+                         plpgsql_add_initdatums(NULL);
+                         /* Make variable names be local to block */
                          plpgsql_ns_setlocal(true);
                      }
                  ;
***************
*** 990,998 ****
                                                                                    -1),
                                                             true);

-                                 /* put the for-variable into the local block */
-                                 plpgsql_add_initdatums(NULL);
-
                                  new = palloc0(sizeof(PLpgSQL_stmt_fori));
                                  new->cmd_type = PLPGSQL_STMT_FORI;
                                  new->lineno   = $1;
--- 992,997 ----
Index: pl_comp.c
===================================================================
RCS file: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v
retrieving revision 1.111
diff -c -r1.111 pl_comp.c
*** pl_comp.c    1 Feb 2007 19:10:29 -0000    1.111
--- pl_comp.c    8 Feb 2007 01:06:24 -0000
***************
*** 667,677 ****
      function->found_varno = var->dno;

      /*
-      * Forget about the above created variables
-      */
-     plpgsql_add_initdatums(NULL);
-
-     /*
       * Now parse the function's text
       */
      parse_rc = plpgsql_yyparse();
--- 667,672 ----
***************
*** 1893,1903 ****


  /* ----------
!  * plpgsql_add_initdatums        Put all datum entries created
!  *                    since the last call into the
!  *                    finishing code block so the
!  *                    block knows which variables to
!  *                    reinitialize when entered.
   * ----------
   */
  int
--- 1888,1904 ----


  /* ----------
!  * plpgsql_add_initdatums        Make an array of the datum numbers of
!  *                    all the simple VAR datums created since the last call
!  *                    to this function.
!  *
!  * If varnos is NULL, we just forget any datum entries created since the
!  * last call.
!  *
!  * This is used around a DECLARE section to create a list of the VARs
!  * that have to be initialized at block entry.  Note that VARs can also
!  * be created elsewhere than DECLARE, eg by a FOR-loop, but it is then
!  * the responsibility of special-purpose code to initialize them.
   * ----------
   */
  int
Index: pl_exec.c
===================================================================
RCS file: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v
retrieving revision 1.187
diff -c -r1.187 pl_exec.c
*** pl_exec.c    1 Feb 2007 19:22:07 -0000    1.187
--- pl_exec.c    8 Feb 2007 01:06:25 -0000
***************
*** 885,927 ****
                  {
                      PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);

                      free_var(var);
!                     if (!var->isconst || var->isnull)
                      {
!                         if (var->default_val == NULL)
                          {
!                             /* Initially it contains a NULL */
!                             var->value = (Datum) 0;
!                             var->isnull = true;
!                             /*
!                              * If needed, give the datatype a chance to reject
!                              * NULLs, by assigning a NULL to the variable.
!                              * We claim the value is of type UNKNOWN, not the
!                              * var's datatype, else coercion will be skipped.
!                              * (Do this before the notnull check to be
!                              * consistent with exec_assign_value.)
!                              */
!                             if (!var->datatype->typinput.fn_strict)
!                             {
!                                 bool    valIsNull = true;
!
!                                 exec_assign_value(estate,
!                                                   (PLpgSQL_datum *) var,
!                                                   (Datum) 0,
!                                                   UNKNOWNOID,
!                                                   &valIsNull);
!                             }
!                             if (var->notnull)
!                                 ereport(ERROR,
                                      (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                                       errmsg("variable \"%s\" declared NOT NULL cannot default to NULL",
                                              var->refname)));
!                         }
!                         else
!                         {
!                             exec_assign_expr(estate, (PLpgSQL_datum *) var,
!                                              var->default_val);
!                         }
                      }
                  }
                  break;
--- 885,927 ----
                  {
                      PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);

+                     /* free any old value, in case re-entering block */
                      free_var(var);
!
!                     /* Initially it contains a NULL */
!                     var->value = (Datum) 0;
!                     var->isnull = true;
!
!                     if (var->default_val == NULL)
                      {
!                         /*
!                          * If needed, give the datatype a chance to reject
!                          * NULLs, by assigning a NULL to the variable.
!                          * We claim the value is of type UNKNOWN, not the
!                          * var's datatype, else coercion will be skipped.
!                          * (Do this before the notnull check to be
!                          * consistent with exec_assign_value.)
!                          */
!                         if (!var->datatype->typinput.fn_strict)
                          {
!                             bool    valIsNull = true;
!
!                             exec_assign_value(estate,
!                                               (PLpgSQL_datum *) var,
!                                               (Datum) 0,
!                                               UNKNOWNOID,
!                                               &valIsNull);
!                         }
!                         if (var->notnull)
!                             ereport(ERROR,
                                      (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                                       errmsg("variable \"%s\" declared NOT NULL cannot default to NULL",
                                              var->refname)));
!                     }
!                     else
!                     {
!                         exec_assign_expr(estate, (PLpgSQL_datum *) var,
!                                          var->default_val);
                      }
                  }
                  break;
***************
*** 1065,1071 ****
--- 1065,1073 ----
                      rc = exec_stmts(estate, exception->action);

                      free_var(state_var);
+                     state_var->value = (Datum) 0;
                      free_var(errm_var);
+                     errm_var->value = (Datum) 0;
                      break;
                  }
              }
***************
*** 4867,4872 ****
--- 4869,4880 ----
      }
  }

+ /*
+  * free_var --- pfree any pass-by-reference value of the variable.
+  *
+  * This should always be followed by some assignment to var->value,
+  * as it leaves a dangling pointer.
+  */
  static void
  free_var(PLpgSQL_var *var)
  {

pgsql-bugs by date:

Previous
From: "Asif Ali"
Date:
Subject: server crash: displaying sqlerrm in exception block
Next
From: Tom Lane
Date:
Subject: Re: server crash: displaying sqlerrm in exception block