Hello -

Attached is a proposed patch to fix a bug in the ECPG preprocessor that
generates application code that core dumps at run-time. When the input pgc
code uses a record struct for returning query results and uses an indicator
struct that has fewer fields than the record struct, the generated .c code
will compile with no warning but core dump. This situation comes up when a
developer adds a field to an existing query, adds the field to the record
struct and forgets to add the field to the indicator struct.

The patch fixes the generated code to use ECPGt_NO_INDICATOR in the call to
ecpglib for indicator members that are not present and issues a compiler
warning for either too few indicator members or too many indicator members.

The attached sample files are a simple sample of pgc code that can be used
to see the difference in before and after generation and the before and
after generated code.

If accepted, this bug fix can be back ported to earlier versions of ecpg as
well.

Thanks
Dave
From dc24cf9e4b4eb22be1e570fd449f97c6251d61c3 Mon Sep 17 00:00:00 2001
From: David Rader <dav...@openscg.com>
Date: Thu, 11 Jan 2018 16:26:57 +0000
Subject: [PATCH] Fix generated code to avoid core dump when indicator struct
 has fewer members than record struct. Add compiler warnings for too few or
 too many indicator struct members.

---
 src/interfaces/ecpg/preproc/type.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index 4abbf93..fa1a05c 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -609,7 +609,17 @@ ECPGdump_a_struct(FILE *o, const char *name, const char *ind_name, char *arrsize
 						prefix, ind_prefix, arrsize, type->struct_sizeof,
 						(ind_p != NULL) ? ind_type->struct_sizeof : NULL);
 		if (ind_p != NULL && ind_p != &struct_no_indicator)
+		{
 			ind_p = ind_p->next;
+			if (ind_p == NULL && p->next != NULL) {
+				mmerror(PARSE_ERROR, ET_WARNING, "indicator struct \"%s\" has too few members", ind_name);
+				ind_p = &struct_no_indicator;
+			}
+		}
+	}
+
+	if (ind_type != NULL && ind_p != NULL && ind_p != &struct_no_indicator) {
+		mmerror(PARSE_ERROR, ET_WARNING, "indicator struct \"%s\" has too many members", ind_name);
 	}
 
 	free(pbuf);
-- 
1.8.3.1

/* Processed by ecpg (4.12.0) */
/* These include files are added by the preprocessor */
#include <ecpglib.h>
#include <ecpgerrno.h>
#include <sqlca.h>
/* End of automatic include section */

#line 1 "indrecs.pgc"
#include <stdlib.h>
#include <sqlca.h>
#include <string>

using namespace std;

int get_conn(  )
{
	int sqlcode;

	/* exec sql begin declare section */
	     
	     
	     
	
#line 12 "indrecs.pgc"
 char * pgdsn = getenv ( "PGDSN" ) ;
 
#line 13 "indrecs.pgc"
 char * pguser = getenv ( "PGUSER" ) ;
 
#line 14 "indrecs.pgc"
 char * pgpass = getenv ( "PGPASS" ) ;
/* exec sql end declare section */
#line 15 "indrecs.pgc"


	if (pgdsn == NULL)
	{
	    printf("PGDSN is not set\n");
	    sqlcode = 100;
	    return 1;
	}
	if (pguser == NULL)
	{
	    printf("PGUSER is not set\n");
	    sqlcode = 100;
	    return 1;
	}
	if (pgpass == NULL)
	{
	    printf("PGPASS is not set\n");
	    sqlcode = 100;
	    return 1;
	}

	{ ECPGconnect(__LINE__, 0, pgdsn , pguser , pgpass , NULL, 0); }
#line 36 "indrecs.pgc"

	sqlcode = sqlca.sqlcode;
	printf("connect sqlcode: %d\n", sqlca.sqlcode);

}

void close_conn() {
	{ ECPGdisconnect(__LINE__, "CURRENT");}
#line 43 "indrecs.pgc"

	printf("disconnect sqlcode: %d\n", sqlca.sqlcode);
}

