ecpg: Fix zero-termination of string generated by intoasc()
authorMichael Paquier <michael@paquier.xyz>
Mon, 19 Feb 2024 02:38:18 +0000 (11:38 +0900)
committerMichael Paquier <michael@paquier.xyz>
Mon, 19 Feb 2024 02:38:18 +0000 (11:38 +0900)
intoasc(), a wrapper for PGTYPESinterval_to_asc that converts an
interval to its textual representation, used a plain memcpy() when
copying its result.  This could miss a zero-termination in the result
string, leading to an incorrect result.

The routines in informix.c do not provide the length of their result
buffer, which would allow a replacement of strcpy() to safer strlcpy()
calls, but this requires an ABI breakage and that cannot happen in
back-branches.

Author: Oleg Tselebrovskiy
Reviewed-by: Ashutosh Bapat
Discussion: https://postgr.es/m/bf47888585149f83b276861a1662f7e4@postgrespro.ru
Backpatch-through: 12

src/interfaces/ecpg/compatlib/informix.c
src/interfaces/ecpg/test/compat_informix/.gitignore
src/interfaces/ecpg/test/compat_informix/Makefile
src/interfaces/ecpg/test/compat_informix/intoasc.pgc [new file with mode: 0644]
src/interfaces/ecpg/test/compat_informix/meson.build
src/interfaces/ecpg/test/ecpg_schedule
src/interfaces/ecpg/test/expected/compat_informix-intoasc.c [new file with mode: 0644]
src/interfaces/ecpg/test/expected/compat_informix-intoasc.stderr [new file with mode: 0644]
src/interfaces/ecpg/test/expected/compat_informix-intoasc.stdout [new file with mode: 0644]

index dccf39582da55c0cbe246dd1c6bbd80574a8f5bf..80d40aa3e09b2c8526f6fdf3148791589ae363b6 100644 (file)
@@ -654,7 +654,7 @@ intoasc(interval * i, char *str)
    if (!tmp)
        return -errno;
 
-   memcpy(str, tmp, strlen(tmp));
+   strcpy(str, tmp);
    free(tmp);
    return 0;
 }
index f97706ba4bee037dd4bd3d3f4939d269c8971c92..6967ae77cd2dddf4bf5d4820e35436aef806a4be 100644 (file)
@@ -4,6 +4,8 @@
 /dec_test.c
 /describe
 /describe.c
+/intoasc
+/intoasc.c
 /rfmtdate
 /rfmtdate.c
 /rfmtlong
index d50fdc29fd1c0044fed6e4756bf321cc716cb788..638b4e0af7820703664236b15605e724eb83748e 100644 (file)
@@ -16,7 +16,8 @@ TESTS = test_informix test_informix.c \
         rnull rnull.c \
         sqlda sqlda.c \
         describe describe.c \
-        charfuncs charfuncs.c
+        charfuncs charfuncs.c \
+        intoasc intoasc.c
 
 all: $(TESTS)
 
diff --git a/src/interfaces/ecpg/test/compat_informix/intoasc.pgc b/src/interfaces/ecpg/test/compat_informix/intoasc.pgc
new file mode 100644 (file)
index 0000000..d13c83b
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pgtypes_interval.h"
+
+EXEC SQL BEGIN DECLARE SECTION;
+    char dirty_str[100] = "aaaaaaaaa_bbbbbbbb_ccccccccc_ddddddddd_";
+    interval *interval_ptr;
+EXEC SQL END DECLARE SECTION;
+
+int main()
+{
+    interval_ptr = (interval *) malloc(sizeof(interval));
+    interval_ptr->time = 100000000;
+    interval_ptr->month = 240;
+
+    printf("dirty_str contents before intoasc: %s\n", dirty_str);
+    intoasc(interval_ptr, dirty_str);
+    printf("dirty_str contents after intoasc: %s\n", dirty_str);
+    return 0;
+}
index ab617b6db0de3811ce2df79649c0cda562da1c10..c6ed52f51c55717aa738b649664f620afd169b90 100644 (file)
@@ -4,6 +4,7 @@ pgc_files = [
   'charfuncs',
   'dec_test',
   'describe',
+  'intoasc',
   'rfmtdate',
   'rfmtlong',
   'rnull',
index 39814a39c1767b561449088c89e925a4727e4641..f9c0a0e3c00ffe0bb1ec30f5a21d7aec3d1cc09b 100644 (file)
@@ -7,6 +7,7 @@ test: compat_informix/sqlda
 test: compat_informix/describe
 test: compat_informix/test_informix
 test: compat_informix/test_informix2
+test: compat_informix/intoasc
 test: compat_oracle/char_array
 test: connect/test2
 test: connect/test3
diff --git a/src/interfaces/ecpg/test/expected/compat_informix-intoasc.c b/src/interfaces/ecpg/test/expected/compat_informix-intoasc.c
new file mode 100644 (file)
index 0000000..3098880
--- /dev/null
@@ -0,0 +1,40 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* Needed for informix compatibility */
+#include <ecpg_informix.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "intoasc.pgc"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pgtypes_interval.h"
+
+/* exec sql begin declare section */
+       
+     
+
+#line 7 "intoasc.pgc"
+ char dirty_str [ 100 ] = "aaaaaaaaa_bbbbbbbb_ccccccccc_ddddddddd_" ;
+#line 8 "intoasc.pgc"
+ interval * interval_ptr ;
+/* exec sql end declare section */
+#line 9 "intoasc.pgc"
+
+
+int main()
+{
+    interval_ptr = (interval *) malloc(sizeof(interval));
+    interval_ptr->time = 100000000;
+    interval_ptr->month = 240;
+
+    printf("dirty_str contents before intoasc: %s\n", dirty_str);
+    intoasc(interval_ptr, dirty_str);
+    printf("dirty_str contents after intoasc: %s\n", dirty_str);
+    return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/compat_informix-intoasc.stderr b/src/interfaces/ecpg/test/expected/compat_informix-intoasc.stderr
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/interfaces/ecpg/test/expected/compat_informix-intoasc.stdout b/src/interfaces/ecpg/test/expected/compat_informix-intoasc.stdout
new file mode 100644 (file)
index 0000000..0769465
--- /dev/null
@@ -0,0 +1,2 @@
+dirty_str contents before intoasc: aaaaaaaaa_bbbbbbbb_ccccccccc_ddddddddd_
+dirty_str contents after intoasc: @ 20 years 1 min 40 secs