From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=MAILING_LIST_MULTI, RCVD_IN_MSPIKE_H2 autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 25145 invoked from network); 22 Mar 2023 16:56:50 -0000 Received: from second.openwall.net (193.110.157.125) by inbox.vuxu.org with ESMTPUTF8; 22 Mar 2023 16:56:50 -0000 Received: (qmail 5695 invoked by uid 550); 22 Mar 2023 16:56:47 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: musl@lists.openwall.com Received: (qmail 5654 invoked from network); 22 Mar 2023 16:56:46 -0000 Date: Wed, 22 Mar 2023 12:56:34 -0400 From: Rich Felker To: Bruno Haible Cc: musl@lists.openwall.com Message-ID: <20230322165629.GY4163@brightrain.aerifal.cx> References: <15375070.O9o76ZdvQC@nimes> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <15375070.O9o76ZdvQC@nimes> User-Agent: Mutt/1.5.21 (2010-09-15) Subject: Re: [musl] swprintf produces garbage after a null wide character On Wed, Mar 22, 2023 at 05:24:18PM +0100, Bruno Haible wrote: > When swprintf is meant to produce output with a null wide character, in > musl libc 1.2.3, it produces a correct return value, but fills the entire > destination buffer with null wide characters. I.e. in this case, the number > of written wide characters is larger than the return value + 1. > > How to reproduce: > ==================================== foo.c ==================================== > #include > #include > > int main () > { > { > wchar_t buf[5] = { 0xBEEF, 0xBEEF, 0xBEEF, 0xBEEF, 0xBEEF }; > int ret = swprintf (buf, 4, L"%c", '\0'); > printf ("ret = %d, buf[0] = 0x%x, buf[1] = 0x%x, buf[2] = 0x%x, buf[3] = 0x%x, buf[4] = 0x%x\n", > ret, > (unsigned int) buf[0], (unsigned int) buf[1], > (unsigned int) buf[2], (unsigned int) buf[3], > (unsigned int) buf[4]); > } > { > wchar_t buf[5] = { 0xBEEF, 0xBEEF, 0xBEEF, 0xBEEF, 0xBEEF }; > int ret = swprintf (buf, 4, L"%cz", '\0'); > printf ("ret = %d, buf[0] = 0x%x, buf[1] = 0x%x, buf[2] = 0x%x, buf[3] = 0x%x, buf[4] = 0x%x\n", > ret, > (unsigned int) buf[0], (unsigned int) buf[1], > (unsigned int) buf[2], (unsigned int) buf[3], > (unsigned int) buf[4]); > } > return 0; > } > /* > glibc, Solaris 11, Cygwin: > ret = 1, buf[0] = 0x0, buf[1] = 0x0, buf[2] = 0xbeef, buf[3] = 0xbeef, buf[4] = 0xbeef > ret = 2, buf[0] = 0x0, buf[1] = 0x7a, buf[2] = 0x0, buf[3] = 0xbeef, buf[4] = 0xbeef > musl libc: > ret = 1, buf[0] = 0x0, buf[1] = 0x0, buf[2] = 0x0, buf[3] = 0x0, buf[4] = 0xbeef > ret = 2, buf[0] = 0x0, buf[1] = 0x0, buf[2] = 0x0, buf[3] = 0x0, buf[4] = 0xbeef > FreeBSD 13, NetBSD 9, OpenBSD 7.2, macOS 12.5, AIX 7.1: > ret = 1, buf[0] = 0x0, buf[1] = 0xbeef, buf[2] = 0xbeef, buf[3] = 0xbeef, buf[4] = 0xbeef > ret = 2, buf[0] = 0x0, buf[1] = 0xbeef, buf[2] = 0xbeef, buf[3] = 0xbeef, buf[4] = 0xbeef > */ > =============================================================================== > > $ gcc -Wall foo.c > $ ./a.out > > Expected output: > ret = 1, buf[0] = 0x0, buf[1] = 0x0, buf[2] = 0xbeef, buf[3] = 0xbeef, buf[4] = 0xbeef > ret = 2, buf[0] = 0x0, buf[1] = 0x7a, buf[2] = 0x0, buf[3] = 0xbeef, buf[4] = 0xbeef > > Actual output: > ret = 1, buf[0] = 0x0, buf[1] = 0x0, buf[2] = 0x0, buf[3] = 0x0, buf[4] = 0xbeef > ret = 2, buf[0] = 0x0, buf[1] = 0x0, buf[2] = 0x0, buf[3] = 0x0, buf[4] = 0xbeef Thanks. This one is an easy one-line fix. Caught by the bad mbtowc behavior of returning 0 rather than 1 when converting a nul character (thereby not advancing past it in the buffer). Rich