cryptlib.c: eliminate dependency on _strtoui64, older Windows CRT don't have it.
[openssl.git] / crypto / cryptlib.c
index b8c2ee80f649cb605c42510ea0c12add65daec30..bb54e6485ad0efa18dbcaac1f0dc05120ea54489 100644 (file)
@@ -165,7 +165,9 @@ static const char* const lock_names[CRYPTO_NUM_LOCKS] =
        "ec_pre_comp",
        "store",
        "comp",
-#if CRYPTO_NUM_LOCKS != 39
+       "fips",
+       "fips2",
+#if CRYPTO_NUM_LOCKS != 41
 # error "Inconsistency between crypto.h and cryptlib.c"
 #endif
        };
@@ -184,8 +186,10 @@ static void (MS_FAR *locking_callback)(int mode,int type,
        const char *file,int line)=0;
 static int (MS_FAR *add_lock_callback)(int *pointer,int amount,
        int type,const char *file,int line)=0;
+#ifndef OPENSSL_NO_DEPRECATED
 static unsigned long (MS_FAR *id_callback)(void)=0;
-static void *(MS_FAR *idptr_callback)(void)=0;
+#endif
+static void (MS_FAR *threadid_callback)(CRYPTO_THREADID *)=0;
 static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback)
        (const char *file,int line)=0;
 static void (MS_FAR *dynlock_lock_callback)(int mode,
@@ -201,7 +205,7 @@ int CRYPTO_get_new_lockid(char *name)
 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16)
        /* A hack to make Visual C++ 5.0 work correctly when linking as
         * a DLL using /MT. Without this, the application cannot use
-        * and floating point printf's.
+        * any floating point printf's.
         * It also seems to be needed for Visual C 1.5 (win16) */
        SSLeay_MSVC5_hack=(double)name[0]*(double)name[1];
 #endif
@@ -414,54 +418,105 @@ void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
        add_lock_callback=func;
        }
 
-/* Thread IDs. So ... if we build without OPENSSL_NO_DEPRECATED, then we leave
- * the existing implementations and just layer CRYPTO_THREADID_[get|cmp]
- * harmlessly on top. Otherwise, we only use 'id_callback' or 'idptr_callback'
- * if they're non-NULL, ie. we ignore CRYPTO_thread_id()'s fallbacks and we
- * move CRYPTO_thread_idptr()'s "&errno" fallback trick into
- * CRYPTO_THREADID_set(). */
+/* the memset() here and in set_pointer() seem overkill, but for the sake of
+ * CRYPTO_THREADID_cmp() this avoids any platform silliness that might cause two
+ * "equal" THREADID structs to not be memcmp()-identical. */
+void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val)
+       {
+       memset(id, 0, sizeof(*id));
+       id->val = val;
+       }
 
-void CRYPTO_set_id_callback(unsigned long (*func)(void))
+static const unsigned char hash_coeffs[] = { 3, 5, 7, 11, 13, 17, 19, 23 };
+void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr)
        {
-       id_callback=func;
+       unsigned char *dest = (void *)&id->val;
+       unsigned int accum = 0;
+       unsigned char dnum = sizeof(id->val);
+
+       memset(id, 0, sizeof(*id));
+       id->ptr = ptr;
+       if (sizeof(id->val) >= sizeof(id->ptr))
+               {
+               /* 'ptr' can be embedded in 'val' without loss of uniqueness */
+               id->val = (unsigned long)id->ptr;
+               return;
+               }
+       /* hash ptr ==> val. Each byte of 'val' gets the mod-256 total of a
+        * linear function over the bytes in 'ptr', the co-efficients of which
+        * are a sequence of low-primes (hash_coeffs is an 8-element cycle) -
+        * the starting prime for the sequence varies for each byte of 'val'
+        * (unique polynomials unless pointers are >64-bit). For added spice,
+        * the totals accumulate rather than restarting from zero, and the index
+        * of the 'val' byte is added each time (position dependence). If I was
+        * a black-belt, I'd scan big-endian pointers in reverse to give
+        * low-order bits more play, but this isn't crypto and I'd prefer nobody
+        * mistake it as such. Plus I'm lazy. */
+       while (dnum--)
+               {
+               const unsigned char *src = (void *)&id->ptr;
+               unsigned char snum = sizeof(id->ptr);
+               while (snum--)
+                       accum += *(src++) * hash_coeffs[(snum + dnum) & 7];
+               accum += dnum;
+               *(dest++) = accum & 255;
+               }
        }
 
