Skip to content

Commit b45ce94

Browse files
authored
Merge pull request #2522 from spevans/pr_unaligned_access
2 parents 792f401 + 73daa3e commit b45ce94

File tree

5 files changed

+130
-32
lines changed

5 files changed

+130
-32
lines changed

CoreFoundation/Base.subproj/CFInternal.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,5 +1044,79 @@ CF_PRIVATE const CFStringRef __kCFLocaleCollatorID;
10441044

10451045
CF_EXTERN_C_END
10461046

1047+
1048+
// Load 16,32,64 bit values from unaligned memory addresses. These need to be done bytewise otherwise
1049+
// it is undefined behaviour in C. On some architectures, eg x86, unaligned loads are allowed by the
1050+
// processor and the compiler will convert these byte accesses into the appropiate DWORD/QWORD memory
1051+
// access.
1052+
1053+
CF_INLINE uint32_t unaligned_load32(const void *ptr) {
1054+
uint8_t *bytes = (uint8_t *)ptr;
1055+
#if __LITTLE_ENDIAN__
1056+
uint32_t result = (uint32_t)bytes[0];
1057+
result |= ((uint32_t)bytes[1] << 8);
1058+
result |= ((uint32_t)bytes[2] << 16);
1059+
result |= ((uint32_t)bytes[3] << 24);
1060+
#else
1061+
uint32_t result = (uint32_t)bytes[0] << 24;
1062+
result |= ((uint32_t)bytes[1] << 16);
1063+
result |= ((uint32_t)bytes[2] << 8);
1064+
result |= (uint32_t)bytes[3];
1065+
#endif
1066+
return result;
1067+
}
1068+
1069+
1070+
CF_INLINE void unaligned_store32(void *ptr, uint32_t value) {
1071+
uint8_t *bytes = (uint8_t *)ptr;
1072+
#if __LITTLE_ENDIAN__
1073+
bytes[0] = (uint8_t)(value & 0xff);
1074+
bytes[1] = (uint8_t)((value >> 8) & 0xff);
1075+
bytes[2] = (uint8_t)((value >> 16) & 0xff);
1076+
bytes[3] = (uint8_t)((value >> 24) & 0xff);
1077+
#else
1078+
bytes[0] = (uint8_t)((value >> 24) & 0xff);
1079+
bytes[1] = (uint8_t)((value >> 16) & 0xff);
1080+
bytes[2] = (uint8_t)((value >> 8) & 0xff);
1081+
bytes[3] = (uint8_t)((value >> 0) & 0xff);
1082+
#endif
1083+
}
1084+
1085+
1086+
// Load values stored in Big Endian order in memory.
1087+
CF_INLINE uint16_t unaligned_load16be(const void *ptr) {
1088+
uint8_t *bytes = (uint8_t *)ptr;
1089+
uint16_t result = (uint16_t)bytes[0] << 8;
1090+
result |= (uint16_t)bytes[1];
1091+
1092+
return result;
1093+
}
1094+
1095+
1096+
CF_INLINE uint32_t unaligned_load32be(const void *ptr) {
1097+
uint8_t *bytes = (uint8_t *)ptr;
1098+
uint32_t result = (uint32_t)bytes[0] << 24;
1099+
result |= ((uint32_t)bytes[1] << 16);
1100+
result |= ((uint32_t)bytes[2] << 8);
1101+
result |= (uint32_t)bytes[3];
1102+
1103+
return result;
1104+
}
1105+
1106+
1107+
CF_INLINE uint64_t unaligned_load64be(const void *ptr) {
1108+
uint8_t *bytes = (uint8_t *)ptr;
1109+
uint64_t result = (uint64_t)bytes[0] << 56;
1110+
result |= ((uint64_t)bytes[1] << 48);
1111+
result |= ((uint64_t)bytes[2] << 40);
1112+
result |= ((uint64_t)bytes[3] << 32);
1113+
result |= ((uint64_t)bytes[4] << 24);
1114+
result |= ((uint64_t)bytes[5] << 16);
1115+
result |= ((uint64_t)bytes[6] << 8);
1116+
result |= (uint64_t)bytes[7];
1117+
1118+
return result;
1119+
}
1120+
10471121
#endif /* ! __COREFOUNDATION_CFINTERNAL__ */
10481122

