xmlconcat(NULL) crash

Started by Peter Eisentrautabout 17 years ago1 messages
#1Peter Eisentraut
peter_e@gmx.net
2 attachment(s)

Due to some code reshuffling, xmlconcat(NULL) will crash in 8.3 and 8.4.
The pfree(buf.data) in ExecEvalXml() frees a buffer that is actuall
only initialized in the XMLFOREST case. So then the xmlconcat(NULL)
falls through to the pfree() it crashes. I have attached a patch for
8.3 and 8.4 to clean this up.

Attachments:

xmlconcat-null-fix-84.difftext/plain; name=xmlconcat-null-fix-84.diff; x-mac-creator=0; x-mac-type=0Download
diff -cr ../cvs-pgsql/src/backend/executor/execQual.c ./src/backend/executor/execQual.c
*** ../cvs-pgsql/src/backend/executor/execQual.c	2008-11-03 16:31:21.000000000 +0200
--- ./src/backend/executor/execQual.c	2008-11-14 16:31:52.000000000 +0200
***************
*** 3163,3175 ****
  			bool *isNull, ExprDoneCond *isDone)
  {
  	XmlExpr    *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
- 	text	   *result;
- 	StringInfoData buf;
  	Datum		value;
  	bool		isnull;
  	ListCell   *arg;
  	ListCell   *narg;
- 	int			i;
  
  	if (isDone)
  		*isDone = ExprSingleResult;
--- 3163,3172 ----
***************
*** 3195,3206 ****
  					*isNull = false;
  					return PointerGetDatum(xmlconcat(values));
  				}
  			}
  			break;
  
  		case IS_XMLFOREST:
  			initStringInfo(&buf);
- 			i = 0;
  			forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
  			{
  				ExprState  *e = (ExprState *) lfirst(arg);
--- 3192,3207 ----
  					*isNull = false;
  					return PointerGetDatum(xmlconcat(values));
  				}
+ 				else
+ 					return (Datum) 0;
  			}
  			break;
  
  		case IS_XMLFOREST:
+ 		{
+ 			StringInfoData buf;
+ 
  			initStringInfo(&buf);
  			forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
  			{
  				ExprState  *e = (ExprState *) lfirst(arg);
***************
*** 3215,3225 ****
  									 argname);
  					*isNull = false;
  				}
- 				i++;
  			}
  			break;
  
- 			/* The remaining cases don't need to set up buf */
  		case IS_XMLELEMENT:
  			*isNull = false;
  			return PointerGetDatum(xmlelement(xmlExpr, econtext));
--- 3216,3240 ----
  									 argname);
  					*isNull = false;
  				}
  			}
+ 
+ 			if (*isNull)
+ 			{
+ 				pfree(buf.data);
+ 				return (Datum) 0;
+ 			}
+ 			else
+ 			{
+ 				text	   *result;
+ 
+ 				result = cstring_to_text_with_len(buf.data, buf.len);
+ 				pfree(buf.data);
+ 
+ 				return PointerGetDatum(result);
+ 			}
+ 		}
  			break;
  
  		case IS_XMLELEMENT:
  			*isNull = false;
  			return PointerGetDatum(xmlelement(xmlExpr, econtext));
***************
*** 3354,3366 ****
  			break;
  	}
  
