For some reason, getting the topmost error was done the same way as
[openssl.git] / crypto / err / err.c
index 989d4858126085af7b16bb175d49e797fde8c97f..04773d65a69fd87cdf84c21f83cb11d75c2f0599 100644 (file)
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <openssl/bio.h>
 #include <openssl/err.h>
 
+static void err_load_strings(int lib, ERR_STRING_DATA *str);
+
 static void ERR_STATE_free(ERR_STATE *s);
 #ifndef OPENSSL_NO_ERR
 static ERR_STRING_DATA ERR_str_libraries[]=
@@ -214,13 +216,13 @@ static ERR_STRING_DATA ERR_str_reasons[]=
 struct st_ERR_FNS
        {
        /* Works on the "error_hash" string table */
-       LHASH *(*cb_err_get)(void);
+       LHASH *(*cb_err_get)(int create);
        void (*cb_err_del)(void);
        ERR_STRING_DATA *(*cb_err_get_item)(const ERR_STRING_DATA *);
        ERR_STRING_DATA *(*cb_err_set_item)(ERR_STRING_DATA *);
        ERR_STRING_DATA *(*cb_err_del_item)(ERR_STRING_DATA *);
        /* Works on the "thread_hash" error-state table */
-       LHASH *(*cb_thread_get)(void);
+       LHASH *(*cb_thread_get)(int create);
        ERR_STATE *(*cb_thread_get_item)(const ERR_STATE *);
        ERR_STATE *(*cb_thread_set_item)(ERR_STATE *);
        void (*cb_thread_del_item)(const ERR_STATE *);
@@ -229,12 +231,12 @@ struct st_ERR_FNS
        };
 
 /* Predeclarations of the "err_defaults" functions */
-static LHASH *int_err_get(void);
+static LHASH *int_err_get(int create);
 static void int_err_del(void);
 static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *);
 static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *);
 static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *);
-static LHASH *int_thread_get(void);
+static LHASH *int_thread_get(int create);
 static ERR_STATE *int_thread_get_item(const ERR_STATE *);
 static ERR_STATE *int_thread_set_item(ERR_STATE *);
 static void int_thread_del_item(const ERR_STATE *);
@@ -265,18 +267,18 @@ static const ERR_FNS *err_fns = NULL;
  * "err_defaults" functions. This way, a linked module can completely defer all
  * ERR state operation (together with requisite locking) to the implementations
  * and state in the loading application. */
-static LHASH *int_error_hash;
-static int int_error_hash_set = 0;
-static LHASH *int_thread_hash;
-static int int_thread_hash_set = 0;
-static int int_err_library_number=ERR_LIB_USER;
+static LHASH *int_error_hash = NULL;
+static LHASH *int_thread_hash = NULL;
+static int int_err_library_number= ERR_LIB_USER;
 
 /* Internal function that checks whether "err_fns" is set and if not, sets it to
  * the defaults. */
 static void err_fns_check(void)
        {
+       if (err_fns) return;
+       
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
-       if(!err_fns)
+       if (!err_fns)
                err_fns = &err_defaults;
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
        }
@@ -291,17 +293,18 @@ const ERR_FNS *ERR_get_implementation(void)
 
 int ERR_set_implementation(const ERR_FNS *fns)
        {
-       int toret = 0;
+       int ret = 0;
+
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
        /* It's too late if 'err_fns' is non-NULL. BTW: not much point setting
         * an error is there?! */
-       if(!err_fns)
+       if (!err_fns)
                {
                err_fns = fns;
-               toret = 1;
+               ret = 1;
                }
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
-       return toret;
+       return ret;
        }
 
 /* These are the callbacks provided to "lh_new()" when creating the LHASH tables
@@ -315,34 +318,36 @@ static int err_cmp(const void *a_void, const void *b_void);
 static unsigned long pid_hash(const void *pid_void);
 /* static int pid_cmp(ERR_STATE *a,ERR_STATE *pid); */
 static int pid_cmp(const void *a_void,const void *pid_void);
