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 = <<a href=3D"mailto:[email protected]">[email protected]</a>> 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, "fetch hc= _d02ben", ECPGt_EOIT,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 ECPGt_char,&(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,&(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--