int main()
{

	/* exec sql whenever sql_warning  sqlprint ; */
#line 50 "indrecs.pgc"

	/* exec sql whenever sqlerror  sqlprint ; */
#line 51 "indrecs.pgc"


	if(!get_conn()) return 1;

	/* exec sql begin declare section */
	 

	  
	 
	 
	 
	 

	  
	 
	 
	 
	 
	 
	 
	 

	  
	 
	 
	 
	 
	 
	 
	 
	 


         
	   
	   
	   
	   
           
           
        
	
#line 56 "indrecs.pgc"
 char query [ 2048 ] = "\0" ;
 
#line 62 "indrecs.pgc"
 struct record_ind_short { 
#line 59 "indrecs.pgc"
 short Tind0 ;
 
#line 60 "indrecs.pgc"
 short Tind1 ;
 
#line 61 "indrecs.pgc"
 short Tind2 ;
 } record_ind_s ;
 
#line 71 "indrecs.pgc"
 struct record_ind_full { 
#line 65 "indrecs.pgc"
 short Tind0 ;
 
#line 66 "indrecs.pgc"
 short Tind1 ;
 
#line 67 "indrecs.pgc"
 short Tind2 ;
 
#line 68 "indrecs.pgc"
 short Tind3 ;
 
#line 69 "indrecs.pgc"
 short Tind4 ;
 
#line 70 "indrecs.pgc"
 short Tind5 ;
 } record_ind_f ;
 
#line 81 "indrecs.pgc"
 struct record_ind_long { 
#line 74 "indrecs.pgc"
 short Tind0 ;
 
#line 75 "indrecs.pgc"
 short Tind1 ;
 
#line 76 "indrecs.pgc"
 short Tind2 ;
 
#line 77 "indrecs.pgc"
 short Tind3 ;
 
#line 78 "indrecs.pgc"
 short Tind4 ;
 
#line 79 "indrecs.pgc"
 short Tind5 ;
 
#line 80 "indrecs.pgc"
 short Tind6 ;
 } record_ind_l ;
 
#line 91 "indrecs.pgc"
 struct FavRecord { 
#line 85 "indrecs.pgc"
 int service_id ;
 
#line 86 "indrecs.pgc"
 char service_name [ 11 ] ;
 
#line 87 "indrecs.pgc"
 char display_name [ 11 ] ;
 
#line 88 "indrecs.pgc"
 char jsp_name [ 11 ] ;
 
#line 89 "indrecs.pgc"
 int display_seq ;
 
#line 90 "indrecs.pgc"
 int default_display ;
 } record ;
/* exec sql end declare section */
#line 92 "indrecs.pgc"



	/* exec sql whenever not found  continue ; */
#line 95 "indrecs.pgc"


	string favSql = "select a, b, d, f, c, e from dummy";
	printf("Query String: %s\n", favSql.c_str());

	strcpy(query,favSql.c_str());
	printf("Copied query String: %s\n", query);


	{ ECPGprepare(__LINE__, NULL, 0, "favstmt", query);
#line 104 "indrecs.pgc"

if (sqlca.sqlwarn[0] == 'W') sqlprint();
#line 104 "indrecs.pgc"

if (sqlca.sqlcode < 0) sqlprint();}
#line 104 "indrecs.pgc"

        /* declare c_favList cursor for $1 */
#line 105 "indrecs.pgc"


	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare c_favList cursor for $1", 
	ECPGt_char_variable,(ECPGprepared_statement(NULL, "favstmt", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
#line 107 "indrecs.pgc"

if (sqlca.sqlwarn[0] == 'W') sqlprint();
#line 107 "indrecs.pgc"

if (sqlca.sqlcode < 0) sqlprint();}
#line 107 "indrecs.pgc"

	printf("Opened cursor\n");

	//while(true)
	//{
		printf("Retrieving rec with full indicator\n", query);
		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch c_favList", ECPGt_EOIT, 
	ECPGt_int,&(record.service_id),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_f.Tind0),(long)1,(long)1,sizeof( struct record_ind_full ), 
	ECPGt_char,&(record.service_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_f.Tind1),(long)1,(long)1,sizeof( struct record_ind_full ), 
	ECPGt_char,&(record.display_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_f.Tind2),(long)1,(long)1,sizeof( struct record_ind_full ), 
	ECPGt_char,&(record.jsp_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_f.Tind3),(long)1,(long)1,sizeof( struct record_ind_full ), 
	ECPGt_int,&(record.display_seq),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_f.Tind4),(long)1,(long)1,sizeof( struct record_ind_full ), 
	ECPGt_int,&(record.default_display),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_f.Tind5),(long)1,(long)1,sizeof( struct record_ind_full ), ECPGt_EORT);
