* 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-27 Paul Eggert <eggert@cs.ucla.edu>
+
+ 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 <eggert@cs.ucla.edu>
regex: use __attr_access and C99-style array arg
Date Modules Changes
+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 should
now appear at the start of a function declaration:
_GL_ATTRIBUTE_DEPRECATED
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN
*
- * size_t outlen = base32_encode_alloc (in, inlen, &out);
+ * idx_t outlen = base32_encode_alloc (in, inlen, &out);
* if (out == NULL && outlen == 0 && inlen != 0)
* FAIL: input too long
* if (out == NULL)
/* Get prototype. */
#include "base32.h"
-/* Get malloc. */
-#include <stdlib.h>
+/* Get imalloc. */
+#include <ialloc.h>
+
+#include <intprops.h>
+#include <verify.h>
/* Get UCHAR_MAX. */
#include <limits.h>
#include <string.h>
-/* C89 compliant way to cast 'char' to 'unsigned char'. */
+/* Convert 'char' to 'unsigned char' without casting. */
static unsigned char
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] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
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 = 1 + BASE32_LENGTH (inlen);
-
- /* Check for overflow in outlen computation.
- *
- * If there is no overflow, outlen >= inlen.
- *
- * TODO Is this a sufficient check? (See the notes in base64.c.)
- */
- if (inlen > outlen)
+ /* Check for overflow in outlen computation. */
+ assume (0 <= inlen);
+ idx_t in_over_5 = inlen / 5 + (inlen % 5 != 0), outlen;
+ if (! INT_MULTIPLY_OK (in_over_5, 8, &outlen))
{
*out = NULL;
return 0;
}
+ outlen++;
- *out = malloc (outlen);
+ *out = imalloc (outlen);
if (!*out)
return outlen;
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 == 8)
ctx->i = 0;
*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 = *outp;
if (inlen < 8)
return false;
- if (!isbase32 (in[0]) || !isbase32 (in[1]) )
+ if (!isbase32 (in[0]) || !isbase32 (in[1]))
return false;
if (*outleft)
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 = *outlen;
+ idx_t outleft = *outlen;
bool ignore_newlines = ctx != NULL;
bool flush_ctx = false;
unsigned int ctx_i = 0;
while (true)
{
- size_t outleft_save = outleft;
+ idx_t outleft_save = outleft;
if (ctx_i == 0 && !flush_ctx)
{
while (true)
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 "=".
- Dividing before multiplying avoids the possibility of overflow. */
- size_t needlen = 5 * (inlen / 8) + 5;
+ Shifting before multiplying avoids the possibility of overflow. */
+ idx_t needlen = 5 * ((inlen >> 3) + 1);
- *out = malloc (needlen);
+ *out = imalloc (needlen);
if (!*out)
return true;
#ifndef BASE32_H
# define BASE32_H
-/* Get size_t. */
-# include <stddef.h>
+/* Get idx_t. */
+# include <idx.h>
/* Get bool. */
# include <stdbool.h>
struct base32_decode_context
{
- unsigned int i;
+ int i;
char buf[8];
};
extern bool isbase32 (char ch) _GL_ATTRIBUTE_CONST;
-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);
-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 **out);
extern void base32_decode_ctx_init (struct base32_decode_context *ctx);
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);
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);
#define base32_decode(in, inlen, out, outlen) \
base32_decode_ctx (NULL, in, inlen, out, outlen)
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN
*
- * size_t outlen = base64_encode_alloc (in, inlen, &out);
+ * idx_t outlen = base64_encode_alloc (in, inlen, &out);
* if (out == NULL && outlen == 0 && inlen != 0)
* FAIL: input too long
* if (out == NULL)
/* Get prototype. */
#include "base64.h"
-/* Get malloc. */
-#include <stdlib.h>
+/* Get imalloc. */
+#include <ialloc.h>
+
+#include <intprops.h>
+#include <verify.h>
/* Get UCHAR_MAX. */
#include <limits.h>
#include <string.h>
-/* C89 compliant way to cast 'char' to 'unsigned char'. */
+/* Convert 'char' to 'unsigned char' without casting. */
static unsigned char
to_uchar (char ch)
{
to be of length >= 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 *restrict out)
+base64_encode_fast (const char *restrict in, idx_t inlen, char *restrict out)
{
while (inlen)
{
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
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 == 0 && inlen == outlen / 4 * 3)
+ if (outlen % 4 == 0 && inlen == (outlen >> 2) * 3)
{
base64_encode_fast (in, inlen, out);
return;
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 = 1 + BASE64_LENGTH (inlen);
-
- /* Check for overflow in outlen computation.
- *
- * If there is no overflow, outlen >= inlen.
- *
- * If the operation (inlen + 2) overflows then it yields at most +1, so
- * 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 as
- * (inlen > 4).
- */
- if (inlen > outlen)
+ /* Check for overflow in outlen computation. */
+ assume (0 <= inlen);
+ idx_t in_over_3 = inlen / 3 + (inlen % 3 != 0), outlen;
+ if (! INT_MULTIPLY_OK (in_over_3, 4, &outlen))
{
*out = NULL;
return 0;
}
+ outlen++;
- *out = malloc (outlen);
+ *out = imalloc (outlen);
if (!*out)
return outlen;
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 == 4)
ctx->i = 0;
*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 = *outp;
if (inlen < 2)
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 = *outlen;
+ idx_t outleft = *outlen;
bool ignore_newlines = ctx != NULL;
bool flush_ctx = false;
unsigned int ctx_i = 0;
while (true)
{
- size_t outleft_save = outleft;
+ idx_t outleft_save = outleft;
if (ctx_i == 0 && !flush_ctx)
{
while (true)
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 "=" and minus another 1 if the input ends with "==".
- Dividing before multiplying avoids the possibility of overflow. */
- size_t needlen = 3 * (inlen / 4) + 3;
+ Shifting before multiplying avoids the possibility of overflow. */
+ idx_t needlen = 3 * ((inlen >> 2) + 1);
- *out = malloc (needlen);
+ *out = imalloc (needlen);
if (!*out)
return true;
#ifndef BASE64_H
# define BASE64_H
-/* Get size_t. */
-# include <stddef.h>
+/* Get idx_t. */
+# include <idx.h>
/* Get bool. */
# include <stdbool.h>
struct base64_decode_context
{
- unsigned int i;
+ int i;
char buf[4];
};
extern bool isbase64 (char ch) _GL_ATTRIBUTE_CONST;
-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);
-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 **out);
extern void base64_decode_ctx_init (struct base64_decode_context *ctx);
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);
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);
#define base64_decode(in, inlen, out, outlen) \
base64_decode_ctx (NULL, in, inlen, out, outlen)
m4/base32.m4
Depends-on:
+ialloc
stdbool
memchr
+verify
configure.ac:
gl_FUNC_BASE32
m4/base64.m4
Depends-on:
+ialloc
stdbool
memchr
+verify
configure.ac:
gl_FUNC_BASE64
const char *in = "abcdefghijklmnop";
const char *b32in = "MFRGGZDFMZTWQ2LKNNWG23TPOA======";
char out[255];
- size_t len;
+ idx_t len;
bool ok;
char *p;
const char *in = "abcdefghijklmnop";
const char *b64in = "YWJjZGVmZw==";
char out[255];
- size_t len;
+ idx_t len;
bool ok;
char *p;