! 	if (*isNull)
! 		result = NULL;
! 	else
! 		result = cstring_to_text_with_len(buf.data, buf.len);
! 
! 	pfree(buf.data);
! 	return PointerGetDatum(result);
  }
  
  /* ----------------------------------------------------------------
--- 3369,3376 ----
  			break;
  	}
  
! 	elog(ERROR, "unrecognized XML operation");
! 	return (Datum) 0;
  }
  
  /* ----------------------------------------------------------------
diff -cr ../cvs-pgsql/src/test/regress/expected/xml.out ./src/test/regress/expected/xml.out
*** ../cvs-pgsql/src/test/regress/expected/xml.out	2008-09-02 15:11:11.000000000 +0300
--- ./src/test/regress/expected/xml.out	2008-11-14 16:50:02.000000000 +0200
***************
*** 77,82 ****
--- 77,94 ----
   <?xml version="1.1"?><foo/><bar/>
  (1 row)
  
+ SELECT xmlconcat(NULL);
+  xmlconcat 
+ -----------
+  
+ (1 row)
+ 
+ SELECT xmlconcat(NULL, NULL);
+  xmlconcat 
+ -----------
+  
+ (1 row)
+ 
  SELECT xmlelement(name element,
                    xmlattributes (1 as one, 'deuce' as two),
                    'content');
diff -cr ../cvs-pgsql/src/test/regress/expected/xml_1.out ./src/test/regress/expected/xml_1.out
*** ../cvs-pgsql/src/test/regress/expected/xml_1.out	2008-09-02 15:11:11.000000000 +0300
--- ./src/test/regress/expected/xml_1.out	2008-11-14 16:50:16.000000000 +0200
***************
*** 79,84 ****
--- 79,96 ----
                           ^
  DETAIL:  This functionality requires the server to be built with libxml support.
  HINT:  You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlconcat(NULL);
+  xmlconcat 
+ -----------
+  
+ (1 row)
+ 
+ SELECT xmlconcat(NULL, NULL);
+  xmlconcat 
+ -----------
+  
+ (1 row)
+ 
  SELECT xmlelement(name element,
                    xmlattributes (1 as one, 'deuce' as two),
                    'content');
diff -cr ../cvs-pgsql/src/test/regress/sql/xml.sql ./src/test/regress/sql/xml.sql
*** ../cvs-pgsql/src/test/regress/sql/xml.sql	2007-11-09 17:52:51.000000000 +0200
--- ./src/test/regress/sql/xml.sql	2008-11-14 16:49:41.000000000 +0200
***************
*** 26,31 ****
--- 26,33 ----
  SELECT xmlconcat('bad', '<syntax');
  SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
  SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
+ SELECT xmlconcat(NULL);
+ SELECT xmlconcat(NULL, NULL);
  
  
  SELECT xmlelement(name element,
xmlconcat-null-fix-83.difftext/plain; name=xmlconcat-null-fix-83.diff; x-mac-creator=0; x-mac-type=0Download
diff -cr ../cvs-pgsql/src/backend/executor/execQual.c ./src/backend/executor/execQual.c
*** ../cvs-pgsql/src/backend/executor/execQual.c	2008-09-04 15:15:17.000000000 +0300
--- ./src/backend/executor/execQual.c	2008-11-14 15:57:59.000000000 +0200
***************
*** 2848,2860 ****
  			bool *isNull, ExprDoneCond *isDone)
  {
  	XmlExpr    *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
- 	text	   *result;
- 	StringInfoData buf;
  	Datum		value;
  	bool		isnull;
  	ListCell   *arg;
  	ListCell   *narg;
- 	int			i;
  
  	if (isDone)
  		*isDone = ExprSingleResult;
--- 2848,2857 ----
***************
*** 2880,2891 ****
  					*isNull = false;
  					return PointerGetDatum(xmlconcat(values));
  				}
  			}
  			break;
  
  		case IS_XMLFOREST:
  			initStringInfo(&buf);
- 			i = 0;
  			forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
  			{
  				ExprState  *e = (ExprState *) lfirst(arg);
--- 2877,2892 ----
  					*isNull = false;
  					return PointerGetDatum(xmlconcat(values));
  				}
+ 				else
+ 					return (Datum) 0;
  			}
  			break;
  
  		case IS_XMLFOREST:
+ 		{
+ 			StringInfoData buf;
+ 
  			initStringInfo(&buf);
  			forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
  			{
  				ExprState  *e = (ExprState *) lfirst(arg);
***************
*** 2900,2910 ****
  									 argname);
  					*isNull = false;
  				}
- 				i++;
  			}
  			break;
  
- 			/* The remaining cases don't need to set up buf */
  		case IS_XMLELEMENT:
  			*isNull = false;
  			return PointerGetDatum(xmlelement(xmlExpr, econtext));
