1
/*
2
*******************************************************************************
3
\file mem.c
4
\brief Memory management
5
\project bee2 [cryptographic library]
6
\author (C) Sergey Agievich [agievich@{bsu.by|gmail.com}]
7
\created 2012.12.18
8
\version 2019.07.09
9
\license This program is released under the GNU General Public License
10
version 3. See Copyright Notices in bee2/info.h.
11
*******************************************************************************
12
*/
13

14
#include "bee2/core/mem.h"
15
#include "bee2/core/str.h"
16
#include "bee2/core/util.h"
17
#include "bee2/core/word.h"
18

19
#ifndef OS_APPLE
20
	#include <malloc.h>
21
#else
22
	#include <stdlib.h>
23
#endif
24
#ifdef OS_WIN
25
	#include <windows.h>
26
#endif
27

28
/*
29
*******************************************************************************
30
Проверка
31

32
\todo Реализовать полноценную проверку корректности памяти.
33
*******************************************************************************
34
*/
35

36 1
bool_t memIsValid(const void* buf, size_t count)
37
{
38 1
	return count == 0 || buf != 0;
39
}
40

41 0
bool_t memIsAligned(const void* buf, size_t size)
42
{
43 0
	return (size_t)buf % size == 0;
44
}
45

46

47
/*
48
*******************************************************************************
49
Стандартные функции
50

51
\remark Перед вызовом memcpy(), memmove(), memset() проверяется, 
52
что count != 0: при count == 0 поведение стандартных функций непредсказуемо
53
(см. https://www.imperialviolet.org/2016/06/26/nonnull.html).
54

55
\remark Прямое обращение к функции ядра HeapAlloc() решает проблему 
56
с освобождением памяти в плагине bee2evp, связывающем bee2 с OpenSSL (1.1.0).
57
*******************************************************************************
58
*/
59

60 1
void memCopy(void* dest, const void* src, size_t count)
61
{
62 1
	ASSERT(memIsDisjoint(src, dest, count));
63 1
	if (count)
64 1
		memcpy(dest, src, count);
65
}
66

67 1
void memMove(void* dest, const void* src, size_t count)
68
{
69 1
	ASSERT(memIsValid(src, count));
70 1
	ASSERT(memIsValid(dest, count));
71 1
	if (count)
72 1
		memmove(dest, src, count);
73
}
74

75 1
void memSet(void* buf, octet c, size_t count)
76
{
77 1
	ASSERT(memIsValid(buf, count));
78 1
	if (count)
79 1
		memset(buf, c, count);
80
}
81

82 1
void memNeg(void* buf, size_t count)
83
{
84 1
	ASSERT(memIsValid(buf, count));
85 1
	for (; count >= O_PER_W; count -= O_PER_W)
86
	{
87 1
		*(word*)buf = ~*(word*)buf;
88 1
		buf = (word*)buf + 1;
89
	}
90 1
	while (count--)
91
	{
92 0
		*(octet*)buf = ~*(octet*)buf;
93 0
		buf = (octet*)buf + 1;
94
	}
95
}
96

97 1
void* memAlloc(size_t count)
98
{
99
#ifdef OS_WIN
100
	return HeapAlloc(GetProcessHeap(), 0, count);
101
#else
102 1
	return malloc(count);
103
#endif
104
}
105

106 1
void* memRealloc(void* buf, size_t count)
107
{
108 1
	if (count == 0)
109
	{
110 1
		memFree(buf);
111 1
		return 0;
112
	}
113
#ifdef OS_WIN
114
	if (!buf)
115
		return HeapAlloc(GetProcessHeap(), 0, count);
116
	return HeapReAlloc(GetProcessHeap(), 0, buf, count);
117
#else
118 1
	return realloc(buf, count);
119
#endif
120
}
121

122 1
void memFree(void* buf)
123
{
124
#ifdef OS_WIN
125
	HeapFree(GetProcessHeap(), 0, buf);
126
#else
127 1
	free(buf);
128
#endif
129
}
130

131
/*
132
*******************************************************************************
133
Дополнительные функции
134

135
\remark Функция memWipe() повторяет функцию OPENSSL_cleanse()
136
из библиотеки OpenSSL:
137
\code
138
	unsigned char cleanse_ctr = 0;
139
	void OPENSSL_cleanse(void *ptr, size_t len)
140
	{
141
		unsigned char *p = ptr;
142
		size_t loop = len, ctr = cleanse_ctr;
143
		while(loop--)
144
		{
145
			*(p++) = (unsigned char)ctr;
146
			ctr += (17 + ((size_t)p & 0xF));
147
		}
148
		p=memchr(ptr, (unsigned char)ctr, len);
149
		if(p)
150
			ctr += (63 + (size_t)p);
151
		cleanse_ctr = (unsigned char)ctr;
152
	}
153
\endcode
154

155
\remark На платформе Windows есть функции SecureZeroMemory()
156
и RtlSecureZeroMemory(), которые, как и memWipe(), выполняют
157
гарантированную очистку памяти.
158
*******************************************************************************
159
*/
160

