Skip to content

Commit 3ff660b

Browse files
committed
Fix off-by-one error in PGTYPEStimestamp_fmt_asc
When using %b or %B patterns to format a date, the code was simply using tm_mon as an index into array of month names. But that is wrong, because tm_mon is 1-based, while array indexes are 0-based. The result is we either use name of the next month, or a segfault (for December). Fix by subtracting 1 from tm_mon for both patterns, and add a regression test triggering the issue. Backpatch to all supported versions (the bug is there far longer, since at least 2003). Reported-by: Paul Spencer Backpatch-through: 9.4 Discussion: https://postgr.es/m/16143-0d861eb8688d3fef%40postgresql.org
1 parent 98a9b37 commit 3ff660b

File tree

5 files changed

+41
-7
lines changed

5 files changed

+41
-7
lines changed

src/interfaces/ecpg/pgtypeslib/timestamp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,13 +334,13 @@ dttofmtasc_replace(timestamp * ts, date dDate, int dow, struct tm *tm,
334334
/* XXX should be locale aware */
335335
case 'b':
336336
case 'h':
337-
replace_val.str_val = months[tm->tm_mon];
337+
replace_val.str_val = months[tm->tm_mon - 1];
338338
replace_type = PGTYPES_TYPE_STRING_CONSTANT;
339339
break;
340340
/* the full name of the month */
341341
/* XXX should be locale aware */
342342
case 'B':
343-
replace_val.str_val = pgtypes_date_months[tm->tm_mon];
343+
replace_val.str_val = pgtypes_date_months[tm->tm_mon - 1];
344344
replace_type = PGTYPES_TYPE_STRING_CONSTANT;
345345
break;
346346

src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -436,17 +436,33 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
436436
printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
437437
PGTYPESchar_free(text);
438438

439+
out = (char*) malloc(64);
440+
fmt = "%a %b %d %H:%M:%S %Y";
441+
in = "Mon Dec 30 17:28:44 2019";
442+
i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
443+
i = PGTYPEStimestamp_fmt_asc(&ts1, out, 63, fmt);
444+
printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, out, i);
445+
free(out);
446+
447+
out = (char*) malloc(64);
448+
fmt = "%a %b %d %H:%M:%S %Y";
449+
in = "Mon December 30 17:28:44 2019";
450+
i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
451+
i = PGTYPEStimestamp_fmt_asc(&ts1, out, 63, fmt);
452+
printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, out, i);
453+
free(out);
454+
439455
{ ECPGtrans(__LINE__, NULL, "rollback");
440-
#line 365 "dt_test.pgc"
456+
#line 381 "dt_test.pgc"
441457

442458
if (sqlca.sqlcode < 0) sqlprint ( );}
443-
#line 365 "dt_test.pgc"
459+
#line 381 "dt_test.pgc"
444460

445461
{ ECPGdisconnect(__LINE__, "CURRENT");
446-
#line 366 "dt_test.pgc"
462+
#line 382 "dt_test.pgc"
447463

448464
if (sqlca.sqlcode < 0) sqlprint ( );}
449-
#line 366 "dt_test.pgc"
465+
#line 382 "dt_test.pgc"
450466

451467

452468
return 0;

src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
[NO_PID]: sqlca: code: 0, state: 00000
4343
[NO_PID]: ecpg_get_data on line 38: RESULT: 2000-07-12 17:34:29 offset: -1; array: no
4444
[NO_PID]: sqlca: code: 0, state: 00000
45-
[NO_PID]: ECPGtrans on line 365: action "rollback"; connection "ecpg1_regression"
45+
[NO_PID]: ECPGtrans on line 381: action "rollback"; connection "ecpg1_regression"
4646
[NO_PID]: sqlca: code: 0, state: 00000
4747
[NO_PID]: ecpg_finish: connection ecpg1_regression closed
4848
[NO_PID]: sqlca: code: 0, state: 00000

src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stdout

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,5 @@ timestamp_defmt_asc( 1976, July 14. Time: 9:15am, %Y, %B %d. Time: %I:%M %p)
4848
timestamp_defmt_asc( 1976, July 14. Time: 9:15 am, %Y, %B %d. Time: %I:%M%p) = 1976-07-14 09:15:00, error: 0
4949
timestamp_defmt_asc( 1976, P.M. July 14. Time: 9:15, %Y, %P %B %d. Time: %I:%M) = 1976-07-14 21:15:00, error: 0
5050
timestamp_defmt_asc(1234567890, %s) = 2009-02-13 23:31:30, error: 0
51+
timestamp_defmt_asc(Mon Dec 30 17:28:44 2019, %a %b %d %H:%M:%S %Y) = Mon Dec 30 17:28:44 2019, error: 0
52+
timestamp_defmt_asc(Mon December 30 17:28:44 2019, %a %b %d %H:%M:%S %Y) = Mon Dec 30 17:28:44 2019, error: 0

src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,22 @@ main(void)
362362
printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
363363
PGTYPESchar_free(text);
364364

365+
out = (char*) malloc(64);
366+
fmt = "%a %b %d %H:%M:%S %Y";
367+
in = "Mon Dec 30 17:28:44 2019";
368+
i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
369+
i = PGTYPEStimestamp_fmt_asc(&ts1, out, 63, fmt);
370+
printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, out, i);
371+
free(out);
372+
373+
out = (char*) malloc(64);
374+
fmt = "%a %b %d %H:%M:%S %Y";
375+
in = "Mon December 30 17:28:44 2019";
376+
i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
377+
i = PGTYPEStimestamp_fmt_asc(&ts1, out, 63, fmt);
378+
printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, out, i);
379+
free(out);
380+
365381
exec sql rollback;
366382
exec sql disconnect;
367383

0 commit comments

Comments
 (0)