--- 2901,2930 ----
  									 argname);
  					*isNull = false;
  				}
  			}
+ 
+ 			if (*isNull)
+ 			{
+ 				pfree(buf.data);
+ 				return (Datum) 0;
+ 			}
+ 			else
+ 			{
+ 				int			len;
+ 				text	   *result;
+ 
+ 				len = buf.len + VARHDRSZ;
+ 
+ 				result = palloc(len);
+ 				SET_VARSIZE(result, len);
+ 				memcpy(VARDATA(result), buf.data, buf.len);
+ 				pfree(buf.data);
+ 
+ 				return PointerGetDatum(result);
+ 			}
+ 		}
  			break;
  
  		case IS_XMLELEMENT:
  			*isNull = false;
  			return PointerGetDatum(xmlelement(xmlExpr, econtext));
***************
*** 3039,3057 ****
  			break;
  	}
  
! 	if (*isNull)
! 		result = NULL;
! 	else
! 	{
! 		int			len = buf.len + VARHDRSZ;
! 
! 		result = palloc(len);
! 		SET_VARSIZE(result, len);
! 		memcpy(VARDATA(result), buf.data, buf.len);
! 	}
! 
! 	pfree(buf.data);
! 	return PointerGetDatum(result);
  }
  
  /* ----------------------------------------------------------------
--- 3059,3066 ----
  			break;
  	}
  
! 	elog(ERROR, "unrecognized XML operation");
! 	return (Datum) 0;
  }
  
  /* ----------------------------------------------------------------
diff -cr ../cvs-pgsql/src/test/regress/expected/xml.out ./src/test/regress/expected/xml.out
*** ../cvs-pgsql/src/test/regress/expected/xml.out	2008-09-04 15:15:55.000000000 +0300
--- ./src/test/regress/expected/xml.out	2008-11-14 16:48:59.000000000 +0200
***************
*** 71,76 ****
--- 71,88 ----
   <?xml version="1.1"?><foo/><bar/>
  (1 row)
  
+ SELECT xmlconcat(NULL);
+  xmlconcat 
+ -----------
+  
+ (1 row)
+ 
+ SELECT xmlconcat(NULL, NULL);
+  xmlconcat 
+ -----------
+  
+ (1 row)
+ 
  SELECT xmlelement(name element,
                    xmlattributes (1 as one, 'deuce' as two),
                    'content');
diff -cr ../cvs-pgsql/src/test/regress/expected/xml_1.out ./src/test/regress/expected/xml_1.out
*** ../cvs-pgsql/src/test/regress/expected/xml_1.out	2008-09-04 15:15:55.000000000 +0300
--- ./src/test/regress/expected/xml_1.out	2008-11-14 16:49:19.000000000 +0200
***************
*** 63,68 ****
--- 63,80 ----
  ERROR:  unsupported XML feature
  DETAIL:  This functionality requires the server to be built with libxml support.
  HINT:  You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlconcat(NULL);
+  xmlconcat 
+ -----------
+  
+ (1 row)
+ 
+ SELECT xmlconcat(NULL, NULL);
+  xmlconcat 
+ -----------
+  
+ (1 row)
+ 
  SELECT xmlelement(name element,
                    xmlattributes (1 as one, 'deuce' as two),
                    'content');
diff -cr ../cvs-pgsql/src/test/regress/sql/xml.sql ./src/test/regress/sql/xml.sql
*** ../cvs-pgsql/src/test/regress/sql/xml.sql	2007-11-09 17:52:51.000000000 +0200
--- ./src/test/regress/sql/xml.sql	2008-11-14 16:48:31.000000000 +0200
***************
*** 26,31 ****
--- 26,33 ----
  SELECT xmlconcat('bad', '<syntax');
  SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
  SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
+ SELECT xmlconcat(NULL);
+ SELECT xmlconcat(NULL, NULL);
  
  
  SELECT xmlelement(name element,