-static unsigned long get_error_values(int inc,const char **file,int *line,
+static unsigned long get_error_values(int inc,int top,const char **file,int *line,
                                      const char **data,int *flags);
 
 /* The internal functions used in the "err_defaults" implementation */
 
-static LHASH *int_err_get(void)
+static LHASH *int_err_get(int create)
        {
-       LHASH *toret = NULL;
+       LHASH *ret = NULL;
+
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
-       if(!int_error_hash_set)
-               int_error_hash = lh_new(err_hash, err_cmp);
-       if(int_error_hash)
+       if (!int_error_hash && create)
                {
-               int_error_hash_set = 1;
-               toret = int_error_hash;
+               CRYPTO_push_info("int_err_get (err.c)");
+               int_error_hash = lh_new(err_hash, err_cmp);
+               CRYPTO_pop_info();
                }
+       if (int_error_hash)
+               ret = int_error_hash;
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
-       return(toret);
+
+       return ret;
        }
 
 static void int_err_del(void)
        {
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
-       if(int_error_hash_set)
+       if (int_error_hash)
                {
                lh_free(int_error_hash);
                int_error_hash = NULL;
-               int_error_hash_set = 0;
                }
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
        }
@@ -351,13 +356,16 @@ static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
        {
        ERR_STRING_DATA *p;
        LHASH *hash;
+
        err_fns_check();
-       hash = ERRFN(err_get)();
-       if(!hash)
+       hash = ERRFN(err_get)(0);
+       if (!hash)
                return NULL;
+
        CRYPTO_r_lock(CRYPTO_LOCK_ERR);
        p = (ERR_STRING_DATA *)lh_retrieve(hash, d);
        CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
+
        return p;
        }
 
@@ -365,13 +373,16 @@ static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d)
        {
        ERR_STRING_DATA *p;
        LHASH *hash;
+
        err_fns_check();
-       hash = ERRFN(err_get)();
-       if(!hash)
+       hash = ERRFN(err_get)(1);
+       if (!hash)
                return NULL;
+
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
        p = (ERR_STRING_DATA *)lh_insert(hash, d);
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+
        return p;
        }
 
@@ -379,42 +390,50 @@ static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d)
        {
        ERR_STRING_DATA *p;
        LHASH *hash;
+
        err_fns_check();
-       hash = ERRFN(err_get)();
-       if(!hash)
+       hash = ERRFN(err_get)(0);
+       if (!hash)
                return NULL;
+
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
        p = (ERR_STRING_DATA *)lh_delete(hash, d);
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+
        return p;
        }
 
-static LHASH *int_thread_get(void)
+static LHASH *int_thread_get(int create)
        {
-       LHASH *toret = NULL;
+       LHASH *ret = NULL;
+
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
-       if(!int_thread_hash_set)
-               int_thread_hash = lh_new(pid_hash, pid_cmp);
-       if(int_thread_hash)
+       if (!int_thread_hash && create)
                {
-               int_thread_hash_set = 1;
-               toret = int_thread_hash;
+               CRYPTO_push_info("int_thread_get (err.c)");
+               int_thread_hash = lh_new(pid_hash, pid_cmp);
+               CRYPTO_pop_info();
                }
+       if (int_thread_hash)
+               ret = int_thread_hash;
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
-       return(toret);
+       return ret;
        }
 
 static ERR_STATE *int_thread_get_item(const ERR_STATE *d)
        {
        ERR_STATE *p;
        LHASH *hash;
+
        err_fns_check();
-       hash = ERRFN(thread_get)();
-       if(!hash)
+       hash = ERRFN(thread_get)(0);
+       if (!hash)
                return NULL;
+
        CRYPTO_r_lock(CRYPTO_LOCK_ERR);
        p = (ERR_STATE *)lh_retrieve(hash, d);
        CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
+
        return p;
        }
 
@@ -422,13 +441,16 @@ static ERR_STATE *int_thread_set_item(ERR_STATE *d)
        {
        ERR_STATE *p;
        LHASH *hash;
+
        err_fns_check();
-       hash = ERRFN(thread_get)();
-       if(!hash)
+       hash = ERRFN(thread_get)(1);
+       if (!hash)
                return NULL;
+
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
        p = (ERR_STATE *)lh_insert(hash, d);
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+
        return p;
        }
 
@@ -436,31 +458,35 @@ static void int_thread_del_item(const ERR_STATE *d)
        {
        ERR_STATE *p;
        LHASH *hash;
+
        err_fns_check();
-       hash = ERRFN(thread_get)();
-       if(!hash)
+       hash = ERRFN(thread_get)(0);
+       if (!hash)
                return;
+
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
        p = (ERR_STATE *)lh_delete(hash, d);
        /* make sure we don't leak memory */
-       if(int_thread_hash_set && (lh_num_items(int_thread_hash) == 0))
+       if (int_thread_hash && (lh_num_items(int_thread_hash) == 0))
                {
                lh_free(int_thread_hash);
                int_thread_hash = NULL;
-               int_thread_hash_set = 0;
                }
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
-       if(p)
+
+       if (p)
                ERR_STATE_free(p);
        }
 
 static int int_err_get_next_lib(void)
        {
-       int toret;
+       int ret;
+
        CRYPTO_w_lock(CRYPTO_LOCK_ERR);
-       toret = int_err_library_number++;
+       ret = int_err_library_number++;
        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
-       return toret;
+
+       return ret;
        }
 
 