CoreFoundation/Parsing.subproj/CFBinaryPList.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CF
501501
CFDictionaryAddValue(objtable, plist, (const void *)(uintptr_t)refnum);
502502
if (_kCFRuntimeIDCFDictionary == type) {
503503
CFIndex count = CFDictionaryGetCount((CFDictionaryRef)plist);
504-
STACK_BUFFER_DECL(CFPropertyListRef, buffer, count <= 128 ? count * 2 : 1);
504+
STACK_BUFFER_DECL(CFPropertyListRef, buffer, (count > 0 && count <= 128) ? count * 2 : 1);
505505
CFPropertyListRef *list = (count <= 128) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0);
506506
CFDictionaryGetKeysAndValues((CFDictionaryRef)plist, list, list + count);
507507
for (CFIndex idx = 0; idx < 2 * count; idx++) {
@@ -510,7 +510,7 @@ static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CF
510510
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
511511
} else if (_kCFRuntimeIDCFArray == type) {
512512
CFIndex count = CFArrayGetCount((CFArrayRef)plist);
513-
STACK_BUFFER_DECL(CFPropertyListRef, buffer, count <= 256 ? count : 1);
513+
STACK_BUFFER_DECL(CFPropertyListRef, buffer, (count > 0 && count <= 256) ? count : 1);
514514
CFPropertyListRef *list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0);
515515
CFArrayGetValues((CFArrayRef)plist, CFRangeMake(0, count), list);
516516
for (CFIndex idx = 0; idx < count; idx++) {
@@ -713,22 +713,19 @@ CF_PRIVATE bool __CFBinaryPlistCreateObjectFiltered(const uint8_t *databytes, ui
713713
/* Grab a valSize-bytes integer out of the buffer pointed at by data and return it.
714714
*/
715715
CF_INLINE uint64_t _getSizedInt(const uint8_t *data, uint8_t valSize) {
716-
#if defined(__i386__) || defined(__x86_64__)
716+
717717
if (valSize == 1) {
718718
return (uint64_t)*data;
719719
} else if (valSize == 2) {
720-
uint16_t val = *(uint16_t *)data;
721-
return (uint64_t)CFSwapInt16BigToHost(val);
720+
return (uint64_t)unaligned_load16be(data);
722721
} else if (valSize == 4) {
723-
uint32_t val = *(uint32_t *)data;
724-
return (uint64_t)CFSwapInt32BigToHost(val);
722+
return (uint64_t)unaligned_load32be(data);
725723
} else if (valSize == 8) {
726-
uint64_t val = *(uint64_t *)data;
727-
return CFSwapInt64BigToHost(val);
724+
return unaligned_load64be(data);
728725
}
729-
#endif
730-
// Compatibility with existing archives, including anything with a non-power-of-2
731-
// size and 16-byte values, and architectures that don't support unaligned access
726+
727+
// Compatibility with existing archives, including anything with a non-power-of-2
728+
// size and 16-byte values
732729
uint64_t res = 0;
733730
for (CFIndex idx = 0; idx < valSize; idx++) {
734731
res = (res << 8) + data[idx];
@@ -1429,7 +1426,7 @@ CF_PRIVATE bool __CFBinaryPlistCreateObjectFiltered(const uint8_t *databytes, ui
14291426
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
14301427
byte_cnt = check_size_t_mul(arrayCount, sizeof(CFPropertyListRef), &err);
14311428
if (CF_NO_ERROR != err) FAIL_FALSE;
1432-
STACK_BUFFER_DECL(CFPropertyListRef, buffer, arrayCount <= 256 ? arrayCount : 1);
1429+
STACK_BUFFER_DECL(CFPropertyListRef, buffer, (arrayCount > 0 && arrayCount <= 256) ? arrayCount : 1);
14331430
list = (arrayCount <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, 0);
14341431
if (!list) FAIL_FALSE;
14351432
Boolean madeSet = false;

CoreFoundation/String.subproj/CFString.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,18 @@ CFStringEncoding __CFStringComputeEightBitStringEncoding(void) {
533533
/* Returns whether the provided bytes can be stored in ASCII
534534
*/
535535
CF_INLINE Boolean __CFBytesInASCII(const uint8_t *bytes, CFIndex len) {
536+
#if TARGET_RT_64_BIT
537+
uint64_t align_mask = 7;
538+
#else
539+
uint32_t align_mask = 3;
540+
#endif
541+
542+
/* Read bytes until the buffer is aligned. */
543+
while (((uintptr_t)bytes & align_mask) && len > 0) {
544+
if (*bytes++ & 0x80) return false;
545+
len--;
546+
}
547+
536548
#if TARGET_RT_64_BIT
537549
/* A bit of unrolling; go by 32s, 16s, and 8s first */
538550
while (len >= 32) {

CoreFoundation/StringEncodings.subproj/CFUniChar.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,8 @@ CF_PRIVATE uint8_t CFUniCharGetBitmapForPlane(uint32_t charset, uint32_t plane,
632632
numBytes /= 4; // for 32bit
633633

634634
while (numBytes-- > 0) {
635-
*((uint32_t *)bitmap) = value;
636-
#if defined (__cplusplus)
635+
unaligned_store32(bitmap, value);
636+
#if defined (__cplusplus)
637637
bitmap = (uint8_t *)bitmap + sizeof(uint32_t);
638638
#else
639639
bitmap += sizeof(uint32_t);
@@ -744,7 +744,8 @@ CF_PRIVATE const void *CFUniCharGetMappingData(uint32_t type) {
744744
headerSize = *((uint8_t *)bytes); bytes = (uint8_t *)bytes + sizeof(uint32_t);
745745
#else
746746
bytes += 4; // Skip Unicode version
747-
headerSize = *((uint32_t *)bytes); bytes += sizeof(uint32_t);
747+
headerSize = unaligned_load32(bytes);
748+
bytes += sizeof(uint32_t);
748749
#endif
749750
headerSize -= (sizeof(uint32_t) * 2);
750751
bodyBase = (char *)bytes + headerSize;
@@ -757,7 +758,8 @@ CF_PRIVATE const void *CFUniCharGetMappingData(uint32_t type) {
757758
#if defined (__cplusplus)
758759
__CFUniCharMappingTables[idx] = (char *)bodyBase + *((uint32_t *)bytes); bytes = (uint8_t *)bytes + sizeof(uint32_t);
759760
#else
760-
__CFUniCharMappingTables[idx] = (char *)bodyBase + *((uint32_t *)bytes); bytes += sizeof(uint32_t);
761+
__CFUniCharMappingTables[idx] = (char *)bodyBase + unaligned_load32(bytes);
762+
bytes += sizeof(uint32_t);
761763
#endif
762764
}
763765
}
@@ -783,18 +785,24 @@ typedef struct {
783785
static uint32_t __CFUniCharGetMappedCase(const __CFUniCharCaseMappings *theTable, uint32_t numElem, UTF32Char character) {
784786
const __CFUniCharCaseMappings *p, *q, *divider;
785787

786-
if ((character < theTable[0]._key) || (character > theTable[numElem-1]._key)) {
788+
#define READ_KEY(x) unaligned_load32(((uint8_t *)x) + offsetof(__CFUniCharCaseMappings, _key))
789+
#define READ_VALUE(x) unaligned_load32(((uint8_t *)x) + offsetof(__CFUniCharCaseMappings, _value))
790+
791+
if ((character < READ_KEY(&theTable[0])) || (character > READ_KEY(&theTable[numElem-1]))) {
787792
return 0;
788793
}
789794
p = theTable;
790795
q = p + (numElem-1);
791796
while (p <= q) {
792797
divider = p + ((q - p) >> 1); /* divide by 2 */
793-
if (character < divider->_key) { q = divider - 1; }
794-
else if (character > divider->_key) { p = divider + 1; }
795-
else { return divider->_value; }
798+
if (character < READ_KEY(divider)) { q = divider - 1; }
799+
else if (character > READ_KEY(divider)) { p = divider + 1; }
800+
else { return READ_VALUE(divider); }
796801
}
797802
return 0;
803+
804+
#undef READ_KEY
805+
#undef READ_VALUE
798806
}
799807

800808
#define NUM_CASE_MAP_DATA (kCFUniCharCaseFold + 1)
@@ -818,9 +826,9 @@ static bool __CFUniCharLoadCaseMappingTable(void) {
818826
__CFUniCharCaseMappingExtraTable = (const uint32_t **)__CFUniCharCaseMappingTable + NUM_CASE_MAP_DATA;
819827

820828
for (idx = 0;idx < NUM_CASE_MAP_DATA;idx++) {
821-
countArray[idx] = *((uint32_t *)__CFUniCharMappingTables[idx]) / (sizeof(uint32_t) * 2);
829+
countArray[idx] = unaligned_load32(__CFUniCharMappingTables[idx]) / (sizeof(uint32_t) * 2);
822830
__CFUniCharCaseMappingTable[idx] = ((uint32_t *)__CFUniCharMappingTables[idx]) + 1;
823-
__CFUniCharCaseMappingExtraTable[idx] = (const uint32_t *)((char *)__CFUniCharCaseMappingTable[idx] + *((uint32_t *)__CFUniCharMappingTables[idx]));
831+
__CFUniCharCaseMappingExtraTable[idx] = (const uint32_t *)((char *)__CFUniCharCaseMappingTable[idx] + unaligned_load32(__CFUniCharMappingTables[idx]));
824832
}
825833

826834
__CFUniCharCaseMappingTableCounts = countArray;
@@ -1034,7 +1042,7 @@ CFIndex CFUniCharMapCaseTo(UTF32Char theChar, UTF16Char *convertedChar, CFIndex
10341042
} else {
10351043
CFIndex idx;
10361044

1037-
for (idx = 0;idx < count;idx++) *(convertedChar++) = (UTF16Char)*(extraMapping++);
1045+
for (idx = 0;idx < count;idx++) *(convertedChar++) = (UTF16Char)unaligned_load32(extraMapping++);
10381046
return count;
10391047
}
10401048
}
@@ -1241,7 +1249,8 @@ const void *CFUniCharGetUnicodePropertyDataForPlane(uint32_t propertyType, uint3
12411249
headerSize = CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes = (uint8_t *)bytes + sizeof(uint32_t);
12421250
#else
12431251
bytes += 4; // Skip Unicode version
1244-
headerSize = CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes += sizeof(uint32_t);
1252+
headerSize = unaligned_load32be(bytes);
1253+
bytes += sizeof(uint32_t);
12451254
#endif
12461255

12471256
headerSize -= (sizeof(uint32_t) * 2);
@@ -1275,7 +1284,7 @@ const void *CFUniCharGetUnicodePropertyDataForPlane(uint32_t propertyType, uint3
12751284
bodyBase = (const uint8_t *)bodyBase + (CFSwapInt32BigToHost(*(uint32_t *)bytes));
12761285
((uint32_t *&)bytes) ++;
12771286
#else
1278-
bodyBase += (CFSwapInt32BigToHost(*((uint32_t *)bytes++)));
1287+
bodyBase += unaligned_load32be(bytes++);
12791288
#endif
12801289
}
12811290

CoreFoundation/StringEncodings.subproj/CFUnicodeDecomposition.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static void __CFUniCharLoadDecompositionTable(void) {
4141
return;
4242
}
4343

44-
__CFUniCharDecompositionTableLength = *(bytes++);
44+
__CFUniCharDecompositionTableLength = unaligned_load32(bytes++);
4545
__CFUniCharDecompositionTable = (UTF32Char *)bytes;
4646
__CFUniCharMultipleDecompositionTable = (UTF32Char *)((intptr_t)bytes + __CFUniCharDecompositionTableLength);
4747

@@ -102,18 +102,24 @@ typedef struct {
102102
static uint32_t __CFUniCharGetMappedValue(const __CFUniCharDecomposeMappings *theTable, uint32_t numElem, UTF32Char character) {
103103
const __CFUniCharDecomposeMappings *p, *q, *divider;
104104

105-
if ((character < theTable[0]._key) || (character > theTable[numElem-1]._key)) {
105+
#define READ_KEY(x) unaligned_load32(((uint8_t *)x) + offsetof(__CFUniCharDecomposeMappings, _key))
106+
#define READ_VALUE(x) unaligned_load32(((uint8_t *)x) + offsetof(__CFUniCharDecomposeMappings, _value))
107+
108+
if ((character < READ_KEY(&theTable[0])) || (character > READ_KEY(&theTable[numElem-1]))) {
106109
return 0;
107110
}
108111
p = theTable;
109112
q = p + (numElem-1);
110113
while (p <= q) {
111114
divider = p + ((q - p) >> 1); /* divide by 2 */
112-
if (character < divider->_key) { q = divider - 1; }
113-
else if (character > divider->_key) { p = divider + 1; }
114-
else { return divider->_value; }
115+
if (character < READ_KEY(divider)) { q = divider - 1; }
116+
else if (character > READ_KEY(divider)) { p = divider + 1; }
117+
else { return READ_VALUE(divider); }
115118
}
116119
return 0;
120+
121+
#undef READ_KEY
122+
#undef READ_VALUE
117123
}
118124

119125
static void __CFUniCharPrioritySort(UTF32Char *characters, CFIndex length) {
@@ -162,7 +168,7 @@ static CFIndex __CFUniCharRecursivelyDecomposeCharacter(UTF32Char character, UTF
162168

163169
usedLength += length;
164170

165-
while (length--) *(convertedChars++) = *(mappings++);
171+
while (length--) *(convertedChars++) = unaligned_load32(mappings++);
166172

167173
return usedLength;
168174
}

0 commit comments

Comments
 (0)