Commit a94b6387f2 for openssl.org

commit a94b6387f2e6894e4cec50317a88b96b6c2d6617
Author: David Benjamin <davidben@google.com>
Date:   Sat Aug 15 08:42:31 2026 -0400

    Make OPENSSL_cleanse(NULL, 0) work

    Cleansing a zero-length buffer is legal, and NULL, 0 should be a legal
    representation of a zero-length buffer.

    However, due to a C language bug, memset cannot be called with NULL and
    zero. This will be fixed in C2y and retroactively applied to older
    versions of C, but we still support older compilers and sanitizers, so
    explicitly check len. See
    https://developers.redhat.com/articles/2024/12/11/making-memcpynull-null-0-well-defined

    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    Merge-date: Thu Oct 29 09:50:44 2026
    Merged-from: https://github.com/openssl/openssl/pull/31573

diff --git a/crypto/mem_clr.c b/crypto/mem_clr.c
index d76ef73179..6f791c053a 100644
--- a/crypto/mem_clr.c
+++ b/crypto/mem_clr.c
@@ -21,5 +21,13 @@ static volatile memset_t memset_func = memset;

 void OPENSSL_cleanse(void *ptr, size_t len)
 {
-    memset_func(ptr, 0, len);
+    /*
+     * If len is zero, ptr may be NULL. However, due to a C language bug, memset
+     * cannot be called with NULL and zero. This will be fixed in C2y and
+     * retroactively applied to older versions of C, but we still support older
+     * compilers and sanitizers, so explicitly check len. See
+     * https://developers.redhat.com/articles/2024/12/11/making-memcpynull-null-0-well-defined
+     */
+    if (len != 0)
+        memset_func(ptr, 0, len);
 }
diff --git a/test/sanitytest.c b/test/sanitytest.c
index 12fe8e6bf1..b064990a98 100644
--- a/test/sanitytest.c
+++ b/test/sanitytest.c
@@ -8,6 +8,7 @@
  */

 #include <string.h>
+#include <openssl/crypto.h>
 #include <openssl/types.h>
 #include "testutil.h"
 #include "internal/numbers.h"
@@ -238,6 +239,16 @@ static int test_sanity_memcmp(void)
     return CRYPTO_memcmp("ab", "cd", 2);
 }

+static int test_sanity_cleanse(void)
+{
+    /*
+     * Cleansing a zero-length buffer, while a no-op, is legal. (NULL, 0) is a
+     * legal representation of a zero-length buffer.
+     */
+    OPENSSL_cleanse(NULL, 0);
+    return 1;
+}
+
 static const struct sleep_test_vector {
     uint64_t val;
 } sleep_test_vectors[] = { { 0 }, { 1 }, { 999 }, { 1000 } };
@@ -318,6 +329,7 @@ int setup_tests(void)
     ADD_TEST(test_sanity_unsigned_conversion);
     ADD_TEST(test_sanity_range);
     ADD_TEST(test_sanity_memcmp);
+    ADD_TEST(test_sanity_cleanse);
     ADD_ALL_TESTS(test_sanity_sleep, OSSL_NELEM(sleep_test_vectors));
     return 1;
 }