Skip to content

Commit 41a0ddc

Browse files
author
Ole John Aske
committed
Bug#35180841 Remove requirement for md5_hash() input to be 8-byte aligned
As described in bug report, there seems to be no valid reasons for requiring the md5_hash input to be 8-byte aligned anymore. It seems to just add complexity for the caller, and sometimes an extra memcpy() may even be needed. Patch replace the Uint64 accesses in md5_hash with memcpy() instead, which seems to perform identical to the original DWORD assignments. (And generate ~identical code as well) md5_hash() signature is also changed to take a char* instead of an Uint64*. Inlined variants of md5_hash, taking an Uint32* as argument, is also provided for convenience and avoiding type casts where md5_hash is normally called with a key stored in an Uint32[] Usage of md5_hash is adapted accordingly. Allocation of temporary buffers for md5_hash as Uint64[] has been changed to Uint32[] as the Uint64 alignment requirements was removed. Change-Id: I6089a3af1436d1e73620fabf01b32082519d9b38
1 parent 2b8e632 commit 41a0ddc

File tree

15 files changed

+140
-216
lines changed

15 files changed

+140
-216
lines changed

storage/ndb/include/util/md5_hash.hpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2003, 2021, Oracle and/or its affiliates.
2+
Copyright (c) 2003, 2023, Oracle and/or its affiliates.
33
All rights reserved. Use is subject to license terms.
44
55
This program is free software; you can redistribute it and/or modify
@@ -28,15 +28,33 @@
2828

2929
#include <ndb_types.h>
3030

31-
// External declaration of hash function
32-
void md5_hash(Uint32 result[4], const Uint64* keybuf, Uint32 no_of_32_words);
31+
/**
32+
* Calculate a md5-hash of keyBuf into result. If 'no_of_bytes' in keybuf
33+
* is not an 32 bit aligned word, the hash is calculated as if keybuf
34+
* were zero-padded to the upper word aligned length.
35+
* Note that there is no alignment requirement on the keybuf itself.
36+
*/
37+
void md5_hash(Uint32 result[4],
38+
const char* keybuf,
39+
Uint32 no_of_bytes);
40+
41+
42+
// Convenient variants as keys are often stored in an Uint32 array
43+
inline
44+
void md5_hash(Uint32 result[4],
45+
const Uint32* keybuf,
46+
Uint32 no_of_words)
47+
{
48+
md5_hash(result, reinterpret_cast<const char*>(keybuf), no_of_words*4);
49+
}
3350

3451
inline
3552
Uint32
36-
md5_hash(const Uint64* keybuf, Uint32 no_of_32_words)
53+
md5_hash(const Uint32* keybuf,
54+
Uint32 no_of_words)
3755
{
3856
Uint32 result[4];
39-
md5_hash(result, keybuf, no_of_32_words);
57+
md5_hash(result, reinterpret_cast<const char*>(keybuf), no_of_words*4);
4058
return result[0];
4159
}
4260

storage/ndb/src/common/util/md5_hash.cpp

Lines changed: 58 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@
2727

2828
#include "md5_hash.hpp"
2929

30-
#ifdef WORDS_BIGENDIAN
31-
#define HIGHFIRST 1
32-
#endif
30+
#include <string.h> // memcpy()
31+
#include <my_compiler.h> // likely
32+
#include <my_config.h> // big/little endian
33+
3334

3435
/*
3536
* This code implements the MD5 message-digest algorithm.
@@ -48,25 +49,6 @@
4849
* is returned as the hash value.
4950
*/
5051