@@ -482,8 +508,11 @@ static void build_SYS_str_reasons()
        /* OPENSSL_malloc cannot be used here, use static storage instead */
        static char strerror_tab[NUM_SYS_STR_REASONS][LEN_SYS_STR_REASON];
        int i;
+       static int init = 1;
 
-       CRYPTO_w_lock(CRYPTO_LOCK_ERR_HASH);
+       if (!init) return;
+
+       CRYPTO_w_lock(CRYPTO_LOCK_ERR);
 
        for (i = 1; i <= NUM_SYS_STR_REASONS; i++)
                {
@@ -508,7 +537,9 @@ static void build_SYS_str_reasons()
        /* Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL},
         * as required by ERR_load_strings. */
 
-       CRYPTO_w_unlock(CRYPTO_LOCK_ERR_HASH);
+       init = 0;
+       
+       CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
        }
 #endif
 
@@ -525,7 +556,7 @@ static void ERR_STATE_free(ERR_STATE *s)
        {
        int i;
 
-       if(s == NULL)
+       if (s == NULL)
            return;
 
        for (i=0; i<ERR_NUM_ERRORS; i++)
@@ -537,31 +568,18 @@ static void ERR_STATE_free(ERR_STATE *s)
 
 void ERR_load_ERR_strings(void)
        {
-       static int init=1;
-
-       if (init)
-               {
-               init=0;
-               /* We put the first-time check code here to reduce the number of
-                * times it is called (then it doesn't get called from
-                * ERR_load_strings() loads of times). */
-               err_fns_check();
+       err_fns_check();
 #ifndef OPENSSL_NO_ERR
-               ERR_load_strings(0,ERR_str_libraries);
-               ERR_load_strings(0,ERR_str_reasons);
-               ERR_load_strings(ERR_LIB_SYS,ERR_str_functs);
-               build_SYS_str_reasons();
-               ERR_load_strings(ERR_LIB_SYS,SYS_str_reasons);
+       err_load_strings(0,ERR_str_libraries);
+       err_load_strings(0,ERR_str_reasons);
+       err_load_strings(ERR_LIB_SYS,ERR_str_functs);
+       build_SYS_str_reasons();
+       err_load_strings(ERR_LIB_SYS,SYS_str_reasons);
 #endif
-               }
        }
 
-void ERR_load_strings(int lib, ERR_STRING_DATA *str)
+static void err_load_strings(int lib, ERR_STRING_DATA *str)
        {
-       /* Do this if it hasn't been done already (NB: The order of the "init=0"
-        * statement and the recursive calls back to this function prevent a
-        * loop). */
-       ERR_load_ERR_strings();
        while (str->error)
                {
                str->error|=ERR_PACK(lib,0,0);
@@ -570,9 +588,15 @@ void ERR_load_strings(int lib, ERR_STRING_DATA *str)
                }
        }
 
+void ERR_load_strings(int lib, ERR_STRING_DATA *str)
+       {
+       ERR_load_ERR_strings();
+       err_load_strings(lib, str);
+       }
+
 void ERR_unload_strings(int lib, ERR_STRING_DATA *str)
        {
-       while(str->error)
+       while (str->error)
                {
                str->error|=ERR_PACK(lib,0,0);
                ERRFN(err_del_item)(str);
@@ -642,30 +666,40 @@ void ERR_clear_error(void)
 
 
 unsigned long ERR_get_error(void)
-       { return(get_error_values(1,NULL,NULL,NULL,NULL)); }
+       { return(get_error_values(1,0,NULL,NULL,NULL,NULL)); }
 
 unsigned long ERR_get_error_line(const char **file,
             int *line)
-       { return(get_error_values(1,file,line,NULL,NULL)); }
+       { return(get_error_values(1,0,file,line,NULL,NULL)); }
 
 unsigned long ERR_get_error_line_data(const char **file, int *line,
             const char **data, int *flags)
-       { return(get_error_values(1,file,line,
-            data,flags)); }
+       { return(get_error_values(1,0,file,line,data,flags)); }
+
 
 unsigned long ERR_peek_error(void)
-       { return(get_error_values(0,NULL,NULL,NULL,NULL)); }
+       { return(get_error_values(0,0,NULL,NULL,NULL,NULL)); }
 
-unsigned long ERR_peek_error_line(const char **file,
-            int *line)
-       { return(get_error_values(0,file,line,NULL,NULL)); }
+unsigned long ERR_peek_error_line(const char **file, int *line)
+       { return(get_error_values(0,0,file,line,NULL,NULL)); }
 
 unsigned long ERR_peek_error_line_data(const char **file, int *line,
             const char **data, int *flags)
-       { return(get_error_values(0,file,line,
-            data,flags)); }
+       { return(get_error_values(0,0,file,line,data,flags)); }
+
+
+unsigned long ERR_peek_last_error(void)
+       { return(get_error_values(0,1,NULL,NULL,NULL,NULL)); }
+
+unsigned long ERR_peek_last_error_line(const char **file, int *line)
+       { return(get_error_values(0,1,file,line,NULL,NULL)); }
+
+unsigned long ERR_peek_last_error_line_data(const char **file, int *line,
+            const char **data, int *flags)
+       { return(get_error_values(0,1,file,line,data,flags)); }
+
 
-static unsigned long get_error_values(int inc, const char **file, int *line,
+static unsigned long get_error_values(int inc, int top, const char **file, int *line,
             const char **data, int *flags)
        {       
        int i=0;
@@ -674,8 +708,21 @@ static unsigned long get_error_values(int inc, const char **file, int *line,
 
        es=ERR_get_state();
 
-       if (es->bottom == es->top) return(0);
-       i=(es->bottom+1)%ERR_NUM_ERRORS;
+       if (inc && top)
+               {
+               if (file) *file = "";
+               if (line) *line = 0;
+               if (data) *data = "";
+               if (flags) *flags = 0;
+                       
+               return ERR_R_INTERNAL_ERROR;
+               }
+
+       if (es->bottom == es->top) return 0;
+       if (top)
+               i=es->top;                       /* last error */
+       else
+               i=(es->bottom+1)%ERR_NUM_ERRORS; /* first error */
 
        ret=es->err_buffer[i];
        if (inc)
@@ -718,7 +765,7 @@ static unsigned long get_error_values(int inc, const char **file, int *line,
                        if (flags != NULL) *flags=es->err_data_flags[i];
                        }
                }
-       return(ret);
+       return ret;
        }
 
 void ERR_error_string_n(unsigned long e, char *buf, size_t len)
@@ -780,19 +827,19 @@ char *ERR_error_string(unsigned long e, char *ret)
        if (ret == NULL) ret=buf;
        ERR_error_string_n(e, ret, 256);
 
-       return(ret);
+       return ret;
        }
 
 LHASH *ERR_get_string_table(void)
        {
        err_fns_check();
-       return ERRFN(err_get)();
+       return ERRFN(err_get)(0);
        }
 
 LHASH *ERR_get_err_state_table(void)
        {
        err_fns_check();
-       return ERRFN(thread_get)();
+       return ERRFN(thread_get)(0);
        }
 
 const char *ERR_lib_error_string(unsigned long e)
@@ -830,7 +877,7 @@ const char *ERR_reason_error_string(unsigned long e)
        r=ERR_GET_REASON(e);
        d.error=ERR_PACK(l,0,r);
        p=ERRFN(err_get_item)(&d);
-       if(!p)
+       if (!p)
                {
                d.error=ERR_PACK(0,0,r);
                p=ERRFN(err_get_item)(&d);
@@ -871,6 +918,7 @@ static int pid_cmp(const void *a_void, const void *b_void)
 void ERR_remove_state(unsigned long pid)
        {
        ERR_STATE tmp;
+
        err_fns_check();
        if (pid == 0)
                pid=(unsigned long)CRYPTO_thread_id();
@@ -886,6 +934,7 @@ ERR_STATE *ERR_get_state(void)
        ERR_STATE *ret,tmp,*tmpp=NULL;
        int i;
        unsigned long pid;
+
        err_fns_check();
        pid=(unsigned long)CRYPTO_thread_id();
        tmp.pid=pid;
@@ -906,17 +955,17 @@ ERR_STATE *ERR_get_state(void)
                        }
                tmpp = ERRFN(thread_set_item)(ret);
                /* To check if insertion failed, do a get. */
-               if(ERRFN(thread_get_item)(ret) != ret)
+               if (ERRFN(thread_get_item)(ret) != ret)
                        {
                        ERR_STATE_free(ret); /* could not insert it */
                        return(&fallback);
                        }
                /* If a race occured in this function and we came second, tmpp
                 * is the first one that we just replaced. */
-               if(tmpp)
+               if (tmpp)
                        ERR_STATE_free(tmpp);
                }
-       return(ret);
+       return ret;
        }
 
 int ERR_get_next_error_library(void)
@@ -968,7 +1017,7 @@ void ERR_add_error_data(int num, ...)
                                if (p == NULL)
                                        {
                                        OPENSSL_free(str);
-                                       return;
+                                       goto err;
                                        }
                                else
                                        str=p;
@@ -978,5 +1027,6 @@ void ERR_add_error_data(int num, ...)
                }
        ERR_set_error_data(str,ERR_TXT_MALLOCED|ERR_TXT_STRING);
 
+err:
        va_end(args);
        }