161 1
bool_t SAFE(memEq)(const void* buf1, const void* buf2, size_t count)
162
{
163 1
	register word diff = 0;
164 1
	ASSERT(memIsValid(buf1, count));
165 1
	ASSERT(memIsValid(buf2, count));
166 1
	for (; count >= O_PER_W; count -= O_PER_W)
167
	{
168 1
		diff |= *(const word*)buf1 ^ *(const word*)buf2;
169 1
		buf1 = (const word*)buf1 + 1;
170 1
		buf2 = (const word*)buf2 + 1;
171
	}
172 1
	while (count--)
173
	{
174 1
		diff |= *(const octet*)buf1 ^ *(const octet*)buf2;
175 1
		buf1 = (const octet*)buf1 + 1;
176 1
		buf2 = (const octet*)buf2 + 1;
177
	}
178 1
	return wordEq(diff, 0);
179
}
180

181 1
bool_t FAST(memEq)(const void* buf1, const void* buf2, size_t count)
182
{
183 1
	ASSERT(memIsValid(buf1, count));
184 1
	ASSERT(memIsValid(buf2, count));
185 1
	return memcmp(buf1, buf2, count) == 0;
186
}
187

188 1
int SAFE(memCmp)(const void* buf1, const void* buf2, size_t count)
189
{
190 1
	register word less = 0;
191 1
	register word greater = 0;
192
	register word w1;
193
	register word w2;
194 1
	ASSERT(memIsValid(buf1, count));
195 1
	ASSERT(memIsValid(buf2, count));
196 1
	if (count % O_PER_W)
197
	{
198 1
		w1 = w2 = 0;
199 1
		while (count % O_PER_W)
200
		{
201 1
			w1 = w1 << 8 | ((const octet*)buf1)[--count];
202 1
			w2 = w2 << 8 | ((const octet*)buf2)[count];
203
		}
204 1
		less |= ~greater & wordLess01(w1, w2);
205 1
		greater |= ~less & wordGreater01(w1, w2);
206
	}
207 1
	count /= O_PER_W;
208 1
	while (count--)
209
	{
210 1
		w1 = ((const word*)buf1)[count];
211 1
		w2 = ((const word*)buf2)[count];
212
#if (OCTET_ORDER == BIG_ENDIAN)
213
		w1 = wordRev(w1);
214
		w2 = wordRev(w2);
215
#endif
216 1
		less |= ~greater & wordLess(w1, w2);
217 1
		greater |= ~less & wordGreater(w1, w2);
218
	}
219 1
	w1 = w2 = 0;
220 1
	return (wordEq(less, 0) - 1) | wordNeq(greater, 0);
221
}
222

223 1
int FAST(memCmp)(const void* buf1, const void* buf2, size_t count)
224
{
225 1
	const octet* b1 = (const octet*)buf1 + count;
226 1
	const octet* b2 = (const octet*)buf2 + count;
227 1
	ASSERT(memIsValid(buf1, count));
228 1
	ASSERT(memIsValid(buf2, count));
229 1
	while (count--)
230 1
		if (*--b1 > *--b2)
231 1
			return 1;
232 1
		else if (*b1 < *b2)
233 1
			return -1;
234 1
	return 0;
235
}
236

237 1
void memWipe(void* buf, size_t count)
238
{
239
	static octet wipe_ctr = 0;
240 1
	volatile octet* p = (octet*)buf;
241 1
	size_t ctr = wipe_ctr;
242 1
	size_t i = count;
243 1
	ASSERT(memIsValid(buf, count));
244
	// вычисления, которые должны показаться полезными оптимизатору
245 1
	while (i--)
246 1
		*(p++) = (octet)ctr, ctr += 17 + ((size_t)p & 15);
247 1
	p = memchr(buf, (octet)ctr, count);
248 1
	if (p)
249 1
		ctr += (63 + (size_t)p);
250 1
	wipe_ctr = (octet)ctr;
251
}
252

253 1
bool_t SAFE(memIsZero)(const void* buf, size_t count)
254
{
255 1
	register word diff = 0;
256 1
	ASSERT(memIsValid(buf, count));
257 1
	for (; count >= O_PER_W; count -= O_PER_W)
258
	{
259 1
		diff |= *(const word*)buf;
260 1
		buf = (const word*)buf + 1;
261
	}
262 1
	while (count--)
263
	{
264 1
		diff |= *(const octet*)buf;
265 1
		buf = (const octet*)buf + 1;
266
	}
267 1
	return (bool_t)wordEq(diff, 0);
268
}
269

