Skip to content

Commit afdef54

Browse files
committed
[PGPRO-7614] Fix crash by using cursor after rollback of cursor creation
Tags: pg_variables
1 parent 02d5dac commit afdef54

File tree

4 files changed

+171
-8
lines changed

4 files changed

+171
-8
lines changed

expected/pg_variables_trans.out

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3834,3 +3834,51 @@ SELECT pgv_free();
38343834
--
38353835
SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE);
38363836
ERROR: could not identify a hash function for type record
3837+
--
3838+
-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor
3839+
-- creation.
3840+
--
3841+
BEGIN;
3842+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true);
3843+
pgv_insert
3844+
------------
3845+
3846+
(1 row)
3847+
3848+
DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x');
3849+
SAVEPOINT sp1;
3850+
FETCH 1 in r1_cur;
3851+
pgv_select
3852+
------------
3853+
(1,2)
3854+
(1 row)
3855+
3856+
ROLLBACK TO SAVEPOINT sp1;
3857+
FETCH 1 in r1_cur;
3858+
pgv_select
3859+
------------
3860+
(0 rows)
3861+
3862+
ROLLBACK;
3863+
BEGIN;
3864+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE);
3865+
pgv_insert
3866+
------------
3867+
3868+
(1 row)
3869+
3870+
DECLARE r1_cur CURSOR FOR SELECT pgv_stats();
3871+
SAVEPOINT sp1;
3872+
FETCH 1 in r1_cur;
3873+
pgv_stats
3874+
--------------
3875+
(test,32768)
3876+
(1 row)
3877+
3878+
ROLLBACK TO SAVEPOINT sp1;
3879+
FETCH 1 in r1_cur;
3880+
pgv_stats
3881+
-----------
3882+
(0 rows)
3883+
3884+
ROLLBACK;

expected/pg_variables_trans_0.out

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3838,3 +3838,51 @@ SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE);
38383838

38393839
(1 row)
38403840

3841+
--
3842+
-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor
3843+
-- creation.
3844+
--
3845+
BEGIN;
3846+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true);
3847+
pgv_insert
3848+
------------
3849+
3850+
(1 row)
3851+
3852+
DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x');
3853+
SAVEPOINT sp1;
3854+
FETCH 1 in r1_cur;
3855+
pgv_select
3856+
------------
3857+
(1,2)
3858+
(1 row)
3859+
3860+
ROLLBACK TO SAVEPOINT sp1;
3861+
FETCH 1 in r1_cur;
3862+
pgv_select
3863+
------------
3864+
(0 rows)
3865+
3866+
ROLLBACK;
3867+
BEGIN;
3868+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE);
3869+
pgv_insert
3870+
------------
3871+
3872+
(1 row)
3873+
3874+
DECLARE r1_cur CURSOR FOR SELECT pgv_stats();
3875+
SAVEPOINT sp1;
3876+
FETCH 1 in r1_cur;
3877+
pgv_stats
3878+
--------------
3879+
(test,32768)
3880+
(1 row)
3881+
3882+
ROLLBACK TO SAVEPOINT sp1;
3883+
FETCH 1 in r1_cur;
3884+
pgv_stats
3885+
-----------
3886+
(0 rows)
3887+
3888+
ROLLBACK;

pg_variables.c

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,14 @@ typedef struct tagVariableStatEntry
166166
Variable *variable;
167167
Package *package;
168168
Levels levels;
169+
void **user_fctx; /* pointer to funcctx->user_fctx */
169170
} VariableStatEntry;
170171

171172
typedef struct tagPackageStatEntry
172173
{
173174
HASH_SEQ_STATUS *status;
174175
Levels levels;
176+
void **user_fctx; /* pointer to funcctx->user_fctx */
175177
} PackageStatEntry;
176178

177179
#ifdef PGPRO_EE
@@ -268,6 +270,25 @@ PackageStatEntry_status_ptr(void *entry)
268270
return ((PackageStatEntry *) entry)->status;
269271
}
270272

273+
/*
274+
* VariableStatEntry and PackageStatEntry functions for clear function context.
275+
*/
276+
static void
277+
VariableStatEntry_clear_fctx(void *entry)
278+
{
279+
VariableStatEntry *e = (VariableStatEntry *) entry;
280+
if (e->user_fctx)
281+
*e->user_fctx = NULL;
282+
}
283+
284+
static void
285+
PackageStatEntry_clear_fctx(void *entry)
286+
{
287+
PackageStatEntry *e = (PackageStatEntry *) entry;
288+
if (e->user_fctx)
289+
*e->user_fctx = NULL;
290+
}
291+
271292
/*
272293
* Generic remove_if algorithm.
273294
*
@@ -289,6 +310,7 @@ typedef struct tagRemoveIfContext
289310
HASH_SEQ_STATUS *(*getter) (void *); /* status getter */
290311
bool match_first; /* return on first match */
291312
bool term; /* hash_seq_term on match */
313+
void (*clear_fctx) (void *); /* clear function context */
292314
} RemoveIfContext;
293315

294316
static void
@@ -316,6 +338,8 @@ list_remove_if(RemoveIfContext ctx)
316338
hash_seq_term(ctx.getter(entry));
317339
#endif
318340

341+
ctx.clear_fctx(entry);
342+
319343
pfree(ctx.getter(entry));
320344
pfree(entry);
321345

@@ -352,6 +376,8 @@ list_remove_if(RemoveIfContext ctx)
352376
hash_seq_term(ctx.getter(entry));
353377
#endif
354378

379+
ctx.clear_fctx(entry);
380+
355381
pfree(ctx.getter(entry));
356382
pfree(entry);
357383

