Re: ESQL/C FETCH of CHAR data delivers to much data for UTF-8

Olivier Gautherot <[email protected]> Fri, 10 Jan 2020 13:32:57 +0100
Newsgroups gmane.comp.db.postgresql.general
Message-ID <CAJ7S9TWosuMTy-b5Bfd0JwtpgtM=uCVOXFrW8erJZQt9_KOtWQ@mail.gmail.com>
--0000000000000269c7059bc8541e
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hi Matthias,

On Thu, Jan 9, 2020, 20:21 Matthias Apitz <[email protected]> wrote:

> Hello,
>
> We encounter the following problem with ESQL/C: Imagine a table with two
> columns: CHAR(16) and DATE
>
> The CHAR column can contain not only 16 bytes, but 16 Unicode chars,
> which are longer than 16 bytes if one or more of the chars is a UTF-8
> multibyte
> encoded.
>
> If one provides in C a host structure to FETCH the data as:
>
> EXEC SQL BEGIN DECLARE SECTION;
> struct  r_d02ben_ec {
>         char    string[17];
>         char    date[11];
> };
> typedef struct r_d02ben_ec t_d02ben_ec;
> t_d02ben_ec *hp_d02ben, hrec_d02ben;
> EXEC SQL END DECLARE SECTION;
>
> and fetches the data with ESQL/C as:
>
> EXEC SQL FETCH hc_d02ben INTO :hrec_d02ben;
>
> The generated C-code looks like this:
>
>     ...
>     ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch hc_d02ben",
> ECPGt_EOIT,
>         ECPGt_char,&(hrec_d02ben.string),(long)17,(long)1,sizeof( struct
> r_d02ben_ec ),
>         ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
>         ECPGt_char,&(hrec_d02ben.date),(long)11,(long)1,sizeof( struct
> r_d02ben_ec ),
>         ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
>         ...
>
> As you can see for the first item the length 17 is sent to the PG server
> together with the pointer to where the data should be stored
> and for the second element the length 11 is sent (which is big enough to
> receive in ASCII MM.DD.YYYY and a trailing \0).
>
> What we now see using GDB is that for the first element all UTF-8 data
> is returned, lets asume only one multibyte char, which gives 17 bytes,
> not only 16, and the trailing NULL is already placed into the element for
> the date. Now the function ECPGdo() returns the date as MM.DD.YYYY
> into the area pointed to for the 2nd element and with this overwrites
> the NULL terminator of the string[17] element. Result is later a
> SIGSEGV because the expected string in string[17] is not NULL
> terminated anymore :-)
>
> I would call it a bug, that ECPGdo() puts more than 17 bytes (16 bytes +
> NULL) as return into the place pointed to by the host var pointer when
> the column in the database has more (UTF-8) chars as will fit into
> 16+1 byte.
>
> Comments?
> Proposals for a solution?
>
> Thanks
>
>         matthias
>
>
> --
> Matthias Apitz, =E2=9C=89 [email protected], http://www.unixarea.de/
> +49-176-38902045
> Public GnuPG key: http://www.unixarea.de/key.pub
>


I would be cautious about naming this a bug as it is a classical buffer
overflow (i.e. design) issue: if you have UTF-8 characters, your text is no
longer 16-byte long and you should plan extra space in your variables.

--0000000000000269c7059bc8541e
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto"><div>Hi Matthias,<br><br><div class=3D"gmail_quote"><div =
dir=3D"ltr" class=3D"gmail_attr">On Thu, Jan 9, 2020, 20:21 Matthias Apitz =
&lt;<a href=3D"mailto:[email protected]">[email protected]</a>&gt; wrote:<br>=
</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l=
eft:1px #ccc solid;padding-left:1ex">Hello,<br>
<br>
We encounter the following problem with ESQL/C: Imagine a table with two<br=
>
columns: CHAR(16) and DATE<br>
<br>
The CHAR column can contain not only 16 bytes, but 16 Unicode chars,<br>
which are longer than 16 bytes if one or more of the chars is a UTF-8 multi=
byte<br>
encoded.<br>
<br>
If one provides in C a host structure to FETCH the data as:<br>
<br>
EXEC SQL BEGIN DECLARE SECTION;<br>
struct=C2=A0 r_d02ben_ec {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 char=C2=A0 =C2=A0 string[17];<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 char=C2=A0 =C2=A0 date[11];<br>
};<br>
typedef struct r_d02ben_ec t_d02ben_ec;<br>
t_d02ben_ec *hp_d02ben, hrec_d02ben;<br>
EXEC SQL END DECLARE SECTION;<br>
<br>
and fetches the data with ESQL/C as:<br>
<br>
EXEC SQL FETCH hc_d02ben INTO :hrec_d02ben;<br>
<br>
The generated C-code looks like this:<br>
<br>
=C2=A0 =C2=A0 ...<br>
=C2=A0 =C2=A0 ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, &quot;fetch hc=
_d02ben&quot;, ECPGt_EOIT,<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ECPGt_char,&amp;(hrec_d02ben.string),(long)17,(=
long)1,sizeof( struct r_d02ben_ec ),<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ECPGt_char,&amp;(hrec_d02ben.date),(long)11,(lo=
ng)1,sizeof( struct r_d02ben_ec ),<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ...<br>
<br>
As you can see for the first item the length 17 is sent to the PG server<br=
>
together with the pointer to where the data should be stored<br>
and for the second element the length 11 is sent (which is big enough to<br=
>
receive in ASCII MM.DD.YYYY and a trailing \0).<br>
<br>
What we now see using GDB is that for the first element all UTF-8 data<br>
is returned, lets asume only one multibyte char, which gives 17 bytes,<br>
not only 16, and the trailing NULL is already placed into the element for<b=
r>
the date. Now the function ECPGdo() returns the date as MM.DD.YYYY<br>
into the area pointed to for the 2nd element and with this overwrites<br>
the NULL terminator of the string[17] element. Result is later a<br>
SIGSEGV because the expected string in string[17] is not NULL<br>
terminated anymore :-)<br>
<br>
I would call it a bug, that ECPGdo() puts more than 17 bytes (16 bytes +<br=
>
NULL) as return into the place pointed to by the host var pointer when<br>
the column in the database has more (UTF-8) chars as will fit into<br>
16+1 byte.<br>
<br>
Comments?<br>
Proposals for a solution?<br>
<br>
Thanks <br>
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 matthias<br>
<br>
<br>
-- <br>
Matthias Apitz, =E2=9C=89 <a href=3D"mailto:[email protected]" target=3D"_bl=
ank" rel=3D"noreferrer">[email protected]</a>, <a href=3D"http://www.unixare=
a.de/" rel=3D"noreferrer noreferrer" target=3D"_blank">http://www.unixarea.=
de/</a> +49-176-38902045<br>
Public GnuPG key: <a href=3D"http://www.unixarea.de/key.pub" rel=3D"norefer=
rer noreferrer" target=3D"_blank">http://www.unixarea.de/key.pub</a><br></b=
lockquote></div></div><div dir=3D"auto"><br></div><div dir=3D"auto"><br></d=
iv><div dir=3D"auto">I would be cautious about naming this a bug as it is a=
 classical buffer overflow (i.e. design) issue: if you have UTF-8 character=
s, your text is no longer 16-byte long and you should plan extra space in y=
our variables.=C2=A0</div><div dir=3D"auto"><br></div><div dir=3D"auto"></d=
iv></div>

--0000000000000269c7059bc8541e--