#line 113 "indrecs.pgc"

if (sqlca.sqlwarn[0] == 'W') sqlprint();
#line 113 "indrecs.pgc"

if (sqlca.sqlcode < 0) sqlprint();}
#line 113 "indrecs.pgc"

		printf("Retrieved rec with full indicator\n", query);

		printf("Retrieving rec with short indicator\n", query);
		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch c_favList", ECPGt_EOIT, 
	ECPGt_int,&(record.service_id),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_s.Tind0),(long)1,(long)1,sizeof( struct record_ind_short ), 
	ECPGt_char,&(record.service_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_s.Tind1),(long)1,(long)1,sizeof( struct record_ind_short ), 
	ECPGt_char,&(record.display_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_s.Tind2),(long)1,(long)1,sizeof( struct record_ind_short ), 
	ECPGt_char,&(record.jsp_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_int,&(record.display_seq),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_int,&(record.default_display),(long)1,(long)1,sizeof( struct FavRecord ), ECPGt_EORT);
#line 117 "indrecs.pgc"

if (sqlca.sqlwarn[0] == 'W') sqlprint();
#line 117 "indrecs.pgc"

if (sqlca.sqlcode < 0) sqlprint();}
#line 117 "indrecs.pgc"

		printf("Retrieved rec with short indicator\n", query);

		printf("Retrieving rec with long indicator\n", query);
		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch c_favList", ECPGt_EOIT, 
	ECPGt_int,&(record.service_id),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_l.Tind0),(long)1,(long)1,sizeof( struct record_ind_long ), 
	ECPGt_char,&(record.service_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_l.Tind1),(long)1,(long)1,sizeof( struct record_ind_long ), 
	ECPGt_char,&(record.display_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_l.Tind2),(long)1,(long)1,sizeof( struct record_ind_long ), 
	ECPGt_char,&(record.jsp_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_l.Tind3),(long)1,(long)1,sizeof( struct record_ind_long ), 
	ECPGt_int,&(record.display_seq),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_l.Tind4),(long)1,(long)1,sizeof( struct record_ind_long ), 
	ECPGt_int,&(record.default_display),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_short,&(record_ind_l.Tind5),(long)1,(long)1,sizeof( struct record_ind_long ), ECPGt_EORT);
#line 121 "indrecs.pgc"

if (sqlca.sqlwarn[0] == 'W') sqlprint();
#line 121 "indrecs.pgc"

if (sqlca.sqlcode < 0) sqlprint();}
#line 121 "indrecs.pgc"

		printf("Retrieved rec with long indicator\n", query);

		printf("Retrieving rec with no indicator\n", query);
		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch c_favList", ECPGt_EOIT, 
	ECPGt_int,&(record.service_id),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
	ECPGt_char,&(record.service_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
	ECPGt_char,&(record.display_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
	ECPGt_char,&(record.jsp_name),(long)11,(long)1,sizeof( struct FavRecord ), 
	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
	ECPGt_int,&(record.display_seq),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
	ECPGt_int,&(record.default_display),(long)1,(long)1,sizeof( struct FavRecord ), 
	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
#line 125 "indrecs.pgc"

if (sqlca.sqlwarn[0] == 'W') sqlprint();
#line 125 "indrecs.pgc"

if (sqlca.sqlcode < 0) sqlprint();}
#line 125 "indrecs.pgc"

		printf("Retrieved rec with no indicator\n", query);

	//}

	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "close c_favList", ECPGt_EOIT, ECPGt_EORT);
#line 130 "indrecs.pgc"

if (sqlca.sqlwarn[0] == 'W') sqlprint();
#line 130 "indrecs.pgc"

if (sqlca.sqlcode < 0) sqlprint();}
#line 130 "indrecs.pgc"


	close_conn();

  	return( 0 );
}

Attachment: indrecs.c.fix
Description: Binary data

Attachment: indrecs.pgc
Description: Binary data

Reply via email to