Commit bf39120c27 for openssl.org

commit bf39120c27047683c90f675ab1f1fbfa286cc026
Author: Bob Beck <beck@openssl.org>
Date:   Wed Jan 7 16:21:10 2026 -0700

    Allow testing the valgrind suppression file in CI

    Skip the OPENSSL_cleanup() call from the openssl app and in tests
    when OSSL_USE_VALGRIND environment variable is set.

    This can be used in the CI to test the valgrind suppressions.

    Builds upon https://github.com/openssl/openssl/pull/29573

    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
    Reviewed-by: Tomas Mraz <tomas@openssl.org>
    MergeDate: Tue Feb 10 14:00:54 2026
    (Merged from https://github.com/openssl/openssl/pull/29575)

diff --git a/apps/openssl.c b/apps/openssl.c
index 2d587e2249..e869910e82 100644
--- a/apps/openssl.c
+++ b/apps/openssl.c
@@ -21,6 +21,15 @@
 #include <openssl/pem.h>
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+
+#if defined __has_include
+/* Any compiler you're going to run valgrind on has this */
+#if __has_include(<valgrind/valgrind.h>)
+#include <valgrind/valgrind.h>
+#define OPENSSL_VALGRIND_H_INCLUDED
+#endif
+#endif /* defined(__has_include) */
+
 /* Needed to get the other O_xxx flags. */
 #ifdef OPENSSL_SYS_VMS
 #include <unixio.h>
@@ -372,6 +381,31 @@ end:
 #ifndef OPENSSL_NO_SECURE_MEMORY
     CRYPTO_secure_malloc_done();
 #endif
+
+#if defined(OPENSSL_VALGRIND_TEST)
+#if defined(OPENSSL_VALGRIND_H_INCLUDED)
+#if defined(RUNNING_ON_VALGRIND)
+    /*
+     * Enable special behaviour if we are compiled with
+     * OPENSSL_VALGRIND_TEST defined.
+     *
+     * Somewhat paradoxically, we do *NOT* want to clean up normally
+     * when running our tests using valgrind in order to test the
+     * suppression file which we will ship with the distribution. We
+     * set the OSSL_USE_VALGRIND environment variable for this
+     * purpose, but we only want to dodge cleanup when running under
+     * valgrind, *and* that environment variable is set. If you run
+     * this under valgrind without that environment variable set, it
+     * will still call OPENSSL_cleanup normally.
+     *
+     */
+    if (RUNNING_ON_VALGRIND && getenv("OSSL_USE_VALGRIND") != NULL)
+        EXIT(ret);
+#endif /* defined(RUNNING_ON_VALGRIND) */
+#else
+#error "OPENSSL_VALGRIND_TEST is defined, but <valgrind/valgrind.h> could not be included!"
+#endif /* defined(OPENSSL_VALGRIND_H_INCLUDED) */
+#endif /* defined(OPENSSL_VALGRIND_TEST) */
     OPENSSL_cleanup();
     EXIT(ret);
 }
diff --git a/doc/internal/man7/valgrind-tests.pod b/doc/internal/man7/valgrind-tests.pod
new file mode 100644
index 0000000000..e5b31b868d
--- /dev/null
+++ b/doc/internal/man7/valgrind-tests.pod
@@ -0,0 +1,49 @@
+=pod
+
+=head1 NAME
+
+valgrind-tests - How we test for valgrind
+
+=head1 DESCRIPTION
+
+We have CI jobs that run to verify that the suppression file we
+ship with valgrind functions correctly when users use valgrind
+with full leak checking.
+
+While doing full leak checking shows the global objects the library
+frees on exit as leaks, which really are not leaks, it is a chore
+to continuously tell people to ignore the results from the library.
+
+==head1 ENVIRONMENT
+
+Normally the openssl application main program and the test main program
+always call OPENSSL_cleanup(). This means that running these applications
+under valgrind will not show anything. Therefore we selectively disable
+the call to OPENSSL_cleanup() when running these applications for
+testing.
+
+the test environment sets the environment variable
+
+I<OSSL_USE_VALGRIND> when using valgrind to run our tests.
+
+As such the main programs above are instrumented so that when they
+are built and the <valgrind/valgrind.h> header can be seen in the
+include path, the macro RUNNING_ON_VALGRIND is used at exit time
+to test to see if the program is actually running under valgrind.
+
+If the program is running under valgrind, the program checks to
+see if I<OSSL_USE_VALGRIND> is set in the environment. If so,
+the call to OPENSSL_cleanup() is skipped on exit. This will ensure
+the library globals are noticed by valgrind with full leak checking
+ensuring our suppression file is working in CI.
+
+=head1 COPYRIGHT
+
+Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/test/testutil/main.c b/test/testutil/main.c
index 2d7c88c383..c0d3ffe7fd 100644
--- a/test/testutil/main.c
+++ b/test/testutil/main.c
@@ -12,6 +12,19 @@
 #include "output.h"
 #include "tu_local.h"

+#if defined __has_include
+/* Any compiler you're going to run valgrind on has this */
+#if __has_include(<valgrind/valgrind.h>)
+#include <valgrind/valgrind.h>
+#define OPENSSL_VALGRIND_H_INCLUDED
+#endif
+#endif /* defined(__has_include) */
+
+/*
+ * At some point we should consider looking at this function with a view to
+ * moving most/all of this into onfree handlers in OSSL_LIB_CTX.
+ */
+
 int main(int argc, char *argv[])
 {
     int ret = EXIT_FAILURE;
@@ -40,6 +53,20 @@ int main(int argc, char *argv[])
 end:
     ret = pulldown_test_framework(ret);
     test_close_streams();
+#if defined(OPENSSL_VALGRIND_H_INCLUDED) && defined(RUNNING_ON_VALGRIND)
+    /*
+     * Somewhat paradoxically, we do *NOT* want to clean up normally
+     * when running our tests using valgrind in order to test the
+     * suppression file which we will ship with the distribution. We
+     * set the OSSL_USE_VALGRIND environment variable for this
+     * purpose, but we only want to dodge cleanup when running under
+     * valgrind, *and* that environment variable is set. If you run
+     * this under valgrind without that environment variable set, it
+     * will still call OPENSSL_cleanup normally.
+     */
+    if (RUNNING_ON_VALGRIND && getenv("OSSL_USE_VALGRIND") != NULL)
+        return ret;
+#endif /* defined(OPENSSL_VALGRIND_H_INCLUDED) && defined(RUNNING_ON_VALGRIND) */
     OPENSSL_cleanup();
     return ret;
 }