270 1
bool_t FAST(memIsZero)(const void* buf, size_t count)
271
{
272 1
	ASSERT(memIsValid(buf, count));
273 1
	for (; count >= O_PER_W; count -= O_PER_W, buf = (const word*)buf + 1)
274 1
		if (*(const word*)buf)
275 1
			return FALSE;
276 1
	for (; count--; buf = (const octet*)buf + 1)
277 1
		if (*(const octet*)buf)
278 1
			return FALSE;
279 0
	return TRUE;
280
}
281

282 1
size_t memNonZeroSize(const void* buf, size_t count)
283
{
284 1
	ASSERT(memIsValid(buf, count));
285 1
	while (count--)
286 1
		if (*((const octet*)buf + count))
287 1
			return count + 1;
288 0
	return 0;
289
}
290

291 1
bool_t SAFE(memIsRep)(const void* buf, size_t count, octet o)
292
{
293 1
	register word diff = 0;
294 1
	ASSERT(memIsValid(buf, count));
295 1
	for (; count--; buf = (const octet*)buf + 1)
296 1
		diff |= *(const octet*)buf ^ o;
297 1
	return wordEq(diff, 0);
298
}
299

300 1
bool_t FAST(memIsRep)(const void* buf, size_t count, octet o)
301
{
302 1
	ASSERT(memIsValid(buf, count));
303 1
	for (; count--; buf = (const octet*)buf + 1)
304 1
		if (*(const octet*)buf != o)
305 1
			return FALSE;
306 1
	return TRUE;
307
}
308

309 1
bool_t memIsDisjoint(const void* buf1, const void* buf2, size_t count)
310
{
311 1
	ASSERT(memIsValid(buf1, count));
312 1
	ASSERT(memIsValid(buf2, count));
313 1
	return count == 0 || (const octet*)buf1 + count <= (const octet*)buf2 ||
314 1
		(const octet*)buf1 >= (const octet*)buf2 + count;
315
}
316

317 1
bool_t memIsSameOrDisjoint(const void* buf1, const void* buf2, size_t count)
318
{
319 1
	ASSERT(memIsValid(buf1, count));
320 1
	ASSERT(memIsValid(buf2, count));
321 1
	return buf1 == buf2 || count == 0 ||
322 1
		(const octet*)buf1 + count <= (const octet*)buf2 ||
323 1
		(const octet*)buf1 >= (const octet*)buf2 + count;
324
}
325

326 1
bool_t memIsDisjoint2(const void* buf1, size_t count1,
327
	const void* buf2, size_t count2)
328
{
329 1
	ASSERT(memIsValid(buf1, count1));
330 1
	ASSERT(memIsValid(buf2, count2));
331 1
	return count1 == 0 || count2 == 0 ||
332 1
		(const octet*)buf1 + count1 <= (const octet*)buf2 ||
333 1
		(const octet*)buf1 >= (const octet*)buf2 + count2;
334
}
335

336 1
bool_t memIsDisjoint3(const void* buf1, size_t count1,
337
	const void* buf2, size_t count2,
338
	const void* buf3, size_t count3)
339
{
340 1
	return memIsDisjoint2(buf1, count1, buf2, count2) &&
341 1
		memIsDisjoint2(buf1, count1, buf3, count3) &&
342 1
		memIsDisjoint2(buf2, count2, buf3, count3);
343
}
344

345 1
bool_t memIsDisjoint4(const void* buf1, size_t count1,
346
	const void* buf2, size_t count2,
347
	const void* buf3, size_t count3,
348
	const void* buf4, size_t count4)
349
{
350 1
	return memIsDisjoint2(buf1, count1, buf2, count2) &&
351 1
		memIsDisjoint2(buf1, count1, buf3, count3) &&
352 1
		memIsDisjoint2(buf1, count1, buf4, count4) &&
353 1
		memIsDisjoint3(buf2, count2, buf3, count3, buf4, count4);
354
}
355

356 1
void memJoin(void* dest, const void* src1, size_t count1, const void* src2,
357
	size_t count2)
