Coverage Report

Created: 2025-06-11 06:40

/src/boringssl/crypto/thread_pthread.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2015 The BoringSSL Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
// Ensure we can't call OPENSSL_malloc circularly.
16
#define _BORINGSSL_PROHIBIT_OPENSSL_MALLOC
17
#include "internal.h"
18
19
#if defined(OPENSSL_PTHREADS)
20
21
#include <assert.h>
22
#include <pthread.h>
23
#include <stdlib.h>
24
#include <string.h>
25
26
2.68k
void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) {
27
2.68k
  if (pthread_rwlock_init(lock, NULL) != 0) {
28
0
    abort();
29
0
  }
30
2.68k
}
31
32
0
void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) {
33
0
  if (pthread_rwlock_rdlock(lock) != 0) {
34
0
    abort();
35
0
  }
36
0
}
37
38
0
void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) {
39
0
  if (pthread_rwlock_wrlock(lock) != 0) {
40
0
    abort();
41
0
  }
42
0
}
43
44
0
void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) {
45
0
  if (pthread_rwlock_unlock(lock) != 0) {
46
0
    abort();
47
0
  }
48
0
}
49
50
0
void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) {
51
0
  if (pthread_rwlock_unlock(lock) != 0) {
52
0
    abort();
53
0
  }
54
0
}
55
56
2.67k
void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { pthread_rwlock_destroy(lock); }
57
58
17.6k
void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) {
59
17.6k
  if (pthread_once(once, init) != 0) {
60
0
    abort();
61
0
  }
62
17.6k
}
63
64
static pthread_mutex_t g_destructors_lock = PTHREAD_MUTEX_INITIALIZER;
65
static thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS];
66
67
// thread_local_destructor is called when a thread exits. It releases thread
68
// local data for that thread only.
69
0
static void thread_local_destructor(void *arg) {
70
0
  if (arg == NULL) {
71
0
    return;
72
0
  }
73
74
0
  thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS];
75
0
  if (pthread_mutex_lock(&g_destructors_lock) != 0) {
76
0
    return;
77
0
  }
78
0
  OPENSSL_memcpy(destructors, g_destructors, sizeof(destructors));
79
0
  pthread_mutex_unlock(&g_destructors_lock);
80
81
0
  unsigned i;
82
0
  void **pointers = reinterpret_cast<void **>(arg);
83
0
  for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) {
84
0
    if (destructors[i] != NULL) {
85
0
      destructors[i](pointers[i]);
86
0
    }
87
0
  }
88
89
0
  free(pointers);
90
0
}
91
92
static pthread_once_t g_thread_local_init_once = PTHREAD_ONCE_INIT;
93
static pthread_key_t g_thread_local_key;
94
static int g_thread_local_key_created = 0;
95
96
1
static void thread_local_init(void) {
97
1
  g_thread_local_key_created =
98
1
      pthread_key_create(&g_thread_local_key, thread_local_destructor) == 0;
99
1
}
100
101
17.0k
void *CRYPTO_get_thread_local(thread_local_data_t index) {
102
17.0k
  CRYPTO_once(&g_thread_local_init_once, thread_local_init);
103
17.0k
  if (!g_thread_local_key_created) {
104
0
    return NULL;
105
0
  }
106
107
17.0k
  void **pointers =
108
17.0k
      reinterpret_cast<void **>(pthread_getspecific(g_thread_local_key));
109
17.0k
  if (pointers == NULL) {
110
1
    return NULL;
111
1
  }
112
17.0k
  return pointers[index];
113
17.0k
}
114
115
int CRYPTO_set_thread_local(thread_local_data_t index, void *value,
116
1
                            thread_local_destructor_t destructor) {
117
1
  CRYPTO_once(&g_thread_local_init_once, thread_local_init);
118
1
  if (!g_thread_local_key_created) {
119
0
    destructor(value);
120
0
    return 0;
121
0
  }
122
123
1
  void **pointers =
124
1
      reinterpret_cast<void **>(pthread_getspecific(g_thread_local_key));
125
1
  if (pointers == NULL) {
126
1
    pointers = reinterpret_cast<void **>(
127
1
        malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS));
128
1
    if (pointers == NULL) {
129
0
      destructor(value);
130
0
      return 0;
131
0
    }
132
1
    OPENSSL_memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS);
133
1
    if (pthread_setspecific(g_thread_local_key, pointers) != 0) {
134
0
      free(pointers);
135
0
      destructor(value);
136
0
      return 0;
137
0
    }
138
1
  }
139
140
1
  if (pthread_mutex_lock(&g_destructors_lock) != 0) {
141
0
    destructor(value);
142
0
    return 0;
143
0
  }
144
1
  g_destructors[index] = destructor;
145
1
  pthread_mutex_unlock(&g_destructors_lock);
146
147
1
  pointers[index] = value;
148
1
  return 1;
149
1
}
150
151
#endif  // OPENSSL_PTHREADS