-void CRYPTO_set_idptr_callback(void *(*func)(void))
+int CRYPTO_THREADID_set_callback(void (*func)(CRYPTO_THREADID *))
        {
-       idptr_callback=func;
+       if (threadid_callback)
+               return 0;
+       threadid_callback = func;
+       return 1;
        }
 
-void CRYPTO_THREADID_set(CRYPTO_THREADID *id)
+void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *)
        {
-       if (id_callback)
-               id->ulong = id_callback();
-       else
-               id->ulong = 0;
+       return threadid_callback;
+       }
 
-       if (idptr_callback)
-               id->ptr = idptr_callback();
-       else
-               id->ptr = &errno;
+void CRYPTO_THREADID_current(CRYPTO_THREADID *id)
+       {
+       if (threadid_callback)
+               {
+               threadid_callback(id);
+               return;
+               }
+#ifndef OPENSSL_NO_DEPRECATED
+       /* If the deprecated callback was set, fall back to that */
+       if (id_callback)
+               {
+               CRYPTO_THREADID_set_numeric(id, id_callback());
+               return;
+               }
+#endif
+       /* Else pick a backup */
+#ifdef OPENSSL_SYS_WIN16
+       CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentTask());
+#elif defined(OPENSSL_SYS_WIN32)
+       CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentThreadId());
+#elif defined(OPENSSL_SYS_BEOS)
+       CRYPTO_THREADID_set_numeric(id, (unsigned long)find_thread(NULL));
+#else
+       /* For everything else, default to using the address of 'errno' */
+       CRYPTO_THREADID_set_pointer(id, &errno);
+#endif
        }
 
-int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *id1, const CRYPTO_THREADID *id2)
+int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b)
        {
-       if (id1->ulong != id2->ulong)
-               return ((id1->ulong < id2->ulong) ? -1 : 1);
-       if (id1->ptr != id2->ptr)
-               return ((id1->ptr < id2->ptr) ? -1 : 1);
-       return 0;
+       return memcmp(a, b, sizeof(*a));
        }
 
-unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id)
+void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src)
        {
-       /* will need further processing to arrive at a good hash (mem_dbg.c uses this) */
-       return id->ulong + (unsigned long)id->ptr;
+       memcpy(dest, src, sizeof(*src));
        }
 
-void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dst, const CRYPTO_THREADID *src)
+unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id)
        {
-       memcpy(dst, src, sizeof(*src));
+       return id->val;
        }
 
 #ifndef OPENSSL_NO_DEPRECATED
@@ -470,6 +525,11 @@ unsigned long (*CRYPTO_get_id_callback(void))(void)
        return(id_callback);
        }
 