51-
#ifndef HIGHFIRST
52-
#define byteReverse(buf, len) /* Nothing */
53-
#else
54-
void byteReverse(unsigned char *buf, unsigned longs);
55-
/*
56-
* Note: this code is harmless on little-endian machines.
57-
*/
58-
void byteReverse(unsigned char *buf, unsigned longs)
59-
{
60-
Uint32 t;
61-
do {
62-
t = (Uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
63-
((unsigned) buf[1] << 8 | buf[0]);
64-
*(Uint32 *) buf = t;
65-
buf += 4;
66-
} while (--longs);
67-
}
68-
#endif
69-
7052
/* The four core functions - F1 is optimized somewhat */
7153

7254
/* #define F1(x, y, z) (x & y | ~x & z) */
@@ -168,47 +150,46 @@ static void MD5Transform(Uint32 buf[4], Uint32 const in[16])
168150
}
169151

170152
/*
171-
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
153+
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
172154
* initialization constants.
173155
*/
174-
void md5_hash(Uint32 result[4], const Uint64* keybuf, Uint32 no_of_32_words)
156+
void md5_hash(Uint32 result[4],
157+
const char* keybuf,
158+
Uint32 no_of_bytes)
175159
{
176-
/**
177-
* This is the external interface of the module
178-
* It is assumed that keybuf is placed on 8 byte
179-
* alignment.
180-
*/
181-
Uint32 i;
182160
Uint32 buf[4];
183161
union {
184162
Uint64 transform64_buf[8];
185163
Uint32 transform32_buf[16];
186164
};
187-
Uint32 len = no_of_32_words << 2;
188-
const Uint64* key64buf = (const Uint64*)keybuf;
189-
const Uint32* key32buf = (const Uint32*)keybuf;
165+
166+
// Round up to full word length
167+
const Uint32 len = (no_of_bytes + 3) & ~3;
190168

191169
buf[0] = 0x67452301;
192170
buf[1] = 0xefcdab89;
193171
buf[2] = 0x98badcfe;
194172
buf[3] = 0x10325476;
195173

196-
while (no_of_32_words >= 16) {
197-
transform64_buf[0] = key64buf[0];
198-
transform64_buf[1] = key64buf[1];
199-
transform64_buf[2] = key64buf[2];
200-
transform64_buf[3] = key64buf[3];
201-
transform64_buf[4] = key64buf[4];
202-
transform64_buf[5] = key64buf[5];
203-
transform64_buf[6] = key64buf[6];
204-
transform64_buf[7] = key64buf[7];
205-
no_of_32_words -= 16;
206-
key64buf += 8;
207-
byteReverse((unsigned char *)transform32_buf, 16);
174+
while (no_of_bytes >= 64) {
175+
memcpy(transform32_buf, keybuf, 64);
176+
keybuf += 64;
177+
no_of_bytes -= 64;
178+
MD5Transform(buf, transform32_buf);
179+
}
180+
181+
if (unlikely(no_of_bytes >= 61)) { // Will be a full frame when padded
182+
// Last word written will not be a full word -> zero pad before memcpy over
183+
transform32_buf[15] = 0;
184+
memcpy(transform32_buf, keybuf, no_of_bytes);
185+
keybuf += no_of_bytes;
186+
no_of_bytes = 0;
208187
MD5Transform(buf, transform32_buf);
209188
}
210189

211-
key32buf = (const Uint32*)key64buf;
190+
// Remaining words, including zero padding, to get to a word-aligned size.
191+
const Uint32 no_of_32_words = (no_of_bytes + 3) >> 2;
192+
212193
transform64_buf[0] = 0;
213194
transform64_buf[1] = 0;
214195
transform64_buf[2] = 0;
@@ -218,35 +199,47 @@ void md5_hash(Uint32 result[4], const Uint64* keybuf, Uint32 no_of_32_words)
218199
transform64_buf[6] = 0;
219200
transform64_buf[7] = (Uint64)len;
220201

221-
for (i = 0; i < no_of_32_words; i++)
222-
transform32_buf[i] = key32buf[i];
202+
// 0x800... Is used as an end / length mark, possibly overwriting the 'len'.
223203
transform32_buf[no_of_32_words] = 0x80000000;
224204

225-
if (no_of_32_words < 14) {
226-
byteReverse((unsigned char *)transform32_buf, 16);
227-
MD5Transform(buf, transform32_buf);
228-
} else {
229-
if (no_of_32_words == 14)
230-
transform32_buf[15] = 0;
231-
MD5Transform(buf, transform32_buf);
232-
transform64_buf[0] = 0;
233-
transform64_buf[1] = 0;
234-
transform64_buf[2] = 0;
235-
transform64_buf[3] = 0;
236-
transform64_buf[4] = 0;
237-
transform64_buf[5] = 0;
238-
transform64_buf[6] = 0;
239-
transform64_buf[7] = (Uint64)len;
240-
byteReverse((unsigned char *)transform32_buf, 16);
241-
MD5Transform(buf, transform32_buf);
205+
if (likely(no_of_32_words > 0)) {
206+
// Last word written may not be a full word -> zero pad before memcpy over
207+
transform32_buf[no_of_32_words-1] = 0;
208+
memcpy(transform32_buf, keybuf, no_of_bytes);
209+
210+
if (unlikely(no_of_32_words >= 14)) {
211+
// On a little endian platform the memcpy() + 0x800.. wrote over 'len'
212+
// located at 32_buf[14], 32_buf[15] was already zero.
213+
// On a big endian, len is written to 32_buf[15] and not written over
214+
// if '#32_words == 14' -> We clear it as it is set in next frame instead.
215+
#ifdef WORDS_BIGENDIAN
216+
if (no_of_32_words == 14)
217+
transform32_buf[15] = 0;
218+
#endif
219+
// Note: 'len' should have been written to 32_buf[15] for both
220+
// big/little endian.
221+
// For backward bug compatability it is too late to fix it now.
222+
MD5Transform(buf, transform32_buf);
223+
transform64_buf[0] = 0;
224+
transform64_buf[1] = 0;
225+
transform64_buf[2] = 0;
226+
transform64_buf[3] = 0;
227+
transform64_buf[4] = 0;
228+
transform64_buf[5] = 0;
229+
transform64_buf[6] = 0;
230+
transform64_buf[7] = (Uint64)len;
231+
}
242232
}
233+
MD5Transform(buf, transform32_buf);
243234

244235
result[0] = buf[0];
245236
result[1] = buf[1];
246237
result[2] = buf[2];
247238
result[3] = buf[3];
248239
}
249240

241+
242+
250243
//////////////////////////////////////////////////
251244
//////////////////////////////////////////////////
252245
//////////////////////////////////////////////////
@@ -371,27 +364,6 @@ test_sample test_samples[] = {
371364
};
372365
#endif
373366

374-
375-
/**
376-
* Glue function for allowing to test non-word-aligned 'no_of_bytes'.
377-
* Will zero-pad the 'key' to a word aligned length before hashing.
378-
*/
379-
void md5_hash(Uint32 result[4],
380-
const char* keybuf,
381-
Uint32 no_of_bytes)
382-
{
383-
union {
384-
char tmp[MAX_TEST_SAMPLE_WORDS*4];
385-
Uint64 _align;
386-
};
387-
memcpy(tmp, keybuf, no_of_bytes);
388-
while (no_of_bytes & 3) {
389-
tmp[no_of_bytes++] = 0;
390-
}
391-
md5_hash(result, (Uint64*)tmp, no_of_bytes / 4);
392-
}
393-
394-
395367
int main()
396368
{
397369
Uint32 test_data[MAX_TEST_SAMPLE_WORDS];

storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2003, 2022, Oracle and/or its affiliates.
2+
Copyright (c) 2003, 2023, Oracle and/or its affiliates.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -1202,11 +1202,7 @@ struct Tabrec {
12021202
BlockReference cndbcntrRef;
12031203
Uint16 csignalkey;
12041204
Uint32 czero;
1205-
union {
12061205
Uint32 ckeys[2048 * MAX_XFRM_MULTIPLY];
1207-
Uint64 ckeys_align;
1208-
};
1209-
12101206
Uint32 c_errorInsert3000_TableId;
12111207
Uint32 c_memusage_report_frequency;
12121208
};

storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2003, 2022, Oracle and/or its affiliates.
1+
/* Copyright (c) 2003, 2023, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -5846,7 +5846,7 @@ LHBits32 Dbacc::getElementHash(OperationrecPtr& oprec)
58465846
localkey = oprec.p->localdata;
58475847
Uint32 len = readTablePk(localkey.m_page_no, localkey.m_page_idx, ElementHeader::setLocked(oprec.i), oprec);
58485848
if (len > 0)
5849-
oprec.p->hashValue = LHBits32(md5_hash((Uint64*)ckeys, len));
5849+
oprec.p->hashValue = LHBits32(md5_hash(ckeys, len));
58505850
}
58515851
return oprec.p->hashValue;
58525852
}
@@ -5868,7 +5868,7 @@ LHBits32 Dbacc::getElementHash(Uint32 const* elemptr)
58685868
if (len > 0)
58695869
{
58705870
jam();
5871-
return LHBits32(md5_hash((Uint64*)ckeys, len));
5871+
return LHBits32(md5_hash(ckeys, len));
58725872
}
58735873
else
58745874
{ // Return an invalid hash value if no data

storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6221,7 +6221,7 @@ Dblqh::nr_copy_delete_row(Signal* signal,
62216221
}
62226222
else
62236223
{
6224-
req->hashValue = md5_hash((Uint64*)(signal->theData+24), len);
6224+
req->hashValue = md5_hash(signal->theData+24, len);
62256225
}
62266226
req->keyLen = 0; // seach by local key
62276227
req->localKey[0] = rowid->m_page_no;
@@ -14094,13 +14094,13 @@ Uint32
1409414094
Dblqh::calculateHash(Uint32 tableId, const Uint32* src)
1409514095
{
1409614096
jam();
14097-
Uint64 Tmp[(MAX_KEY_SIZE_IN_WORDS*MAX_XFRM_MULTIPLY) >> 1];
14097+
Uint32 tmp[MAX_KEY_SIZE_IN_WORDS*MAX_XFRM_MULTIPLY];
1409814098
Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX];
14099-
Uint32 keyLen = xfrm_key(tableId, src, (Uint32*)Tmp, sizeof(Tmp) >> 2,
14099+
Uint32 keyLen = xfrm_key(tableId, src, tmp, sizeof(tmp) >> 2,
1410014100
keyPartLen);
1410114101
ndbrequire(keyLen);
14102-
14103-
return md5_hash(Tmp, keyLen);
14102+
14103+
return md5_hash(tmp, keyLen);
1410414104
}//Dblqh::calculateHash()
1410514105

1410614106
/**
@@ -14806,7 +14806,7 @@ void Dblqh::copyTupkeyConfLab(Signal* signal)
1480614806
}
1480714807
else
1480814808
{
14809-
tcConnectptr.p->hashValue = md5_hash((Uint64*)tmp, len);
14809+
tcConnectptr.p->hashValue = md5_hash(tmp, len);
1481014810
}
1481114811

1481214812
// Copy keyinfo into long section for LQHKEYREQ below

storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2012, 2021, Oracle and/or its affiliates.
2+
Copyright (c) 2012, 2023, Oracle and/or its affiliates.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -1529,7 +1529,7 @@ class Dbspj: public SimulatedBlock {
15291529
void lookup_cleanup(Ptr<Request>, Ptr<TreeNode>);
15301530

15311531
Uint32 handle_special_hash(Uint32 tableId, Uint32 dstHash[4],
1532-
const Uint64* src,
1532+
const Uint32* src,
15331533
Uint32 srcLen, // Len in #32bit words
15341534
const struct KeyDescriptor* desc);
15351535

0 commit comments

Comments
 (0)