358
{
359
	register octet o;
360
	size_t i;
361 1
	ASSERT(memIsValid(src1, count1));
362 1
	ASSERT(memIsValid(src2, count2));
363 1
	ASSERT(memIsValid(dest, count1 + count2));
364
repeat:
365 1
	if (memIsDisjoint2(dest, count1, src2, count2))
366
	{
367 1
		memMove(dest, src1, count1);
368 1
		memMove((octet*)dest + count1, src2, count2);
369
	}
370 1
	else if (memIsDisjoint2((octet*)dest + count1, count2, src1, count1))
371
	{
372 1
		memMove((octet*)dest + count1, src2, count2);
373 1
		memMove(dest, src1, count1);
374
	}
375 1
	else if (memIsDisjoint2(dest, count2, src1, count1))
376
	{
377
		// dest <- src2 || src1
378 1
		memMove(dest, src2, count2);
379 1
		memMove((octet*)dest + count2, src1, count1);
380
		// dest <- dest <<< count2
381 1
		for (i = 0; i < count2; ++i)
382
		{
383 1
			o = ((octet*)dest)[0];
384 1
			memMove(dest, (octet*)dest + 1, count1 + count2 - 1);
385 1
			((octet*)dest)[count1 + count2 - 1] = o;
386
		}
387
	}
388 1
	else if (memIsDisjoint2((octet*)dest + count2, count1, src2, count2))
389
	{
390
		// dest <- src2 || src1
391 1
		memMove((octet*)dest + count2, src1, count1);
392 1
		memMove(dest, src2, count2);
393
		// dest <- dest <<< count2
394 1
		for (i = 0; i < count2; ++i)
395
		{
396 1
			o = ((octet*)dest)[0];
397 1
			memMove(dest, (octet*)dest + 1, count1 + count2 - 1);
398 1
			((octet*)dest)[count1 + count2 - 1] = o;
399
		}
400
	}
401
	else
402
	{
403
		// src1 (src2) пересекается и с префиксом, и с суффиксом dest
404
		// длины count2 (count1) => и первый, и последний октет dest
405
		// не входят не входят ни в src1, ни в src2
406 1
		((octet*)dest)[0] = ((const octet*)src1)[0];
407 1
		((octet*)dest)[count1 + count2 - 1] = ((const octet*)src2)[count2 - 1];
408 1
		VERIFY(count1--);
409 1
		VERIFY(count2--);
410 1
		src1 = (const octet*)src1 + 1;
411 1
		dest = (octet*)dest + 1;
412 1
		goto repeat;
413
	}
414
}
415

416 1
void memXor(void* dest, const void* src1, const void* src2, size_t count)
417
{
418 1
	ASSERT(memIsSameOrDisjoint(src1, dest, count));
419 1
	ASSERT(memIsSameOrDisjoint(src2, dest, count));
420 1
	for (; count >= O_PER_W; count -= O_PER_W)
421
	{
422 1
		*(word*)dest = *(const word*)src1 ^ *(const word*)src2;
423 1
		src1 = (const word*)src1 + 1;
424 1
		src2 = (const word*)src2 + 1;
425 1
		dest = (word*)dest + 1;
426
	}
427 1
	while (count--)
428
	{
429 1
		*(octet*)dest = *(const octet*)src1 ^ *(const octet*)src2;
430 1
		src1 = (const octet*)src1 + 1;
431 1
		src2 = (const octet*)src2 + 1;
432 1
		dest = (octet*)dest + 1;
433
	}
434
}
435

436 1
void memXor2(void* dest, const void* src, size_t count)
437
{
438 1
	ASSERT(memIsSameOrDisjoint(src, dest, count));
439 1
	for (; count >= O_PER_W; count -= O_PER_W)
440
	{
441 1
		*(word*)dest ^= *(const word*)src;
442 1
		src = (const word*)src + 1;
443 1
		dest = (word*)dest + 1;
444
	}
445 1
	while (count--)
446
	{
447 1
		*(octet*)dest ^= *(const octet*)src;
448 1
		src = (const octet*)src + 1;
449 1
		dest = (octet*)dest + 1;
450
	}
451
}
452

453 1
void memSwap(void* buf1, void* buf2, size_t count)
454
{
455 1
	ASSERT(memIsDisjoint(buf1, buf2, count));
456 1
	for (; count >= O_PER_W; count -= O_PER_W)
457
	{
458 1
		SWAP(*(word*)buf1, *(word*)buf2);
459 1
		buf1 = (word*)buf1 + 1;
460 1
		buf2 = (word*)buf2 + 1;
461
	}
462 1
	while (count--)
463
	{
464 1
		SWAP(*(octet*)buf1, *(octet*)buf2);
465 1
		buf1 = (octet*)buf1 + 1;
466 1
		buf2 = (octet*)buf2 + 1;
467
	}
468
}
469

470
/*
471
*******************************************************************************
472
Реверс октетов
473
*******************************************************************************
474
*/
475

476 1
void memRev(void* buf, size_t count)
477
{
478 1
	register size_t i = count / 2;
479 1
	ASSERT(memIsValid(buf, count));
480 1
	while (i--)
481
	{
482 1
		((octet*)buf)[i] ^= ((octet*)buf)[count - 1 - i];
483 1
		((octet*)buf)[count - 1 - i] ^= ((octet*)buf)[i];
484 1
		((octet*)buf)[i] ^= ((octet*)buf)[count - 1 - i];
485
	}
486
}

Read our documentation on viewing source code .

Loading