From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS22989 209.51.188.0/24 X-Spam-Status: No, score=-3.4 required=3.0 tests=AWL,BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id 4AD281F8C6 for ; Fri, 27 Aug 2021 22:28:24 +0000 (UTC) Received: from localhost ([::1]:38020 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mJkKj-00044o-4A for normalperson@yhbt.net; Fri, 27 Aug 2021 18:28:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:41198) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mJkKY-00044f-Ft for bug-gnulib@gnu.org; Fri, 27 Aug 2021 18:28:10 -0400 Received: from zimbra.cs.ucla.edu ([131.179.128.68]:34372) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mJkKU-00065R-TH for bug-gnulib@gnu.org; Fri, 27 Aug 2021 18:28:09 -0400 Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 68AC71600DB for ; Fri, 27 Aug 2021 15:28:04 -0700 (PDT) Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id a6lllZdkDtqr; Fri, 27 Aug 2021 15:27:59 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 8ED6A1600CC; Fri, 27 Aug 2021 15:27:59 -0700 (PDT) X-Virus-Scanned: amavisd-new at zimbra.cs.ucla.edu Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id OAHlGtSUT4Go; Fri, 27 Aug 2021 15:27:59 -0700 (PDT) Received: from penguin.cs.ucla.edu (Penguin.CS.UCLA.EDU [131.179.64.200]) by zimbra.cs.ucla.edu (Postfix) with ESMTPSA id 592A8160084; Fri, 27 Aug 2021 15:27:59 -0700 (PDT) From: Paul Eggert To: bug-gnulib@gnu.org Subject: [PATCH] base32, base64: prefer signed to unsigned integers Date: Fri, 27 Aug 2021 15:27:56 -0700 Message-Id: <20210827222756.530247-1-eggert@cs.ucla.edu> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass client-ip=131.179.128.68; envelope-from=eggert@cs.ucla.edu; helo=zimbra.cs.ucla.edu X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: bug-gnulib@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Gnulib discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paul Eggert Errors-To: bug-gnulib-bounces+normalperson=yhbt.net@gnu.org Sender: "bug-gnulib" * lib/base32.c, lib/base64.c: Include ialloc.h instad of stdlib.h. Include intprops.h, verify.h. * lib/base32.c (base32_encode, base32_encode_alloc, get_8, decode_8) (base32_decode_ctx, base32_decode_alloc_ctx): * lib/base32.h (struct base32_decode_context): * lib/base64.c (base64_encode_fast, base64_encode) (base64_encode_alloc, get_4, decode_4, base64_decode_ctx) (base64_decode_alloc_ctx): * lib/base64.h (struct base64_decode_context): * tests/test-base32.c (main): * tests/test-base64.c (main): Prefer signed to unsigned integers. * lib/base32.c (base32_encode_alloc): * lib/base64.c (base64_encode_alloc): Use simpler and more-direct check for overflow, removing a TODO. * lib/base32.h, lib/base64.h: Include idx.h instead of stddef.h. * modules/base32, modules/base64 (Depends-on): Add ialloc, verify. --- ChangeLog | 21 ++++++++++++++ NEWS | 3 ++ lib/base32.c | 61 ++++++++++++++++++++------------------- lib/base32.h | 20 ++++++------- lib/base64.c | 69 ++++++++++++++++++++------------------------- lib/base64.h | 20 ++++++------- modules/base32 | 2 ++ modules/base64 | 2 ++ tests/test-base32.c | 2 +- tests/test-base64.c | 2 +- 10 files changed, 111 insertions(+), 91 deletions(-) diff --git a/ChangeLog b/ChangeLog index adfbcf3e21..498525a242 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2021-08-27 Paul Eggert + + base32, base64: prefer signed to unsigned integers + * lib/base32.c, lib/base64.c: Include ialloc.h instad of stdlib.h. + Include intprops.h, verify.h. + * lib/base32.c (base32_encode, base32_encode_alloc, get_8, decode_8) + (base32_decode_ctx, base32_decode_alloc_ctx): + * lib/base32.h (struct base32_decode_context): + * lib/base64.c (base64_encode_fast, base64_encode) + (base64_encode_alloc, get_4, decode_4, base64_decode_ctx) + (base64_decode_alloc_ctx): + * lib/base64.h (struct base64_decode_context): + * tests/test-base32.c (main): + * tests/test-base64.c (main): + Prefer signed to unsigned integers. + * lib/base32.c (base32_encode_alloc): + * lib/base64.c (base64_encode_alloc): + Use simpler and more-direct check for overflow, removing a TODO. + * lib/base32.h, lib/base64.h: Include idx.h instead of stddef.h. + * modules/base32, modules/base64 (Depends-on): Add ialloc, verify. + 2021-08-26 Paul Eggert =20 regex: use __attr_access and C99-style array arg diff --git a/NEWS b/NEWS index e0f0d836c2..2ce1c73014 100644 --- a/NEWS +++ b/NEWS @@ -66,6 +66,9 @@ User visible incompatible changes =20 Date Modules Changes =20 +2021-08-27 base32 These modules now use idx_t instead of size_= t + base64 for indexes and counts. + 2021-07-29 (all) Due to draft C2x, the following attributes s= hould now appear at the start of a function declar= ation: _GL_ATTRIBUTE_DEPRECATED diff --git a/lib/base32.c b/lib/base32.c index 75d0b296fd..e8feaf1663 100644 --- a/lib/base32.c +++ b/lib/base32.c @@ -28,7 +28,7 @@ * FAIL: memory allocation error * OK: data in OUT/OUTLEN * - * size_t outlen =3D base32_encode_alloc (in, inlen, &out); + * idx_t outlen =3D base32_encode_alloc (in, inlen, &out); * if (out =3D=3D NULL && outlen =3D=3D 0 && inlen !=3D 0) * FAIL: input too long * if (out =3D=3D NULL) @@ -42,15 +42,18 @@ /* Get prototype. */ #include "base32.h" =20 -/* Get malloc. */ -#include +/* Get imalloc. */ +#include + +#include +#include =20 /* Get UCHAR_MAX. */ #include =20 #include =20 -/* C89 compliant way to cast 'char' to 'unsigned char'. */ +/* Convert 'char' to 'unsigned char' without casting. */ static unsigned char to_uchar (char ch) { @@ -62,8 +65,8 @@ to_uchar (char ch) possible. If OUTLEN is larger than BASE32_LENGTH(INLEN), also zero terminate the output buffer. */ void -base32_encode (const char *restrict in, size_t inlen, - char *restrict out, size_t outlen) +base32_encode (const char *restrict in, idx_t inlen, + char *restrict out, idx_t outlen) { static const char b32str[32] =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; @@ -136,24 +139,20 @@ base32_encode (const char *restrict in, size_t inle= n, memory allocation failed, OUT is set to NULL, and the return value indicates length of the requested memory block, i.e., BASE32_LENGTH(inlen) + 1. */ -size_t -base32_encode_alloc (const char *in, size_t inlen, char **out) +idx_t +base32_encode_alloc (const char *in, idx_t inlen, char **out) { - size_t outlen =3D 1 + BASE32_LENGTH (inlen); - - /* Check for overflow in outlen computation. - * - * If there is no overflow, outlen >=3D inlen. - * - * TODO Is this a sufficient check? (See the notes in base64.c.) - */ - if (inlen > outlen) + /* Check for overflow in outlen computation. */ + assume (0 <=3D inlen); + idx_t in_over_5 =3D inlen / 5 + (inlen % 5 !=3D 0), outlen; + if (! INT_MULTIPLY_OK (in_over_5, 8, &outlen)) { *out =3D NULL; return 0; } + outlen++; =20 - *out =3D malloc (outlen); + *out =3D imalloc (outlen); if (!*out) return outlen; =20 @@ -305,7 +304,7 @@ base32_decode_ctx_init (struct base32_decode_context = *ctx) static char * get_8 (struct base32_decode_context *ctx, char const *restrict *in, char const *restrict in_end, - size_t *n_non_newline) + idx_t *n_non_newline) { if (ctx->i =3D=3D 8) ctx->i =3D 0; @@ -357,14 +356,14 @@ get_8 (struct base32_decode_context *ctx, *OUT to point to the byte after the last one written, and decrement *OUTLEN to reflect the number of bytes remaining in *OUT. */ static bool -decode_8 (char const *restrict in, size_t inlen, - char *restrict *outp, size_t *outleft) +decode_8 (char const *restrict in, idx_t inlen, + char *restrict *outp, idx_t *outleft) { char *out =3D *outp; if (inlen < 8) return false; =20 - if (!isbase32 (in[0]) || !isbase32 (in[1]) ) + if (!isbase32 (in[0]) || !isbase32 (in[1])) return false; =20 if (*outleft) @@ -468,10 +467,10 @@ decode_8 (char const *restrict in, size_t inlen, =20 bool base32_decode_ctx (struct base32_decode_context *ctx, - const char *restrict in, size_t inlen, - char *restrict out, size_t *outlen) + const char *restrict in, idx_t inlen, + char *restrict out, idx_t *outlen) { - size_t outleft =3D *outlen; + idx_t outleft =3D *outlen; bool ignore_newlines =3D ctx !=3D NULL; bool flush_ctx =3D false; unsigned int ctx_i =3D 0; @@ -485,7 +484,7 @@ base32_decode_ctx (struct base32_decode_context *ctx, =20 while (true) { - size_t outleft_save =3D outleft; + idx_t outleft_save =3D outleft; if (ctx_i =3D=3D 0 && !flush_ctx) { while (true) @@ -559,17 +558,17 @@ base32_decode_ctx (struct base32_decode_context *ct= x, undefined. */ bool base32_decode_alloc_ctx (struct base32_decode_context *ctx, - const char *in, size_t inlen, char **out, - size_t *outlen) + const char *in, idx_t inlen, char **out, + idx_t *outlen) { /* This may allocate a few bytes too many, depending on input, but it's not worth the extra CPU time to compute the exact size. The exact size is 5 * inlen / 8, minus one or more bytes if the input is padded with one or more "=3D". - Dividing before multiplying avoids the possibility of overflow. */ - size_t needlen =3D 5 * (inlen / 8) + 5; + Shifting before multiplying avoids the possibility of overflow. */ + idx_t needlen =3D 5 * ((inlen >> 3) + 1); =20 - *out =3D malloc (needlen); + *out =3D imalloc (needlen); if (!*out) return true; =20 diff --git a/lib/base32.h b/lib/base32.h index f65e55b0fe..108a5ecd38 100644 --- a/lib/base32.h +++ b/lib/base32.h @@ -18,8 +18,8 @@ #ifndef BASE32_H # define BASE32_H =20 -/* Get size_t. */ -# include +/* Get idx_t. */ +# include =20 /* Get bool. */ # include @@ -30,26 +30,26 @@ =20 struct base32_decode_context { - unsigned int i; + int i; char buf[8]; }; =20 extern bool isbase32 (char ch) _GL_ATTRIBUTE_CONST; =20 -extern void base32_encode (const char *restrict in, size_t inlen, - char *restrict out, size_t outlen); +extern void base32_encode (const char *restrict in, idx_t inlen, + char *restrict out, idx_t outlen); =20 -extern size_t base32_encode_alloc (const char *in, size_t inlen, char **= out); +extern idx_t base32_encode_alloc (const char *in, idx_t inlen, char **ou= t); =20 extern void base32_decode_ctx_init (struct base32_decode_context *ctx); =20 extern bool base32_decode_ctx (struct base32_decode_context *ctx, - const char *restrict in, size_t inlen, - char *restrict out, size_t *outlen); + const char *restrict in, idx_t inlen, + char *restrict out, idx_t *outlen); =20 extern bool base32_decode_alloc_ctx (struct base32_decode_context *ctx, - const char *in, size_t inlen, - char **out, size_t *outlen); + const char *in, idx_t inlen, + char **out, idx_t *outlen); =20 #define base32_decode(in, inlen, out, outlen) \ base32_decode_ctx (NULL, in, inlen, out, outlen) diff --git a/lib/base64.c b/lib/base64.c index 7a6e7af5fc..2a01ed34e9 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -30,7 +30,7 @@ * FAIL: memory allocation error * OK: data in OUT/OUTLEN * - * size_t outlen =3D base64_encode_alloc (in, inlen, &out); + * idx_t outlen =3D base64_encode_alloc (in, inlen, &out); * if (out =3D=3D NULL && outlen =3D=3D 0 && inlen !=3D 0) * FAIL: input too long * if (out =3D=3D NULL) @@ -44,15 +44,18 @@ /* Get prototype. */ #include "base64.h" =20 -/* Get malloc. */ -#include +/* Get imalloc. */ +#include + +#include +#include =20 /* Get UCHAR_MAX. */ #include =20 #include =20 -/* C89 compliant way to cast 'char' to 'unsigned char'. */ +/* Convert 'char' to 'unsigned char' without casting. */ static unsigned char to_uchar (char ch) { @@ -66,7 +69,7 @@ static const char b64c[64] =3D to be of length >=3D BASE64_LENGTH(INLEN), and INLEN needs to be a multiple of 3. */ static void -base64_encode_fast (const char *restrict in, size_t inlen, char *restric= t out) +base64_encode_fast (const char *restrict in, idx_t inlen, char *restrict= out) { while (inlen) { @@ -85,8 +88,8 @@ base64_encode_fast (const char *restrict in, size_t inl= en, char *restrict out) possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero terminate the output buffer. */ void -base64_encode (const char *restrict in, size_t inlen, - char *restrict out, size_t outlen) +base64_encode (const char *restrict in, idx_t inlen, + char *restrict out, idx_t outlen) { /* Note this outlen constraint can be enforced at compile time. I.E. that the output buffer is exactly large enough to hold @@ -95,7 +98,7 @@ base64_encode (const char *restrict in, size_t inlen, at the end of input. However the common case when reading large inputs is to have both constraints satisfied, so we depend on both in base_encode_fast(). */ - if (outlen % 4 =3D=3D 0 && inlen =3D=3D outlen / 4 * 3) + if (outlen % 4 =3D=3D 0 && inlen =3D=3D (outlen >> 2) * 3) { base64_encode_fast (in, inlen, out); return; @@ -141,30 +144,20 @@ base64_encode (const char *restrict in, size_t inle= n, memory allocation failed, OUT is set to NULL, and the return value indicates length of the requested memory block, i.e., BASE64_LENGTH(inlen) + 1. */ -size_t -base64_encode_alloc (const char *in, size_t inlen, char **out) +idx_t +base64_encode_alloc (const char *in, idx_t inlen, char **out) { - size_t outlen =3D 1 + BASE64_LENGTH (inlen); - - /* Check for overflow in outlen computation. - * - * If there is no overflow, outlen >=3D inlen. - * - * If the operation (inlen + 2) overflows then it yields at most +1, s= o - * outlen is 0. - * - * If the multiplication overflows, we lose at least half of the - * correct value, so the result is < ((inlen + 2) / 3) * 2, which is - * less than (inlen + 2) * 0.66667, which is less than inlen as soon a= s - * (inlen > 4). - */ - if (inlen > outlen) + /* Check for overflow in outlen computation. */ + assume (0 <=3D inlen); + idx_t in_over_3 =3D inlen / 3 + (inlen % 3 !=3D 0), outlen; + if (! INT_MULTIPLY_OK (in_over_3, 4, &outlen)) { *out =3D NULL; return 0; } + outlen++; =20 - *out =3D malloc (outlen); + *out =3D imalloc (outlen); if (!*out) return outlen; =20 @@ -348,7 +341,7 @@ base64_decode_ctx_init (struct base64_decode_context = *ctx) static char * get_4 (struct base64_decode_context *ctx, char const *restrict *in, char const *restrict in_end, - size_t *n_non_newline) + idx_t *n_non_newline) { if (ctx->i =3D=3D 4) ctx->i =3D 0; @@ -400,8 +393,8 @@ get_4 (struct base64_decode_context *ctx, *OUT to point to the byte after the last one written, and decrement *OUTLEN to reflect the number of bytes remaining in *OUT. */ static bool -decode_4 (char const *restrict in, size_t inlen, - char *restrict *outp, size_t *outleft) +decode_4 (char const *restrict in, idx_t inlen, + char *restrict *outp, idx_t *outleft) { char *out =3D *outp; if (inlen < 2) @@ -486,10 +479,10 @@ decode_4 (char const *restrict in, size_t inlen, =20 bool base64_decode_ctx (struct base64_decode_context *ctx, - const char *restrict in, size_t inlen, - char *restrict out, size_t *outlen) + const char *restrict in, idx_t inlen, + char *restrict out, idx_t *outlen) { - size_t outleft =3D *outlen; + idx_t outleft =3D *outlen; bool ignore_newlines =3D ctx !=3D NULL; bool flush_ctx =3D false; unsigned int ctx_i =3D 0; @@ -503,7 +496,7 @@ base64_decode_ctx (struct base64_decode_context *ctx, =20 while (true) { - size_t outleft_save =3D outleft; + idx_t outleft_save =3D outleft; if (ctx_i =3D=3D 0 && !flush_ctx) { while (true) @@ -577,17 +570,17 @@ base64_decode_ctx (struct base64_decode_context *ct= x, undefined. */ bool base64_decode_alloc_ctx (struct base64_decode_context *ctx, - const char *in, size_t inlen, char **out, - size_t *outlen) + const char *in, idx_t inlen, char **out, + idx_t *outlen) { /* This may allocate a few bytes too many, depending on input, but it's not worth the extra CPU time to compute the exact size. The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if = the input ends with "=3D" and minus another 1 if the input ends with "=3D= =3D". - Dividing before multiplying avoids the possibility of overflow. */ - size_t needlen =3D 3 * (inlen / 4) + 3; + Shifting before multiplying avoids the possibility of overflow. */ + idx_t needlen =3D 3 * ((inlen >> 2) + 1); =20 - *out =3D malloc (needlen); + *out =3D imalloc (needlen); if (!*out) return true; =20 diff --git a/lib/base64.h b/lib/base64.h index e45f1db728..e58ccfb1fb 100644 --- a/lib/base64.h +++ b/lib/base64.h @@ -18,8 +18,8 @@ #ifndef BASE64_H # define BASE64_H =20 -/* Get size_t. */ -# include +/* Get idx_t. */ +# include =20 /* Get bool. */ # include @@ -34,26 +34,26 @@ extern "C" { =20 struct base64_decode_context { - unsigned int i; + int i; char buf[4]; }; =20 extern bool isbase64 (char ch) _GL_ATTRIBUTE_CONST; =20 -extern void base64_encode (const char *restrict in, size_t inlen, - char *restrict out, size_t outlen); +extern void base64_encode (const char *restrict in, idx_t inlen, + char *restrict out, idx_t outlen); =20 -extern size_t base64_encode_alloc (const char *in, size_t inlen, char **= out); +extern idx_t base64_encode_alloc (const char *in, idx_t inlen, char **ou= t); =20 extern void base64_decode_ctx_init (struct base64_decode_context *ctx); =20 extern bool base64_decode_ctx (struct base64_decode_context *ctx, - const char *restrict in, size_t inlen, - char *restrict out, size_t *outlen); + const char *restrict in, idx_t inlen, + char *restrict out, idx_t *outlen); =20 extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx, - const char *in, size_t inlen, - char **out, size_t *outlen); + const char *in, idx_t inlen, + char **out, idx_t *outlen); =20 #define base64_decode(in, inlen, out, outlen) \ base64_decode_ctx (NULL, in, inlen, out, outlen) diff --git a/modules/base32 b/modules/base32 index 20f38cf1a0..659081d7e3 100644 --- a/modules/base32 +++ b/modules/base32 @@ -7,8 +7,10 @@ lib/base32.c m4/base32.m4 =20 Depends-on: +ialloc stdbool memchr +verify =20 configure.ac: gl_FUNC_BASE32 diff --git a/modules/base64 b/modules/base64 index b1a3513b7d..717c0697d1 100644 --- a/modules/base64 +++ b/modules/base64 @@ -7,8 +7,10 @@ lib/base64.c m4/base64.m4 =20 Depends-on: +ialloc stdbool memchr +verify =20 configure.ac: gl_FUNC_BASE64 diff --git a/tests/test-base32.c b/tests/test-base32.c index 0f7a43894d..24c46567de 100644 --- a/tests/test-base32.c +++ b/tests/test-base32.c @@ -34,7 +34,7 @@ main (void) const char *in =3D "abcdefghijklmnop"; const char *b32in =3D "MFRGGZDFMZTWQ2LKNNWG23TPOA=3D=3D=3D=3D=3D=3D"; char out[255]; - size_t len; + idx_t len; bool ok; char *p; =20 diff --git a/tests/test-base64.c b/tests/test-base64.c index c16e50267e..bc75acd95f 100644 --- a/tests/test-base64.c +++ b/tests/test-base64.c @@ -33,7 +33,7 @@ main (void) const char *in =3D "abcdefghijklmnop"; const char *b64in =3D "YWJjZGVmZw=3D=3D"; char out[255]; - size_t len; + idx_t len; bool ok; char *p; =20 --=20 2.31.1