Add NOTES.ANDROID.
[openssl.git] / crypto / ex_data.c
index d9807d585916572892856bdc7c26e67774cb8999..ed9820cfad44b9caec470efc3c1d16ed8869d286 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -9,7 +9,6 @@
 
 #include "internal/cryptlib_int.h"
 #include "internal/thread_once.h"
-#include <openssl/lhash.h>
 
 /*
  * Each structure type (sometimes called a class), that supports
@@ -38,6 +37,7 @@ static CRYPTO_ONCE ex_data_init = CRYPTO_ONCE_STATIC_INIT;
 
 DEFINE_RUN_ONCE_STATIC(do_ex_data_init)
 {
+    OPENSSL_init_crypto(0, NULL);
     ex_data_lock = CRYPTO_THREAD_lock_new();
     return ex_data_lock != NULL;
 }
@@ -119,11 +119,11 @@ static void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
 {
 }
 
-static int dummy_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from,
+static int dummy_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
                      void *from_d, int idx,
                      long argl, void *argp)
 {
-    return 0;
+    return 1;
 }
 
 int CRYPTO_free_ex_index(int class_index, int idx)
@@ -250,13 +250,14 @@ int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
  * for each index in the class used by this variable
  */
 int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
-                       CRYPTO_EX_DATA *from)
+                       const CRYPTO_EX_DATA *from)
 {
     int mx, j, i;
-    char *ptr;
+    void *ptr;
     EX_CALLBACK *stack[10];
     EX_CALLBACK **storage = NULL;
     EX_CALLBACKS *ip;
+    int toret = 0;
 
     if (from->sk == NULL)
         /* Nothing to copy over */
@@ -279,21 +280,35 @@ int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
     }
     CRYPTO_THREAD_unlock(ex_data_lock);
 
-    if (mx > 0 && storage == NULL) {
+    if (mx == 0)
+        return 1;
+    if (storage == NULL) {
         CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
         return 0;
     }
+    /*
+     * Make sure the ex_data stack is at least |mx| elements long to avoid
+     * issues in the for loop that follows; so go get the |mx|'th element
+     * (if it does not exist CRYPTO_get_ex_data() returns NULL), and assign
+     * to itself. This is normally a no-op; but ensures the stack is the
+     * proper size
+     */
+    if (!CRYPTO_set_ex_data(to, mx - 1, CRYPTO_get_ex_data(to, mx - 1)))
+        goto err;
 
     for (i = 0; i < mx; i++) {
         ptr = CRYPTO_get_ex_data(from, i);
         if (storage[i] && storage[i]->dup_func)
-            storage[i]->dup_func(to, from, &ptr, i,
-                                 storage[i]->argl, storage[i]->argp);
+            if (!storage[i]->dup_func(to, from, &ptr, i,
+                                      storage[i]->argl, storage[i]->argp))
+                goto err;
         CRYPTO_set_ex_data(to, i, ptr);
     }
+    toret = 1;
+ err:
     if (storage != stack)
         OPENSSL_free(storage);
-    return 1;
+    return toret;
 }
 
 
@@ -306,11 +321,12 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
     int mx, i;
     EX_CALLBACKS *ip;
     void *ptr;
+    EX_CALLBACK *f;
     EX_CALLBACK *stack[10];
     EX_CALLBACK **storage = NULL;
 
     if ((ip = get_and_lock(class_index)) == NULL)
-        return;
+        goto err;
 
     mx = sk_EX_CALLBACK_num(ip->meth);
     if (mx > 0) {
@@ -324,20 +340,23 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
     }
     CRYPTO_THREAD_unlock(ex_data_lock);
 
-    if (mx > 0 && storage == NULL) {
-        CRYPTOerr(CRYPTO_F_CRYPTO_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);
-        return;
-    }
     for (i = 0; i < mx; i++) {
-        if (storage[i] && storage[i]->free_func) {
+        if (storage != NULL)
+            f = storage[i];
+        else {
+            CRYPTO_THREAD_write_lock(ex_data_lock);
+            f = sk_EX_CALLBACK_value(ip->meth, i);
+            CRYPTO_THREAD_unlock(ex_data_lock);
+        }
+        if (f != NULL && f->free_func != NULL) {
             ptr = CRYPTO_get_ex_data(ad, i);
-            storage[i]->free_func(obj, ptr, ad, i,
-                                  storage[i]->argl, storage[i]->argp);
+            f->free_func(obj, ptr, ad, i, f->argl, f->argp);
         }
     }
 
     if (storage != stack)
         OPENSSL_free(storage);
+ err:
     sk_void_free(ad->sk);
     ad->sk = NULL;
 }