From c521edc3a12042701b2dda93e6bb9855e351c929 Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.org>
Date: Wed, 16 Mar 2016 10:38:39 +0000
Subject: [PATCH] Some platforms provide getcontext() but it does not work

Some platforms claim to be POSIX but their getcontext() implementation
does not work. Therefore we update the ASYNC_is_capable() function to test
for this.

RT#4366

Reviewed-by: Richard Levitte <levitte@openssl.org>
---
 crypto/async/arch/async_posix.c |  8 +++++-
 test/asynctest.c                | 45 ++++++++++-----------------------
 2 files changed, 21 insertions(+), 32 deletions(-)

diff --git a/crypto/async/arch/async_posix.c b/crypto/async/arch/async_posix.c
index 2d9e5102fc..33f2a3fa1e 100644
--- a/crypto/async/arch/async_posix.c
+++ b/crypto/async/arch/async_posix.c
@@ -62,7 +62,13 @@
 
 int ASYNC_is_capable(void)
 {
-    return 1;
+    ucontext_t ctx;
+
+    /*
+     * Some platforms provide getcontext() but it does not work (notably
+     * MacOSX PPC64). Check for a working getcontext();
+     */
+    return getcontext(&ctx) == 0;
 }
 
 void async_local_cleanup(void)
diff --git a/test/asynctest.c b/test/asynctest.c
index 31f04e92e4..4694fda23c 100644
--- a/test/asynctest.c
+++ b/test/asynctest.c
@@ -61,21 +61,6 @@
 #include <openssl/crypto.h>
 #include <../apps/apps.h>
 
-#if (defined(OPENSSL_SYS_UNIX) || defined(OPENSSL_SYS_CYGWIN)) && defined(OPENSSL_THREADS)
-# include <unistd.h>
-# if _POSIX_VERSION >= 200112L
-#  define ASYNC_POSIX
-# endif
-#elif defined(_WIN32)
-# define ASYNC_WIN
-#endif
-
-#if !defined(ASYNC_POSIX) && !defined(ASYNC_WIN)
-# define ASYNC_NULL
-#endif
-
-#ifndef ASYNC_NULL
-
 static int ctr = 0;
 static ASYNC_JOB *currjob = NULL;
 
@@ -308,25 +293,23 @@ static int test_ASYNC_block_pause()
     return 1;
 }
 
-#endif
-
 int main(int argc, char **argv)
 {
-
-#ifdef ASYNC_NULL
-    fprintf(stderr, "NULL implementation - skipping async tests\n");
-#else
-    CRYPTO_set_mem_debug(1);
-    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
-
-    if (       !test_ASYNC_init_thread()
-            || !test_ASYNC_start_job()
-            || !test_ASYNC_get_current_job()
-            || !test_ASYNC_WAIT_CTX_get_all_fds()
-            || !test_ASYNC_block_pause()) {
-        return 1;
+    if (!ASYNC_is_capable()) {
+        fprintf(stderr,
+                "OpenSSL build is not ASYNC capable - skipping async tests\n");
+    } else {
+        CRYPTO_set_mem_debug(1);
+        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+        if (       !test_ASYNC_init_thread()
+                || !test_ASYNC_start_job()
+                || !test_ASYNC_get_current_job()
+                || !test_ASYNC_WAIT_CTX_get_all_fds()
+                || !test_ASYNC_block_pause()) {
+            return 1;
+        }
     }
-#endif
     printf("PASS\n");
     return 0;
 }
-- 
2.25.1