@@ -375,7 +401,8 @@ remove_variables_status(List **list, HASH_SEQ_STATUS *status)
375401
.eq = VariableStatEntry_status_eq,
376402
.getter = VariableStatEntry_status_ptr,
377403
.match_first = true,
378-
.term = false
404+
.term = false,
405+
.clear_fctx = VariableStatEntry_clear_fctx
379406
};
380407

381408
list_remove_if(ctx);
@@ -398,7 +425,8 @@ remove_variables_variable(List **list, Variable *variable)
398425
.eq = VariableStatEntry_variable_eq,
399426
.getter = VariableStatEntry_status_ptr,
400427
.match_first = false,
401-
.term = true
428+
.term = true,
429+
.clear_fctx = VariableStatEntry_clear_fctx
402430
};
403431

404432
list_remove_if(ctx);
@@ -417,7 +445,8 @@ remove_variables_package(List **list, Package *package)
417445
.eq = VariableStatEntry_package_eq,
418446
.getter = VariableStatEntry_status_ptr,
419447
.match_first = false,
420-
.term = true
448+
.term = true,
449+
.clear_fctx = VariableStatEntry_clear_fctx
421450
};
422451

423452
list_remove_if(ctx);
@@ -436,7 +465,8 @@ remove_variables_level(List **list, Levels *levels)
436465
.eq = VariableStatEntry_level_eq,
437466
.getter = VariableStatEntry_status_ptr,
438467
.match_first = false,
439-
.term = false
468+
.term = false,
469+
.clear_fctx = VariableStatEntry_clear_fctx
440470
};
441471

442472
list_remove_if(ctx);
@@ -455,7 +485,8 @@ remove_variables_all(List **list)
455485
.eq = VariableStatEntry_eq_all,
456486
.getter = VariableStatEntry_status_ptr,
457487
.match_first = false,
458-
.term = true
488+
.term = true,
489+
.clear_fctx = VariableStatEntry_clear_fctx
459490
};
460491

461492
list_remove_if(ctx);
@@ -474,7 +505,8 @@ remove_packages_status(List **list, HASH_SEQ_STATUS *status)
474505
.eq = PackageStatEntry_status_eq,
475506
.getter = PackageStatEntry_status_ptr,
476507
.match_first = true,
477-
.term = false
508+
.term = false,
509+
.clear_fctx = PackageStatEntry_clear_fctx
478510
};
479511

480512
list_remove_if(ctx);
@@ -493,7 +525,8 @@ remove_packages_level(List **list, Levels *levels)
493525
.eq = PackageStatEntry_level_eq,
494526
.getter = PackageStatEntry_status_ptr,
495527
.match_first = false,
496-
.term = true
528+
.term = true,
529+
.clear_fctx = PackageStatEntry_clear_fctx
497530
};
498531

499532
list_remove_if(ctx);
@@ -513,7 +546,8 @@ remove_variables_transactional(List **list)
513546
.eq = VariableStatEntry_is_transactional,
514547
.getter = VariableStatEntry_status_ptr,
515548
.match_first = false,
516-
.term = true
549+
.term = true,
550+
.clear_fctx = VariableStatEntry_clear_fctx
517551
};
518552

519553
list_remove_if(ctx);
@@ -1027,6 +1061,7 @@ variable_select(PG_FUNCTION_ARGS)
10271061
#ifdef PGPRO_EE
10281062
entry->levels.atxlevel = getNestLevelATX();
10291063
#endif
1064+
entry->user_fctx = &funcctx->user_fctx;
10301065
variables_stats = lcons((void *) entry, variables_stats);
10311066

10321067
MemoryContextSwitchTo(oldcontext);
@@ -1036,6 +1071,15 @@ variable_select(PG_FUNCTION_ARGS)
10361071

10371072
funcctx = SRF_PERCALL_SETUP();
10381073

1074+
if (funcctx->user_fctx == NULL)
1075+
{
1076+
/*
1077+
* VariableStatEntry was removed. For example, after call
1078+
* 'ROLLBACK TO SAVEPOINT ...'
1079+
*/
1080+
SRF_RETURN_DONE(funcctx);
1081+
}
1082+
10391083
/* Get next hash record */
10401084
rstat = (HASH_SEQ_STATUS *) funcctx->user_fctx;
10411085
item = (HashRecordEntry *) hash_seq_search(rstat);
@@ -1672,6 +1716,7 @@ get_packages_stats(PG_FUNCTION_ARGS)
16721716
#ifdef PGPRO_EE
16731717
entry->levels.atxlevel = getNestLevelATX();
16741718
#endif
1719+
entry->user_fctx = &funcctx->user_fctx;
16751720
packages_stats = lcons((void *) entry, packages_stats);
16761721
MemoryContextSwitchTo(ctx);
16771722
}

sql/pg_variables_trans.sql

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,3 +1169,25 @@ SELECT pgv_free();
11691169
-- Test case for issue #38 [PGPRO-4676]
11701170
--
11711171
SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE);
1172+
1173+
--
1174+
-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor
1175+
-- creation.
1176+
--
1177+
BEGIN;
1178+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true);
1179+
DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x');
1180+
SAVEPOINT sp1;
1181+
FETCH 1 in r1_cur;
1182+
ROLLBACK TO SAVEPOINT sp1;
1183+
FETCH 1 in r1_cur;
1184+
ROLLBACK;
1185+
1186+
BEGIN;
1187+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE);
1188+
DECLARE r1_cur CURSOR FOR SELECT pgv_stats();
1189+
SAVEPOINT sp1;
1190+
FETCH 1 in r1_cur;
1191+
ROLLBACK TO SAVEPOINT sp1;
1192+
FETCH 1 in r1_cur;
1193+
ROLLBACK;

0 commit comments

Comments
 (0)