| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
To the extent possible under law, the author has dedicated all copyright |
|
4
|
|
|
|
|
|
|
and related and neighboring rights to this software to the public domain |
|
5
|
|
|
|
|
|
|
worldwide. This software is distributed without any warranty. |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
See . */ |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#include "git2_util.h" |
|
10
|
|
|
|
|
|
|
#include "rand.h" |
|
11
|
|
|
|
|
|
|
#include "runtime.h" |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#if defined(GIT_RAND_GETENTROPY) |
|
14
|
|
|
|
|
|
|
# include |
|
15
|
|
|
|
|
|
|
#endif |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
static uint64_t state[4]; |
|
18
|
|
|
|
|
|
|
static git_mutex state_lock; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
typedef union { |
|
21
|
|
|
|
|
|
|
double f; |
|
22
|
|
|
|
|
|
|
uint64_t d; |
|
23
|
|
|
|
|
|
|
} bits; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
#if defined(GIT_WIN32) |
|
26
|
|
|
|
|
|
|
GIT_INLINE(int) getseed(uint64_t *seed) |
|
27
|
|
|
|
|
|
|
{ |
|
28
|
|
|
|
|
|
|
HCRYPTPROV provider; |
|
29
|
|
|
|
|
|
|
SYSTEMTIME systemtime; |
|
30
|
|
|
|
|
|
|
FILETIME filetime, idletime, kerneltime, usertime; |
|
31
|
|
|
|
|
|
|
bits convert; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
if (CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, |
|
34
|
|
|
|
|
|
|
CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { |
|
35
|
|
|
|
|
|
|
BOOL success = CryptGenRandom(provider, sizeof(uint64_t), (void *)seed); |
|
36
|
|
|
|
|
|
|
CryptReleaseContext(provider, 0); |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
if (success) |
|
39
|
|
|
|
|
|
|
return 0; |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
GetSystemTime(&systemtime); |
|
43
|
|
|
|
|
|
|
if (!SystemTimeToFileTime(&systemtime, &filetime)) { |
|
44
|
|
|
|
|
|
|
git_error_set(GIT_ERROR_OS, "could not get time for random seed"); |
|
45
|
|
|
|
|
|
|
return -1; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
/* Fall-through: generate a seed from the time and system state */ |
|
49
|
|
|
|
|
|
|
*seed = 0; |
|
50
|
|
|
|
|
|
|
*seed |= ((uint64_t)filetime.dwLowDateTime << 32); |
|
51
|
|
|
|
|
|
|
*seed |= ((uint64_t)filetime.dwHighDateTime); |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
GetSystemTimes(&idletime, &kerneltime, &usertime); |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
*seed ^= ((uint64_t)idletime.dwLowDateTime << 32); |
|
56
|
|
|
|
|
|
|
*seed ^= ((uint64_t)kerneltime.dwLowDateTime); |
|
57
|
|
|
|
|
|
|
*seed ^= ((uint64_t)usertime.dwLowDateTime << 32); |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
*seed ^= ((uint64_t)idletime.dwHighDateTime); |
|
60
|
|
|
|
|
|
|
*seed ^= ((uint64_t)kerneltime.dwHighDateTime << 12); |
|
61
|
|
|
|
|
|
|
*seed ^= ((uint64_t)usertime.dwHighDateTime << 24); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
*seed ^= ((uint64_t)GetCurrentProcessId() << 32); |
|
64
|
|
|
|
|
|
|
*seed ^= ((uint64_t)GetCurrentThreadId() << 48); |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
convert.f = git__timer(); *seed ^= (convert.d); |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
/* Mix in the addresses of some functions and variables */ |
|
69
|
|
|
|
|
|
|
*seed ^= (((uint64_t)((uintptr_t)seed) << 32)); |
|
70
|
|
|
|
|
|
|
*seed ^= (((uint64_t)((uintptr_t)&errno))); |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
return 0; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
#else |
|
76
|
|
|
|
|
|
|
|
|
77
|
87
|
|
|
|
|
|
GIT_INLINE(int) getseed(uint64_t *seed) |
|
78
|
|
|
|
|
|
|
{ |
|
79
|
|
|
|
|
|
|
struct timeval tv; |
|
80
|
|
|
|
|
|
|
double loadavg[3]; |
|
81
|
|
|
|
|
|
|
bits convert; |
|
82
|
|
|
|
|
|
|
int fd; |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# if defined(GIT_RAND_GETENTROPY) |
|
85
|
|
|
|
|
|
|
GIT_UNUSED((fd = 0)); |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
if (getentropy(seed, sizeof(uint64_t)) == 0) |
|
88
|
|
|
|
|
|
|
return 0; |
|
89
|
|
|
|
|
|
|
# else |
|
90
|
|
|
|
|
|
|
/* |
|
91
|
|
|
|
|
|
|
* Try to read from /dev/urandom; most modern systems will have |
|
92
|
|
|
|
|
|
|
* this, but we may be chrooted, etc, so it's not a fatal error |
|
93
|
|
|
|
|
|
|
*/ |
|
94
|
87
|
50
|
|
|
|
|
if ((fd = open("/dev/urandom", O_RDONLY)) >= 0) { |
|
95
|
87
|
|
|
|
|
|
ssize_t ret = read(fd, seed, sizeof(uint64_t)); |
|
96
|
87
|
|
|
|
|
|
close(fd); |
|
97
|
|
|
|
|
|
|
|
|
98
|
87
|
50
|
|
|
|
|
if (ret == (ssize_t)sizeof(uint64_t)) |
|
99
|
87
|
|
|
|
|
|
return 0; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
# endif |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
/* Fall-through: generate a seed from the time and system state */ |
|
104
|
0
|
0
|
|
|
|
|
if (gettimeofday(&tv, NULL) < 0) { |
|
105
|
0
|
|
|
|
|
|
git_error_set(GIT_ERROR_OS, "could get time for random seed"); |
|
106
|
0
|
|
|
|
|
|
return -1; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
|
*seed = 0; |
|
110
|
0
|
|
|
|
|
|
*seed |= ((uint64_t)tv.tv_usec << 40); |
|
111
|
0
|
|
|
|
|
|
*seed |= ((uint64_t)tv.tv_sec); |
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getpid() << 48); |
|
114
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getppid() << 32); |
|
115
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getpgid(0) << 28); |
|
116
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getsid(0) << 16); |
|
117
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getuid() << 8); |
|
118
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)getgid()); |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# if defined(GIT_RAND_GETLOADAVG) |
|
121
|
|
|
|
|
|
|
getloadavg(loadavg, 3); |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
convert.f = loadavg[0]; *seed ^= (convert.d >> 36); |
|
124
|
|
|
|
|
|
|
convert.f = loadavg[1]; *seed ^= (convert.d); |
|
125
|
|
|
|
|
|
|
convert.f = loadavg[2]; *seed ^= (convert.d >> 16); |
|
126
|
|
|
|
|
|
|
# else |
|
127
|
0
|
|
|
|
|
|
GIT_UNUSED(loadavg[0]); |
|
128
|
|
|
|
|
|
|
# endif |
|
129
|
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
convert.f = git__timer(); *seed ^= (convert.d); |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
/* Mix in the addresses of some variables */ |
|
133
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)((size_t)((void *)seed)) << 32); |
|
134
|
0
|
|
|
|
|
|
*seed ^= ((uint64_t)((size_t)((void *)&errno))); |
|
135
|
|
|
|
|
|
|
|
|
136
|
87
|
|
|
|
|
|
return 0; |
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
#endif |
|
139
|
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
|
static void git_rand_global_shutdown(void) |
|
141
|
|
|
|
|
|
|
{ |
|
142
|
0
|
|
|
|
|
|
git_mutex_free(&state_lock); |
|
143
|
0
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
87
|
|
|
|
|
|
int git_rand_global_init(void) |
|
146
|
|
|
|
|
|
|
{ |
|
147
|
87
|
|
|
|
|
|
uint64_t seed = 0; |
|
148
|
|
|
|
|
|
|
|
|
149
|
87
|
50
|
|
|
|
|
if (git_mutex_init(&state_lock) < 0 || getseed(&seed) < 0) |
|
|
|
50
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
return -1; |
|
151
|
|
|
|
|
|
|
|
|
152
|
87
|
50
|
|
|
|
|
if (!seed) { |
|
153
|
0
|
|
|
|
|
|
git_error_set(GIT_ERROR_INTERNAL, "failed to generate random seed"); |
|
154
|
0
|
|
|
|
|
|
return -1; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
87
|
|
|
|
|
|
git_rand_seed(seed); |
|
158
|
87
|
|
|
|
|
|
git_runtime_shutdown_register(git_rand_global_shutdown); |
|
159
|
|
|
|
|
|
|
|
|
160
|
87
|
|
|
|
|
|
return 0; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
/* |
|
164
|
|
|
|
|
|
|
* This is splitmix64. xoroshiro256** uses 256 bit seed; this is used |
|
165
|
|
|
|
|
|
|
* to generate 256 bits of seed from the given 64, per the author's |
|
166
|
|
|
|
|
|
|
* recommendation. |
|
167
|
|
|
|
|
|
|
*/ |
|
168
|
348
|
|
|
|
|
|
GIT_INLINE(uint64_t) splitmix64(uint64_t *in) |
|
169
|
|
|
|
|
|
|
{ |
|
170
|
|
|
|
|
|
|
uint64_t z; |
|
171
|
|
|
|
|
|
|
|
|
172
|
348
|
|
|
|
|
|
*in += 0x9e3779b97f4a7c15; |
|
173
|
|
|
|
|
|
|
|
|
174
|
348
|
|
|
|
|
|
z = *in; |
|
175
|
348
|
|
|
|
|
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; |
|
176
|
348
|
|
|
|
|
|
z = (z ^ (z >> 27)) * 0x94d049bb133111eb; |
|
177
|
348
|
|
|
|
|
|
return z ^ (z >> 31); |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
87
|
|
|
|
|
|
void git_rand_seed(uint64_t seed) |
|
181
|
|
|
|
|
|
|
{ |
|
182
|
|
|
|
|
|
|
uint64_t mixer; |
|
183
|
|
|
|
|
|
|
|
|
184
|
87
|
|
|
|
|
|
mixer = seed; |
|
185
|
|
|
|
|
|
|
|
|
186
|
87
|
|
|
|
|
|
git_mutex_lock(&state_lock); |
|
187
|
87
|
|
|
|
|
|
state[0] = splitmix64(&mixer); |
|
188
|
87
|
|
|
|
|
|
state[1] = splitmix64(&mixer); |
|
189
|
87
|
|
|
|
|
|
state[2] = splitmix64(&mixer); |
|
190
|
87
|
|
|
|
|
|
state[3] = splitmix64(&mixer); |
|
191
|
87
|
|
|
|
|
|
git_mutex_unlock(&state_lock); |
|
192
|
87
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid |
|
195
|
|
|
|
|
|
|
generators. It has excellent (sub-ns) speed, a state (256 bits) that is |
|
196
|
|
|
|
|
|
|
large enough for any parallel application, and it passes all tests we |
|
197
|
|
|
|
|
|
|
are aware of. |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
For generating just floating-point numbers, xoshiro256+ is even faster. |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
The state must be seeded so that it is not everywhere zero. If you have |
|
202
|
|
|
|
|
|
|
a 64-bit seed, we suggest to seed a splitmix64 generator and use its |
|
203
|
|
|
|
|
|
|
output to fill s. */ |
|
204
|
|
|
|
|
|
|
|
|
205
|
374
|
|
|
|
|
|
GIT_INLINE(uint64_t) rotl(const uint64_t x, int k) { |
|
206
|
374
|
|
|
|
|
|
return (x << k) | (x >> (64 - k)); |
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
|
|
209
|
187
|
|
|
|
|
|
uint64_t git_rand_next(void) { |
|
210
|
|
|
|
|
|
|
uint64_t t, result; |
|
211
|
|
|
|
|
|
|
|
|
212
|
187
|
|
|
|
|
|
git_mutex_lock(&state_lock); |
|
213
|
|
|
|
|
|
|
|
|
214
|
187
|
|
|
|
|
|
result = rotl(state[1] * 5, 7) * 9; |
|
215
|
|
|
|
|
|
|
|
|
216
|
187
|
|
|
|
|
|
t = state[1] << 17; |
|
217
|
|
|
|
|
|
|
|
|
218
|
187
|
|
|
|
|
|
state[2] ^= state[0]; |
|
219
|
187
|
|
|
|
|
|
state[3] ^= state[1]; |
|
220
|
187
|
|
|
|
|
|
state[1] ^= state[2]; |
|
221
|
187
|
|
|
|
|
|
state[0] ^= state[3]; |
|
222
|
|
|
|
|
|
|
|
|
223
|
187
|
|
|
|
|
|
state[2] ^= t; |
|
224
|
|
|
|
|
|
|
|
|
225
|
187
|
|
|
|
|
|
state[3] = rotl(state[3], 45); |
|
226
|
|
|
|
|
|
|
|
|
227
|
187
|
|
|
|
|
|
git_mutex_unlock(&state_lock); |
|
228
|
|
|
|
|
|
|
|
|
229
|
187
|
|
|
|
|
|
return result; |
|
230
|
|
|
|
|
|
|
} |