From 283644eabebe09b7c5f557ebffe4def8633cea51 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Fri, 11 Apr 2025 11:38:21 -0700 Subject: [PATCH 01/12] Add nitpicks to headers - crypto_aesctr_shared.c: add for uint64_t & uint8_t. We never compile this file by itself so arguably this isn't necessary, but it's useful to allow static analyzers to parse the file. - humansize.c: add for abort() --- libcperciva/crypto/crypto_aesctr_shared.c | 2 ++ libcperciva/util/humansize.c | 1 + 2 files changed, 3 insertions(+) diff --git a/libcperciva/crypto/crypto_aesctr_shared.c b/libcperciva/crypto/crypto_aesctr_shared.c index 632e419c..a91d8253 100644 --- a/libcperciva/crypto/crypto_aesctr_shared.c +++ b/libcperciva/crypto/crypto_aesctr_shared.c @@ -1,3 +1,5 @@ +#include + /* * This code is shared between crypto_aesctr*.c files, and should not be * compiled as a separate translation unit. For details, see the comments in diff --git a/libcperciva/util/humansize.c b/libcperciva/util/humansize.c index 32160b08..750e019e 100644 --- a/libcperciva/util/humansize.c +++ b/libcperciva/util/humansize.c @@ -1,4 +1,5 @@ #include +#include #include "asprintf.h" #include "warnp.h" From 45ca120590ff6971eb344e796b1667c037b615fc Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 12 Jul 2026 08:25:59 -0700 Subject: [PATCH 02/12] crypto_entropy: clear internal state on exit Reported by: ChronoNova Bug bounty: $10 ("harmless") --- libcperciva/crypto/crypto_entropy.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/libcperciva/crypto/crypto_entropy.c b/libcperciva/crypto/crypto_entropy.c index 936e22ae..1922f51c 100644 --- a/libcperciva/crypto/crypto_entropy.c +++ b/libcperciva/crypto/crypto_entropy.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "cpusupport.h" @@ -55,6 +56,14 @@ update_from_rdrand(void) } #endif +/* Clear the DRBG internal state. */ +static void +crypto_entropy_atexit(void) +{ + + insecure_memzero(&drbg, sizeof(drbg)); +} + /** * instantiate(void): * Initialize the DRBG state. (Section 10.1.2.3) @@ -210,9 +219,13 @@ crypto_entropy_read(uint8_t * buf, size_t buflen) /* Instantiate if needed. */ if (instantiated == 0) { + /* Clear the internal state on exit. */ + if (atexit(crypto_entropy_atexit)) + goto err0; + /* Try to instantiate the PRNG. */ if (instantiate()) - return (-1); + goto err0; /* We have instantiated the PRNG. */ instantiated = 1; @@ -223,7 +236,7 @@ crypto_entropy_read(uint8_t * buf, size_t buflen) /* Do we need to reseed? */ if (drbg.reseed_counter > RESEED_INTERVAL) { if (reseed()) - return (-1); + goto err0; } /* How much data are we generating in this step? */ @@ -242,4 +255,8 @@ crypto_entropy_read(uint8_t * buf, size_t buflen) /* Success! */ return (0); + +err0: + /* Failure! */ + return (-1); } From d3f3fb06e689b105944523bf62011f26ef0e1fa8 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 26 Jul 2026 20:20:54 -0700 Subject: [PATCH 03/12] sha256{,_sse2}.c: wrap multi-statement macro with do...while --- libcperciva/alg/sha256.c | 5 +++-- libcperciva/alg/sha256_sse2.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libcperciva/alg/sha256.c b/libcperciva/alg/sha256.c index 1321f1f0..a5c97bd0 100644 --- a/libcperciva/alg/sha256.c +++ b/libcperciva/alg/sha256.c @@ -207,10 +207,11 @@ hwaccel_init(void) #define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) /* SHA256 round function */ -#define RND(a, b, c, d, e, f, g, h, k) \ +#define RND(a, b, c, d, e, f, g, h, k) do { \ h += S1(e) + Ch(e, f, g) + k; \ d += h; \ - h += S0(a) + Maj(a, b, c) + h += S0(a) + Maj(a, b, c); \ +} while (0) /* Adjusted round function for rotating state */ #define RNDr(S, W, i, ii) \ diff --git a/libcperciva/alg/sha256_sse2.c b/libcperciva/alg/sha256_sse2.c index 0dfc04be..e15505c6 100644 --- a/libcperciva/alg/sha256_sse2.c +++ b/libcperciva/alg/sha256_sse2.c @@ -58,10 +58,11 @@ static const uint32_t Krnd[64] = { #define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) /* SHA256 round function */ -#define RND(a, b, c, d, e, f, g, h, k) \ +#define RND(a, b, c, d, e, f, g, h, k) do { \ h += S1(e) + Ch(e, f, g) + k; \ d += h; \ - h += S0(a) + Maj(a, b, c) + h += S0(a) + Maj(a, b, c); \ +} while (0) /* Adjusted round function for rotating state */ #define RNDr(S, W, i, ii) \ From 36469bca55923d89288b01aa95e3e38249d35af2 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 26 Jul 2026 20:20:56 -0700 Subject: [PATCH 04/12] sha256.c: clarify parentheses in #if defined(... Reported by: Claude Sonnet 4.6 --- libcperciva/alg/sha256.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcperciva/alg/sha256.c b/libcperciva/alg/sha256.c index a5c97bd0..06c1b9e1 100644 --- a/libcperciva/alg/sha256.c +++ b/libcperciva/alg/sha256.c @@ -12,7 +12,7 @@ #include "sha256.h" -#if defined(CPUSUPPORT_X86_SHANI) && defined(CPUSUPPORT_X86_SSSE3) || \ +#if (defined(CPUSUPPORT_X86_SHANI) && defined(CPUSUPPORT_X86_SSSE3)) || \ defined(CPUSUPPORT_X86_SSE2) || \ defined(CPUSUPPORT_ARM_SHA256) #define HWACCEL From ab4873305dfcc4ecb545394d828befdf630fc166 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sat, 1 Aug 2026 12:22:34 -0700 Subject: [PATCH 05/12] Slight spacing refactoring Normally we wouldn't do this in a separate commit, but we want to keep the following commit as adding-parentheses-only. --- libcperciva/alg/sha256_shani.c | 3 ++- libcperciva/alg/sha256_sse2.c | 3 ++- libcperciva/util/readpass.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libcperciva/alg/sha256_shani.c b/libcperciva/alg/sha256_shani.c index 7f97319a..a61c0ce1 100644 --- a/libcperciva/alg/sha256_shani.c +++ b/libcperciva/alg/sha256_shani.c @@ -38,7 +38,8 @@ be32dec_128(const uint8_t * src) /* Convert an unsigned 32-bit immediate into a signed value. */ #define I32(a) ((UINT32_C(a) >= UINT32_C(0x80000000)) ? \ - -(int32_t)(UINT32_C(0xffffffff) - UINT32_C(a)) - 1 : (int32_t)INT32_C(a)) + -(int32_t)(UINT32_C(0xffffffff) - UINT32_C(a)) - 1 : \ + (int32_t)INT32_C(a)) /* Load four unsigned 32-bit immediates into a vector register. */ #define IMM4(a, b, c, d) _mm_set_epi32(I32(a), I32(b), I32(c), I32(d)) diff --git a/libcperciva/alg/sha256_sse2.c b/libcperciva/alg/sha256_sse2.c index e15505c6..4c6bb57c 100644 --- a/libcperciva/alg/sha256_sse2.c +++ b/libcperciva/alg/sha256_sse2.c @@ -74,7 +74,8 @@ static const uint32_t Krnd[64] = { /* Message schedule computation */ #define SHR32(x, n) (_mm_srli_epi32(x, n)) -#define ROTR32(x, n) (_mm_or_si128(SHR32(x, n), _mm_slli_epi32(x, (32-n)))) +#define ROTR32(x, n) (_mm_or_si128(SHR32(x, n), \ + _mm_slli_epi32(x, (32 - n)))) #define s0_128(x) _mm_xor_si128(_mm_xor_si128( \ ROTR32(x, 7), ROTR32(x, 18)), SHR32(x, 3)) diff --git a/libcperciva/util/readpass.c b/libcperciva/util/readpass.c index 3683aa1f..4c5bfeba 100644 --- a/libcperciva/util/readpass.c +++ b/libcperciva/util/readpass.c @@ -22,7 +22,8 @@ static const int badsigs[] = { /* Highest signal number we care about. */ #define MAX2(a, b) ((a) > (b) ? (a) : (b)) #define MAX4(a, b, c, d) MAX2(MAX2(a, b), MAX2(c, d)) -#define MAX8(a, b, c, d, e, f, g, h) MAX2(MAX4(a, b, c, d), MAX4(e, f, g, h)) +#define MAX8(a, b, c, d, e, f, g, h) \ + MAX2(MAX4(a, b, c, d), MAX4(e, f, g, h)) #define MAXBADSIG MAX2(SIGALRM, MAX8(SIGHUP, SIGINT, SIGPIPE, SIGQUIT, \ SIGTERM, SIGTSTP, SIGTTIN, SIGTTOU)) From b0d62c90afc77a611a6d19f7f56374bc3a56b926 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sat, 1 Aug 2026 12:22:35 -0700 Subject: [PATCH 06/12] Fix parentheses in macros Reported by: Claude Sonnet 4.6; also used a python script it wrote to find potential missing parentheses --- libcperciva/alg/sha256.c | 34 +++++++++++++-------------- libcperciva/alg/sha256_arm.c | 10 ++++---- libcperciva/alg/sha256_shani.c | 20 ++++++++-------- libcperciva/alg/sha256_sse2.c | 34 +++++++++++++-------------- libcperciva/crypto/crypto_aes_aesni.c | 18 +++++++------- libcperciva/crypto/crypto_aes_arm.c | 22 ++++++++--------- libcperciva/util/align_ptr.h | 4 ++-- libcperciva/util/getopt.h | 18 +++++++------- libcperciva/util/parsenum.h | 4 ++-- libcperciva/util/readpass.c | 6 ++--- 10 files changed, 85 insertions(+), 85 deletions(-) diff --git a/libcperciva/alg/sha256.c b/libcperciva/alg/sha256.c index 06c1b9e1..67ba3f9a 100644 --- a/libcperciva/alg/sha256.c +++ b/libcperciva/alg/sha256.c @@ -197,33 +197,33 @@ hwaccel_init(void) #endif /* HWACCEL */ /* Elementary functions used by SHA256 */ -#define Ch(x, y, z) ((x & (y ^ z)) ^ z) -#define Maj(x, y, z) ((x & (y | z)) | (y & z)) -#define SHR(x, n) (x >> n) -#define ROTR(x, n) ((x >> n) | (x << (32 - n))) -#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) -#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) -#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) -#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) +#define Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) +#define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#define SHR(x, n) ((x) >> (n)) +#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define S0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22)) +#define S1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25)) +#define s0(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ SHR((x), 3)) +#define s1(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ SHR((x), 10)) /* SHA256 round function */ #define RND(a, b, c, d, e, f, g, h, k) do { \ - h += S1(e) + Ch(e, f, g) + k; \ - d += h; \ - h += S0(a) + Maj(a, b, c); \ + (h) += S1((e)) + Ch((e), (f), (g)) + (k); \ + (d) += (h); \ + (h) += S0((a)) + Maj((a), (b), (c)); \ } while (0) /* Adjusted round function for rotating state */ #define RNDr(S, W, i, ii) \ - RND(S[(64 - i) % 8], S[(65 - i) % 8], \ - S[(66 - i) % 8], S[(67 - i) % 8], \ - S[(68 - i) % 8], S[(69 - i) % 8], \ - S[(70 - i) % 8], S[(71 - i) % 8], \ - W[i + ii] + Krnd[i + ii]) + RND((S)[(64 - (i)) % 8], (S)[(65 - (i)) % 8], \ + (S)[(66 - (i)) % 8], (S)[(67 - (i)) % 8], \ + (S)[(68 - (i)) % 8], (S)[(69 - (i)) % 8], \ + (S)[(70 - (i)) % 8], (S)[(71 - (i)) % 8], \ + (W)[(i) + (ii)] + Krnd[(i) + (ii)]) /* Message schedule computation */ #define MSCH(W, ii, i) \ - W[i + ii + 16] = s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii] + (W)[(i) + (ii) + 16] = s1((W)[(i) + (ii) + 14]) + (W)[(i) + (ii) + 9] + s0((W)[(i) + (ii) + 1]) + (W)[(i) + (ii)] /* * SHA256 block compression function. The 256-bit state is transformed via diff --git a/libcperciva/alg/sha256_arm.c b/libcperciva/alg/sha256_arm.c index 96223f4d..56d78869 100644 --- a/libcperciva/alg/sha256_arm.c +++ b/libcperciva/alg/sha256_arm.c @@ -38,15 +38,15 @@ static const uint32_t Krnd[64] = { #define RND4(S, M, Kp) do { \ uint32x4_t S0_step; \ uint32x4_t Wk; \ - S0_step = S[0]; \ - Wk = vaddq_u32(M, vld1q_u32(Kp)); \ - S[0] = vsha256hq_u32(S[0], S[1], Wk); \ - S[1] = vsha256h2q_u32(S[1], S0_step, Wk); \ + S0_step = (S)[0]; \ + Wk = vaddq_u32((M), vld1q_u32(Kp)); \ + (S)[0] = vsha256hq_u32((S)[0], (S)[1], Wk); \ + (S)[1] = vsha256h2q_u32((S)[1], S0_step, Wk); \ } while (0) /* Message schedule computation */ #define MSG4(X0, X1, X2, X3) \ - X0 = vsha256su1q_u32(vsha256su0q_u32(X0, X1), X2, X3) + (X0) = vsha256su1q_u32(vsha256su0q_u32((X0), (X1)), (X2), (X3)) /** * SHA256_Transform_arm(state, block): diff --git a/libcperciva/alg/sha256_shani.c b/libcperciva/alg/sha256_shani.c index a61c0ce1..47151581 100644 --- a/libcperciva/alg/sha256_shani.c +++ b/libcperciva/alg/sha256_shani.c @@ -49,29 +49,29 @@ be32dec_128(const uint8_t * src) __m128i M; \ \ /* Add the next four words of message schedule and round constants. */ \ - M = _mm_add_epi32(W, IMM4(K3, K2, K1, K0)); \ + M = _mm_add_epi32((W), IMM4(K3, K2, K1, K0)); \ \ /* Perform two rounds of SHA256, using the low two words in M. */ \ - S[1] = _mm_sha256rnds2_epu32(S[1], S[0], M); \ + (S)[1] = _mm_sha256rnds2_epu32((S)[1], (S)[0], M); \ \ /* Shift the two words of M down and perform the next two rounds. */ \ M = _mm_srli_si128(M, 8); \ - S[0] = _mm_sha256rnds2_epu32(S[0], S[1], M); \ + (S)[0] = _mm_sha256rnds2_epu32((S)[0], (S)[1], M); \ } while (0) /* Compute the ith set of four words of message schedule. */ #define MSG4(W, i) do { \ - W[(i + 0) % 4] = _mm_sha256msg1_epu32(W[(i + 0) % 4], W[(i + 1) % 4]); \ - W[(i + 0) % 4] = _mm_add_epi32(W[(i + 0) % 4], \ - _mm_alignr_epi8(W[(i + 3) % 4], W[(i + 2) % 4], 4)); \ - W[(i + 0) % 4] = _mm_sha256msg2_epu32(W[(i + 0) % 4], W[(i + 3) % 4]); \ + (W)[((i) + 0) % 4] = _mm_sha256msg1_epu32((W)[((i) + 0) % 4], (W)[((i) + 1) % 4]); \ + (W)[((i) + 0) % 4] = _mm_add_epi32((W)[((i) + 0) % 4], \ + _mm_alignr_epi8((W)[((i) + 3) % 4], (W)[((i) + 2) % 4], 4)); \ + (W)[((i) + 0) % 4] = _mm_sha256msg2_epu32((W)[((i) + 0) % 4], (W)[((i) + 3) % 4]); \ } while (0) /* Perform 4 rounds of SHA256 and generate more message schedule if needed. */ #define RNDMSG(S, W, i, K0, K1, K2, K3) do { \ - RND4(S, W[i % 4], K0, K1, K2, K3); \ - if (i < 12) \ - MSG4(W, i + 4); \ + RND4((S), (W)[(i) % 4], K0, K1, K2, K3); \ + if ((i) < 12) \ + MSG4((W), (i) + 4); \ } while (0) /** diff --git a/libcperciva/alg/sha256_sse2.c b/libcperciva/alg/sha256_sse2.c index 4c6bb57c..4e6a0b12 100644 --- a/libcperciva/alg/sha256_sse2.c +++ b/libcperciva/alg/sha256_sse2.c @@ -51,33 +51,33 @@ static const uint32_t Krnd[64] = { }; /* Elementary functions used by SHA256 */ -#define Ch(x, y, z) ((x & (y ^ z)) ^ z) -#define Maj(x, y, z) ((x & (y | z)) | (y & z)) -#define ROTR(x, n) ((x >> n) | (x << (32 - n))) -#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) -#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) +#define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define S0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22)) +#define S1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25)) /* SHA256 round function */ #define RND(a, b, c, d, e, f, g, h, k) do { \ - h += S1(e) + Ch(e, f, g) + k; \ - d += h; \ - h += S0(a) + Maj(a, b, c); \ + (h) += S1((e)) + Ch((e), (f), (g)) + (k); \ + (d) += (h); \ + (h) += S0((a)) + Maj((a), (b), (c)); \ } while (0) /* Adjusted round function for rotating state */ #define RNDr(S, W, i, ii) \ - RND(S[(64 - i) % 8], S[(65 - i) % 8], \ - S[(66 - i) % 8], S[(67 - i) % 8], \ - S[(68 - i) % 8], S[(69 - i) % 8], \ - S[(70 - i) % 8], S[(71 - i) % 8], \ - W[i + ii] + Krnd[i + ii]) + RND((S)[(64 - (i)) % 8], (S)[(65 - (i)) % 8], \ + (S)[(66 - (i)) % 8], (S)[(67 - (i)) % 8], \ + (S)[(68 - (i)) % 8], (S)[(69 - (i)) % 8], \ + (S)[(70 - (i)) % 8], (S)[(71 - (i)) % 8], \ + (W)[(i) + (ii)] + Krnd[(i) + (ii)]) /* Message schedule computation */ -#define SHR32(x, n) (_mm_srli_epi32(x, n)) -#define ROTR32(x, n) (_mm_or_si128(SHR32(x, n), \ - _mm_slli_epi32(x, (32 - n)))) +#define SHR32(x, n) (_mm_srli_epi32((x), (n))) +#define ROTR32(x, n) (_mm_or_si128(SHR32((x), (n)), \ + _mm_slli_epi32((x), (32 - (n))))) #define s0_128(x) _mm_xor_si128(_mm_xor_si128( \ - ROTR32(x, 7), ROTR32(x, 18)), SHR32(x, 3)) + ROTR32((x), 7), ROTR32((x), 18)), SHR32((x), 3)) static inline __m128i s1_128_high(__m128i a) diff --git a/libcperciva/crypto/crypto_aes_aesni.c b/libcperciva/crypto/crypto_aes_aesni.c index f69db9a7..b6559a05 100644 --- a/libcperciva/crypto/crypto_aes_aesni.c +++ b/libcperciva/crypto/crypto_aes_aesni.c @@ -23,13 +23,13 @@ struct crypto_aes_key_aesni { /* Compute an AES-128 round key. */ #define MKRKEY128(rkeys, i, rcon) do { \ - __m128i _s = rkeys[i - 1]; \ - __m128i _t = rkeys[i - 1]; \ + __m128i _s = (rkeys)[(i) - 1]; \ + __m128i _t = (rkeys)[(i) - 1]; \ _s = _mm_xor_si128(_s, _mm_slli_si128(_s, 4)); \ _s = _mm_xor_si128(_s, _mm_slli_si128(_s, 8)); \ - _t = _mm_aeskeygenassist_si128(_t, rcon); \ + _t = _mm_aeskeygenassist_si128(_t, (rcon)); \ _t = _mm_shuffle_epi32(_t, 0xff); \ - rkeys[i] = _mm_xor_si128(_s, _t); \ + (rkeys)[(i)] = _mm_xor_si128(_s, _t); \ } while (0) /** @@ -79,13 +79,13 @@ crypto_aes_key_expand_128_aesni(const uint8_t key_unexpanded[16], /* Compute an AES-256 round key. */ #define MKRKEY256(rkeys, i, shuffle, rcon) do { \ - __m128i _s = rkeys[i - 2]; \ - __m128i _t = rkeys[i - 1]; \ + __m128i _s = (rkeys)[(i) - 2]; \ + __m128i _t = (rkeys)[(i) - 1]; \ _s = _mm_xor_si128(_s, _mm_slli_si128(_s, 4)); \ _s = _mm_xor_si128(_s, _mm_slli_si128(_s, 8)); \ - _t = _mm_aeskeygenassist_si128(_t, rcon); \ - _t = _mm_shuffle_epi32(_t, shuffle); \ - rkeys[i] = _mm_xor_si128(_s, _t); \ + _t = _mm_aeskeygenassist_si128(_t, (rcon)); \ + _t = _mm_shuffle_epi32(_t, (shuffle)); \ + (rkeys)[(i)] = _mm_xor_si128(_s, _t); \ } while (0) /** diff --git a/libcperciva/crypto/crypto_aes_arm.c b/libcperciva/crypto/crypto_aes_arm.c index 38d27c70..52be59b7 100644 --- a/libcperciva/crypto/crypto_aes_arm.c +++ b/libcperciva/crypto/crypto_aes_arm.c @@ -30,7 +30,7 @@ struct crypto_aes_key_arm { * vdupq_laneq_u32(), except that accepts (and returns) uint8x16_t. */ #define vdupq_laneq_u32_u8(a, lane) \ - vreinterpretq_u8_u32(vdupq_laneq_u32(vreinterpretq_u32_u8(a), lane)) + vreinterpretq_u8_u32(vdupq_laneq_u32(vreinterpretq_u32_u8(a), (lane))) /** * vshlq_n_u128(a, n): @@ -45,7 +45,7 @@ struct crypto_aes_key_arm { * intrinsics; all of the built-in shift instructions operate on multiple * values (such as a pair of 64-bit values). */ -#define vshlq_n_u128(a, n) vextq_u8(vdupq_n_u8(0), a, 16 - n) +#define vshlq_n_u128(a, n) vextq_u8(vdupq_n_u8(0), (a), 16 - (n)) /** * SubWord_duplicate(a): @@ -101,12 +101,12 @@ SubWord_RotWord_XOR_duplicate(uint8x16_t a, const uint32_t rcon) /* Compute an AES-128 round key. */ #define MKRKEY128(rkeys, i, rcon) do { \ - uint8x16_t _s = rkeys[i - 1]; \ - uint8x16_t _t = rkeys[i - 1]; \ + uint8x16_t _s = (rkeys)[(i) - 1]; \ + uint8x16_t _t = (rkeys)[(i) - 1]; \ _s = veorq_u8(_s, vshlq_n_u128(_s, 4)); \ _s = veorq_u8(_s, vshlq_n_u128(_s, 8)); \ - _t = SubWord_RotWord_XOR_duplicate(_t, rcon); \ - rkeys[i] = veorq_u8(_s, _t); \ + _t = SubWord_RotWord_XOR_duplicate(_t, (rcon)); \ + (rkeys)[(i)] = veorq_u8(_s, _t); \ } while (0) /** @@ -144,14 +144,14 @@ crypto_aes_key_expand_128_arm(const uint8_t key_unexpanded[16], /* Compute an AES-256 round key. */ #define MKRKEY256(rkeys, i, rcon) do { \ - uint8x16_t _s = rkeys[i - 2]; \ - uint8x16_t _t = rkeys[i - 1]; \ + uint8x16_t _s = (rkeys)[(i) - 2]; \ + uint8x16_t _t = (rkeys)[(i) - 1]; \ _s = veorq_u8(_s, vshlq_n_u128(_s, 4)); \ _s = veorq_u8(_s, vshlq_n_u128(_s, 8)); \ - _t = (i % 2 == 1) ? \ + _t = ((i) % 2 == 1) ? \ SubWord_duplicate(_t) : \ - SubWord_RotWord_XOR_duplicate(_t, rcon); \ - rkeys[i] = veorq_u8(_s, _t); \ + SubWord_RotWord_XOR_duplicate(_t, (rcon)); \ + (rkeys)[(i)] = veorq_u8(_s, _t); \ } while (0) /** diff --git a/libcperciva/util/align_ptr.h b/libcperciva/util/align_ptr.h index ebe3e0f9..c87d83d9 100644 --- a/libcperciva/util/align_ptr.h +++ b/libcperciva/util/align_ptr.h @@ -13,7 +13,7 @@ * "${name}_buf". */ #define ALIGN_PTR_DECL(type, name, num, alignsize) \ - uint8_t name##_buf[num * sizeof(type) + (alignsize - 1)]; \ + uint8_t name##_buf[(num) * sizeof(type) + ((alignsize) - 1)]; \ type * name /** @@ -25,7 +25,7 @@ * relative to aligned memory. */ #define ALIGN_PTR_INIT(name, alignsize) \ - name = align_ptr(name##_buf, alignsize) + (name) = align_ptr(name##_buf, (alignsize)) /** * align_ptr(arr, alignment): diff --git a/libcperciva/util/getopt.h b/libcperciva/util/getopt.h index 965f0639..cac176c9 100644 --- a/libcperciva/util/getopt.h +++ b/libcperciva/util/getopt.h @@ -83,7 +83,7 @@ extern int optind, opterr, optreset; * the next option string and set optarg / optind appropriately; abort if not * properly initialized when not being called for the first time. */ -#define GETOPT(argc, argv) getopt(argc, argv) +#define GETOPT(argc, argv) getopt((argc), (argv)) /** * GETOPT_SWITCH(ch): @@ -107,13 +107,13 @@ extern int optind, opterr, optreset; * GETOPT_OPT("-x") is equivalent to "case 'x'" in a standard getopt loop * which has an optstring containing "x". */ -#define GETOPT_OPT(os) GETOPT_OPT_(os, __LINE__) -#define GETOPT_OPT_(os, ln) GETOPT_OPT__(os, ln) +#define GETOPT_OPT(os) GETOPT_OPT_((os), __LINE__) +#define GETOPT_OPT_(os, ln) GETOPT_OPT__((os), ln) #define GETOPT_OPT__(os, ln) \ case ln: \ if (getopt_initialized) \ goto getopt_skip_ ## ln; \ - getopt_register_opt(os, ln - getopt_ln_min, 0); \ + getopt_register_opt((os), (ln) - getopt_ln_min, 0); \ DO_LONGJMP; \ getopt_skip_ ## ln @@ -126,15 +126,15 @@ extern int optind, opterr, optreset; * GETOPT_OPTARG("-x") is equivalent to "case 'x'" in a standard getopt loop * which has an optstring containing "x:". */ -#define GETOPT_OPTARG(os) GETOPT_OPTARG_(os, __LINE__) -#define GETOPT_OPTARG_(os, ln) GETOPT_OPTARG__(os, ln) +#define GETOPT_OPTARG(os) GETOPT_OPTARG_((os), __LINE__) +#define GETOPT_OPTARG_(os, ln) GETOPT_OPTARG__((os), ln) #define GETOPT_OPTARG__(os, ln) \ case ln: \ if (getopt_initialized) { \ assert(optarg != NULL); \ goto getopt_skip_ ## ln; \ } \ - getopt_register_opt(os, ln - getopt_ln_min, 1); \ + getopt_register_opt((os), (ln) - getopt_ln_min, 1); \ DO_LONGJMP; \ getopt_skip_ ## ln @@ -153,7 +153,7 @@ extern int optind, opterr, optreset; case ln: \ if (getopt_initialized) \ goto getopt_skip_ ## ln; \ - getopt_register_missing(ln - getopt_ln_min); \ + getopt_register_missing((ln) - getopt_ln_min); \ DO_LONGJMP; \ getopt_skip_ ## ln @@ -179,7 +179,7 @@ extern int optind, opterr, optreset; if (getopt_initialized) \ goto getopt_skip_ ## ln; \ if (!getopt_default_missing) { \ - getopt_setrange(ln - getopt_ln_min); \ + getopt_setrange((ln) - getopt_ln_min); \ getopt_default_missing = 1; \ } \ DO_LONGJMP; \ diff --git a/libcperciva/util/parsenum.h b/libcperciva/util/parsenum.h index d8406c9b..ab21e09a 100644 --- a/libcperciva/util/parsenum.h +++ b/libcperciva/util/parsenum.h @@ -54,9 +54,9 @@ _Pragma("clang diagnostic pop") * set to +/- infinity or the limits of the unsigned integer type. */ #define PARSENUM2(x, s) \ - PARSENUM_EX4(x, s, 0, 0, "PARSENUM") + PARSENUM_EX4((x), (s), 0, 0, "PARSENUM") #define PARSENUM4(x, s, min, max) \ - PARSENUM_EX6(x, s, min, max, 0, 0, "PARSENUM") + PARSENUM_EX6((x), (s), (min), (max), 0, 0, "PARSENUM") /* Magic to select which version of PARSENUM to use. */ #define PARSENUM(...) PARSENUM_(PARSENUM_COUNT(__VA_ARGS__))(__VA_ARGS__) diff --git a/libcperciva/util/readpass.c b/libcperciva/util/readpass.c index 4c5bfeba..322f7f4a 100644 --- a/libcperciva/util/readpass.c +++ b/libcperciva/util/readpass.c @@ -17,13 +17,13 @@ static const int badsigs[] = { SIGPIPE, SIGQUIT, SIGTERM, SIGTSTP, SIGTTIN, SIGTTOU }; -#define NSIGS sizeof(badsigs)/sizeof(badsigs[0]) +#define NSIGS (sizeof(badsigs)/sizeof(badsigs[0])) /* Highest signal number we care about. */ #define MAX2(a, b) ((a) > (b) ? (a) : (b)) -#define MAX4(a, b, c, d) MAX2(MAX2(a, b), MAX2(c, d)) +#define MAX4(a, b, c, d) MAX2(MAX2((a), (b)), MAX2((c), (d))) #define MAX8(a, b, c, d, e, f, g, h) \ - MAX2(MAX4(a, b, c, d), MAX4(e, f, g, h)) + MAX2(MAX4((a), (b), (c), (d)), MAX4((e), (f), (g), (h))) #define MAXBADSIG MAX2(SIGALRM, MAX8(SIGHUP, SIGINT, SIGPIPE, SIGQUIT, \ SIGTERM, SIGTSTP, SIGTTIN, SIGTTOU)) From af64c1c9153d74b2d1204c678f0f41bdcbc7336f Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 2 Aug 2026 18:25:19 -0700 Subject: [PATCH 07/12] cpusupport-ARM-*: indicate dead assignment I missed these earlier because they're in ARM test code that isn't compiled on x86. Reported by: clang 19 scan-build (on a raspberry pi) --- libcperciva/cpusupport/Build/cpusupport-ARM-AES.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c b/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c index b52c44c6..c3ecdafd 100644 --- a/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c +++ b/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c @@ -20,6 +20,7 @@ main(void) /* Check _u32: some compilers only support the _u8 variant. */ lanes = vdupq_laneq_u32(lanes, 0); + (void)lanes; /* UNUSED */ /* Success! */ return (0); From 2507be455825cbe8439051854b7e254b14a74d27 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Sun, 2 Aug 2026 18:25:20 -0700 Subject: [PATCH 08/12] Remove #ifdef around #include - for cpusupport/Build/cpusupport-ARM-*.c: we deliberately want these files to fail to compile if the compiler doesn't support ARM. - for everything else: these #includes are already inside #ifdef CPUSUPPORT_ARM_AES, so we gain nothing from having another #ifdef. This now matches the way we handle #includes for x86 intrinsics. Suggested by: Claude Sonnet 5 Bug bounty: $10 ("harmless") --- libcperciva/alg/sha256_arm.c | 2 -- libcperciva/cpusupport/Build/cpusupport-ARM-AES.c | 2 -- libcperciva/cpusupport/Build/cpusupport-ARM-SHA256.c | 2 -- libcperciva/crypto/crypto_aes_arm.c | 2 -- libcperciva/crypto/crypto_aes_arm_u8.h | 2 -- libcperciva/crypto/crypto_aesctr_arm.c | 2 -- 6 files changed, 12 deletions(-) diff --git a/libcperciva/alg/sha256_arm.c b/libcperciva/alg/sha256_arm.c index 56d78869..fd2d28f9 100644 --- a/libcperciva/alg/sha256_arm.c +++ b/libcperciva/alg/sha256_arm.c @@ -8,9 +8,7 @@ #include #include -#ifdef __ARM_NEON #include -#endif #include "sha256_arm.h" diff --git a/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c b/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c index c3ecdafd..9d19ec40 100644 --- a/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c +++ b/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c @@ -1,8 +1,6 @@ #include -#ifdef __ARM_NEON #include -#endif int main(void) diff --git a/libcperciva/cpusupport/Build/cpusupport-ARM-SHA256.c b/libcperciva/cpusupport/Build/cpusupport-ARM-SHA256.c index 7a04d87b..3183118c 100644 --- a/libcperciva/cpusupport/Build/cpusupport-ARM-SHA256.c +++ b/libcperciva/cpusupport/Build/cpusupport-ARM-SHA256.c @@ -1,6 +1,4 @@ -#ifdef __ARM_NEON #include -#endif int main(void) diff --git a/libcperciva/crypto/crypto_aes_arm.c b/libcperciva/crypto/crypto_aes_arm.c index 52be59b7..92603c8a 100644 --- a/libcperciva/crypto/crypto_aes_arm.c +++ b/libcperciva/crypto/crypto_aes_arm.c @@ -7,9 +7,7 @@ #include #include -#ifdef __ARM_NEON #include -#endif #include "align_ptr.h" #include "insecure_memzero.h" diff --git a/libcperciva/crypto/crypto_aes_arm_u8.h b/libcperciva/crypto/crypto_aes_arm_u8.h index 173020bd..dcccba83 100644 --- a/libcperciva/crypto/crypto_aes_arm_u8.h +++ b/libcperciva/crypto/crypto_aes_arm_u8.h @@ -1,9 +1,7 @@ #ifndef CRYPTO_AES_ARM_U8_H_ #define CRYPTO_AES_ARM_U8_H_ -#ifdef __ARM_NEON #include -#endif /** * crypto_aes_encrypt_block_arm_u8(in, key): diff --git a/libcperciva/crypto/crypto_aesctr_arm.c b/libcperciva/crypto/crypto_aesctr_arm.c index 0b8df71f..d1fd84df 100644 --- a/libcperciva/crypto/crypto_aesctr_arm.c +++ b/libcperciva/crypto/crypto_aesctr_arm.c @@ -8,9 +8,7 @@ #include #include -#ifdef __ARM_NEON #include -#endif #include "crypto_aes.h" #include "crypto_aes_arm_u8.h" From e8941441bbd87367c3af2037226b8ac2ab22cd24 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Mon, 3 Aug 2026 10:52:24 -0700 Subject: [PATCH 09/12] readpass_file: check for error in fgetc() This problem could not have caused an incomplete password to be read; it would only have failed to report a rare read error occurring after fgets() had already succeeded. Reported by: ChronoNova Bug bounty: $10 ("harmless") --- libcperciva/util/readpass_file.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libcperciva/util/readpass_file.c b/libcperciva/util/readpass_file.c index 4379a61d..14ad1fcf 100644 --- a/libcperciva/util/readpass_file.c +++ b/libcperciva/util/readpass_file.c @@ -44,6 +44,9 @@ readpass_file(char ** passwd, const char * filename) if (fgetc(f) != EOF) { warn0("line too long, or more than 1 line in %s", filename); goto err2; + } else if (ferror(f)) { + warnp("fgetc"); + goto err2; } /* Close the file. */ From 51526a35968627ad62bb0e6b4dc33696f0b63930 Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Tue, 4 Aug 2026 11:27:52 -0700 Subject: [PATCH 10/12] STYLE: ignore failures or callback returns in error paths --- STYLE | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/STYLE b/STYLE index 1200c961..7b9e82a4 100644 --- a/STYLE +++ b/STYLE @@ -97,6 +97,10 @@ is preferred over goto done; at the start of a function. +Don't check for failures in an error-handling path if they will not affect +behaviour. In particular, if we're already in an unrecoverable state, don't +let a callback's return value determine control flow. + Headers should be included in the following groups, with a blank line after each (non-empty) group: 1. , with first followed by others alphabetically. From d3eef4e48c7713254f97db2fc701736a64cc837f Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Fri, 27 Feb 2026 10:41:56 -0800 Subject: [PATCH 11/12] warnp: Warn on atexit failure Note that warnp (and warn/warnx) do not call into warnp_setprogname so no problem arises from using warnp within warnp.c. Reported by: Claude Opus 4.6 Bug Bounty value: $10 ("harmless bug") --- libcperciva/util/warnp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libcperciva/util/warnp.c b/libcperciva/util/warnp.c index 04c0d0cf..4ec502cb 100644 --- a/libcperciva/util/warnp.c +++ b/libcperciva/util/warnp.c @@ -47,7 +47,11 @@ warnp_setprogname(const char * progname) /* If we haven't already done so, register our exit handler. */ if (initialized == 0) { - atexit(warnp_atexit); + /* On failure, warn only; we're inside a (void) function. */ + if (atexit(warnp_atexit)) + warnp("atexit"); + + /* Don't try atexit() again. */ initialized = 1; } } From a60d334d5a6616714e82fe4f10c8c2aab16b38bc Mon Sep 17 00:00:00 2001 From: Graham Percival Date: Tue, 11 Aug 2026 13:22:14 -0700 Subject: [PATCH 12/12] getopt: Warn on atexit failure --- libcperciva/util/getopt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libcperciva/util/getopt.c b/libcperciva/util/getopt.c index f0bb09d1..72476259 100644 --- a/libcperciva/util/getopt.c +++ b/libcperciva/util/getopt.c @@ -3,6 +3,8 @@ #include #include +#include "warnp.h" + #include "getopt.h" /* @@ -90,7 +92,11 @@ reset(int argc, char * const argv[]) /* Register atexit handler if we haven't done so already. */ if (!atexit_registered) { - atexit(getopt_atexit); + /* On failure, warn only; we're inside a (void) function. */ + if (atexit(getopt_atexit)) + warnp("atexit"); + + /* Don't try atexit() again. */ atexit_registered = 1; }