mirror of https://github.com/postgres/postgres
ECPGdeallocate_all(), ECPGprepared_statement(), ECPGget_desc(), and ecpg_freeStmtCacheEntry() could crash with a SIGSEGV when called without an established connection (for example, when EXEC SQL CONNECT was forgotten or a non-existent connection name was used), because they dereferenced the result of ecpg_get_connection() without first checking it for NULL. Each site is fixed in the style of the surrounding code. New tests are added for these conditions. Author: Shruthi Gowda <gowdashru@gmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Fujii Masao <masao.fujii@gmail.com> Reviewed-by: Mahendra Singh Thalor <mahi6run@gmail.com> Reviewed-by: Nishant Sharma <nishant.sharma@enterprisedb.com> Discussion: https://postgr.es/m/3007317.1765210195@sss.pgh.pa.us Backpatch-through: 14REL_15_STABLE
parent
e4f035de45
commit
6916f44100
@ -0,0 +1,68 @@ |
||||
/* |
||||
* This test verifies that ecpg functions properly handle NULL connections |
||||
* (i.e., when a connection name doesn't exist or has been disconnected). |
||||
* Before the fix, these operations would cause a segmentation fault. |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
|
||||
exec sql include ../regression; |
||||
|
||||
int |
||||
main(void) |
||||
{ |
||||
exec sql begin declare section; |
||||
int val1output = 2; |
||||
int val1 = 1; |
||||
char val2[6] = "data1"; |
||||
char *stmt1 = "SELECT * from test1 where a = $1 and b = $2"; |
||||
exec sql end declare section; |
||||
|
||||
ECPGdebug(1, stderr); |
||||
|
||||
/* Connect to the database */ |
||||
exec sql connect to REGRESSDB1 as myconn; |
||||
|
||||
/* Test 1: Try to get descriptor on a disconnected connection */ |
||||
printf("Test 1: Try to get descriptor on a disconnected connection\n"); |
||||
exec sql create table test1 (a int, b text); |
||||
exec sql insert into test1 (a,b) values (1, 'data1'); |
||||
|
||||
exec sql allocate descriptor indesc; |
||||
exec sql allocate descriptor outdesc; |
||||
|
||||
exec sql prepare foo2 from :stmt1; |
||||
|
||||
exec sql set descriptor indesc value 1 DATA = :val1; |
||||
exec sql set descriptor indesc value 2 DATA = :val2; |
||||
|
||||
exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc; |
||||
|
||||
exec sql rollback; |
||||
exec sql disconnect; |
||||
exec sql get descriptor outdesc value 1 :val1output = DATA; |
||||
printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); |
||||
|
||||
/* Test 2: Try to deallocate all on a non-existent connection */ |
||||
printf("Test 2: deallocate all with non-existent connection\n"); |
||||
exec sql at nonexistent deallocate all; |
||||
printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); |
||||
|
||||
/* Test 3: deallocate on disconnected connection */ |
||||
printf("Test 3: deallocate all on disconnected connection\n"); |
||||
exec sql deallocate all; |
||||
printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); |
||||
|
||||
/* Test 4: Use prepared statement from non-existent connection */ |
||||
printf("Test 4: Use prepared statement from non-existent connection\n"); |
||||
exec sql at nonexistent prepare stmt1 FROM "SELECT 1"; |
||||
exec sql at nonexistent declare cur1 cursor for stmt1; |
||||
exec sql at nonexistent open cur1; |
||||
printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); |
||||
|
||||
printf("All tests completed !\n"); |
||||
|
||||
return 0; |
||||
} |
||||
@ -0,0 +1,146 @@ |
||||
/* Processed by ecpg (regression mode) */ |
||||
/* These include files are added by the preprocessor */ |
||||
#include <ecpglib.h> |
||||
#include <ecpgerrno.h> |
||||
#include <sqlca.h> |
||||
/* End of automatic include section */ |
||||
#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) |
||||
|
||||
#line 1 "test6.pgc" |
||||
/*
|
||||
* This test verifies that ecpg functions properly handle NULL connections |
||||
* (i.e., when a connection name doesn't exist or has been disconnected). |
||||
* Before the fix, these operations would cause a segmentation fault. |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
|
||||
|
||||
#line 1 "regression.h" |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#line 11 "test6.pgc" |
||||
|
||||
|
||||
int |
||||
main(void) |
||||
{ |
||||
/* exec sql begin declare section */ |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#line 17 "test6.pgc" |
||||
int val1output = 2 ; |
||||
|
||||
#line 18 "test6.pgc" |
||||
int val1 = 1 ; |
||||
|
||||
#line 19 "test6.pgc" |
||||
char val2 [ 6 ] = "data1" ; |
||||
|
||||
#line 20 "test6.pgc" |
||||
char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ; |
||||
/* exec sql end declare section */ |
||||
#line 21 "test6.pgc" |
||||
|
||||
|
||||
ECPGdebug(1, stderr); |
||||
|
||||
/* Connect to the database */ |
||||
{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); } |
||||
#line 26 "test6.pgc" |
||||
|
||||
|
||||
/* Test 1: Try to get descriptor on a disconnected connection */ |
||||
printf("Test 1: Try to get descriptor on a disconnected connection\n"); |
||||
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);} |
||||
#line 30 "test6.pgc" |
||||
|
||||
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);} |
||||
#line 31 "test6.pgc" |
||||
|
||||
|
||||
ECPGallocate_desc(__LINE__, "indesc"); |
||||
#line 33 "test6.pgc" |
||||
|
||||
ECPGallocate_desc(__LINE__, "outdesc"); |
||||
#line 34 "test6.pgc" |
||||
|
||||
|
||||
{ ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);} |
||||
#line 36 "test6.pgc" |
||||
|
||||
|
||||
{ ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data, |
||||
ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT); |
||||
} |
||||
#line 38 "test6.pgc" |
||||
|
||||
{ ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data, |
||||
ECPGt_char,(val2),(long)6,(long)1,(6)*sizeof(char), ECPGd_EODT); |
||||
} |
||||
#line 39 "test6.pgc" |
||||
|
||||
|
||||
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2",
|
||||
ECPGt_descriptor, "indesc", 1L, 1L, 1L,
|
||||
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
|
||||
ECPGt_descriptor, "outdesc", 1L, 1L, 1L,
|
||||
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);} |
||||
#line 41 "test6.pgc" |
||||
|
||||
|
||||
{ ECPGtrans(__LINE__, NULL, "rollback");} |
||||
#line 43 "test6.pgc" |
||||
|
||||
{ ECPGdisconnect(__LINE__, "CURRENT");} |
||||
#line 44 "test6.pgc" |
||||
|
||||
{ ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data, |
||||
ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT); |
||||
} |
||||
#line 45 "test6.pgc" |
||||
|
||||
printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); |
||||
|
||||
/* Test 2: Try to deallocate all on a non-existent connection */ |
||||
printf("Test 2: deallocate all with non-existent connection\n"); |
||||
{ ECPGdeallocate_all(__LINE__, 0, "nonexistent");} |
||||
#line 50 "test6.pgc" |
||||
|
||||
printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); |
||||
|
||||
/* Test 3: deallocate on disconnected connection */ |
||||
printf("Test 3: deallocate all on disconnected connection\n"); |
||||
{ ECPGdeallocate_all(__LINE__, 0, NULL);} |
||||
#line 55 "test6.pgc" |
||||
|
||||
printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); |
||||
|
||||
/* Test 4: Use prepared statement from non-existent connection */ |
||||
printf("Test 4: Use prepared statement from non-existent connection\n"); |
||||
{ ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");} |
||||
#line 60 "test6.pgc" |
||||
|
||||
/* declare cur1 cursor for $1 */ |
||||
#line 61 "test6.pgc" |
||||
|
||||
{ ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1",
|
||||
ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char),
|
||||
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);} |
||||
#line 62 "test6.pgc" |
||||
|
||||
printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); |
||||
|
||||
printf("All tests completed !\n"); |
||||
|
||||
return 0; |
||||
} |
||||
@ -0,0 +1,50 @@ |
||||
[NO_PID]: ECPGdebug: set to 1 |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT> |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_execute on line 30: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_execute on line 30: using PQexec |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_process_output on line 30: OK: CREATE TABLE |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_execute on line 31: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_execute on line 31: using PQexec |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1 |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: prepare_common on line 36: name foo2; query: "SELECT * from test1 where a = $1 and b = $2" |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_execute on line 41: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_execute on line 41: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2" |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1 |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_free_params on line 41: parameter 2 = data1 |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_process_output on line 41: putting result (1 tuples) into descriptor outdesc |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ECPGtrans on line 43: action "rollback"; connection "myconn" |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: deallocate_one on line 0: name foo2 |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ecpg_finish: connection myconn closed |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: ECPGget_desc: reading items for tuple 1 |
||||
[NO_PID]: sqlca: code: 0, state: 00000 |
||||
[NO_PID]: raising sqlcode -220 on line 45: connection "NULL" does not exist on line 45 |
||||
[NO_PID]: sqlca: code: -220, state: 08003 |
||||
[NO_PID]: raising sqlcode -220 on line 50: connection "nonexistent" does not exist on line 50 |
||||
[NO_PID]: sqlca: code: -220, state: 08003 |
||||
[NO_PID]: raising sqlcode -220 on line 55: connection "NULL" does not exist on line 55 |
||||
[NO_PID]: sqlca: code: -220, state: 08003 |
||||
[NO_PID]: raising sqlcode -220 on line 60: connection "nonexistent" does not exist on line 60 |
||||
[NO_PID]: sqlca: code: -220, state: 08003 |
||||
[NO_PID]: raising sqlcode -220 on line 63: connection "nonexistent" does not exist on line 63 |
||||
[NO_PID]: sqlca: code: -220, state: 08003 |
||||
[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62 |
||||
[NO_PID]: sqlca: code: -220, state: 08003 |
||||
@ -0,0 +1,9 @@ |
||||
Test 1: Try to get descriptor on a disconnected connection |
||||
sqlca.sqlcode = -220 |
||||
Test 2: deallocate all with non-existent connection |
||||
sqlca.sqlcode = -220 |
||||
Test 3: deallocate all on disconnected connection |
||||
sqlca.sqlcode = -220 |
||||
Test 4: Use prepared statement from non-existent connection |
||||
sqlca.sqlcode = -220 |
||||
All tests completed ! |
||||
Loading…
Reference in new issue