+void CRYPTO_set_id_callback(unsigned long (*func)(void))
+       {
+       id_callback=func;
+       }
+
 unsigned long CRYPTO_thread_id(void)
        {
        unsigned long ret=0;
@@ -498,8 +558,8 @@ void CRYPTO_lock(int mode, int type, const char *file, int line)
        {
 #ifdef LOCK_DEBUG
                {
+               CRYPTO_THREADID id;
                char *rw_text,*operation_text;
-               CRYPTO_THREADID tid;
 
                if (mode & CRYPTO_LOCK)
                        operation_text="lock  ";
@@ -515,9 +575,9 @@ void CRYPTO_lock(int mode, int type, const char *file, int line)
                else
                        rw_text="ERROR";
 
-               CRYPTO_THREADID_set(&tid);
+               CRYPTO_THREADID_current(&id);
                fprintf(stderr,"lock:%08lx:(%s)%s %-18s %s:%d\n",
-                       CRYPTO_THREADID_hash(&tid), rw_text, operation_text,
+                       CRYPTO_THREADID_hash(&id), rw_text, operation_text,
                        CRYPTO_get_lock_name(type), file, line);
                }
 #endif
@@ -544,10 +604,6 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
             int line)
        {
        int ret = 0;
-#ifdef LOCK_DEBUG
-       CRYPTO_THREADID tid;
-       CRYPTO_THREADID_set(&tid);
-#endif
 
        if (add_lock_callback != NULL)
                {
@@ -557,10 +613,14 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
 
                ret=add_lock_callback(pointer,amount,type,file,line);
 #ifdef LOCK_DEBUG
+               {
+               CRYPTO_THREADID id;
+               CRYPTO_THREADID_current(&id);
                fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
-                       CRYPTO_THREADID_hash(&tid), before,amount,ret,
+                       CRYPTO_THREADID_hash(&id), before,amount,ret,
                        CRYPTO_get_lock_name(type),
                        file,line);
+               }
 #endif
                }
        else
@@ -569,10 +629,15 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
 
                ret= *pointer+amount;
 #ifdef LOCK_DEBUG
+               {
+               CRYPTO_THREADID id;
+               CRYPTO_THREADID_current(&id);
                fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
-                       CRYPTO_THREADID_hash(&tid), *pointer,amount,ret,
+                       CRYPTO_THREADID_hash(&id),
+                       *pointer,amount,ret,
                        CRYPTO_get_lock_name(type),
                        file,line);
+               }
 #endif
                *pointer=ret;
                CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,file,line);
@@ -594,35 +659,48 @@ const char *CRYPTO_get_lock_name(int type)
 
 #if    defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
        defined(__INTEL__) || \
-       defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64)
+       defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
 
-unsigned long  OPENSSL_ia32cap_P=0;
-unsigned long *OPENSSL_ia32cap_loc(void) { return &OPENSSL_ia32cap_P; }
+unsigned int  OPENSSL_ia32cap_P[2];
+unsigned int *OPENSSL_ia32cap_loc(void) { return OPENSSL_ia32cap_P; }
 
 #if defined(OPENSSL_CPUID_OBJ) && !defined(OPENSSL_NO_ASM) && !defined(I386_ONLY)
 #define OPENSSL_CPUID_SETUP
+#if defined(_WIN32)
+typedef unsigned __int64 IA32CAP;
+#else
+typedef unsigned long long IA32CAP;
+#endif
 void OPENSSL_cpuid_setup(void)
 { static int trigger=0;
-  unsigned long OPENSSL_ia32_cpuid(void);
+  IA32CAP OPENSSL_ia32_cpuid(void);
+  IA32CAP vec;
   char *env;
 
     if (trigger)       return;
 
     trigger=1;
     if ((env=getenv("OPENSSL_ia32cap")))
-       OPENSSL_ia32cap_P = strtoul(env,NULL,0)|(1<<10);
+#if defined(_WIN32)
+    {  if (!sscanf(env,"%I64i",&vec)) vec = strtoul(env,NULL,0);   }
+#else
+       vec = strtoull(env,NULL,0);
+#endif
     else
-       OPENSSL_ia32cap_P = OPENSSL_ia32_cpuid()|(1<<10);
+       vec = OPENSSL_ia32_cpuid();
+
     /*
      * |(1<<10) sets a reserved bit to signal that variable
      * was initialized already... This is to avoid interference
      * with cpuid snippets in ELF .init segment.
      */
+    OPENSSL_ia32cap_P[0] = (unsigned int)vec|(1<<10);
+    OPENSSL_ia32cap_P[1] = (unsigned int)(vec>>32);
 }
 #endif
 
 #else
-unsigned long *OPENSSL_ia32cap_loc(void) { return NULL; }
+unsigned int *OPENSSL_ia32cap_loc(void) { return NULL; }
 #endif
 int OPENSSL_NONPIC_relocated = 0;
 #if !defined(OPENSSL_CPUID_SETUP) && !defined(OPENSSL_CPUID_OBJ)