ICU-20048 remove uses of UAlignedMemory, replace with native C++11 constructs.

Also update the Travis CI configuration to use newer compilers, and the
dependency checker to be happy with the newer clang compiler.
This commit is contained in:
Andy Heninger 2019-05-31 17:46:49 -07:00
parent fa240d49cc
commit 0367d4c135
11 changed files with 36 additions and 88 deletions

View file

@ -45,6 +45,7 @@ matrix:
# Invokes test/hdrtst to check public headers compliance.
- name: "c: linux gcc"
dist: xenial
language: cpp
compiler: gcc
env: PREFIX=/tmp/icu-prefix
@ -61,6 +62,7 @@ matrix:
# clang release build with some options to enforce useful constraints.
- name: "c: linux clang"
dist: xenial
language: cpp
env:
- CPPFLAGS="-DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1"
@ -93,16 +95,9 @@ matrix:
- CPPFLAGS="-fsanitize=address"
- LDFLAGS="-fsanitize=address"
os: linux
dist: trusty
dist: xenial
sudo: true
compiler: clang
addons:
apt:
update: true
sources:
- llvm-toolchain-trusty-5.0
packages:
- clang-5.0
before_script:
- cd icu4c/source
- ./runConfigureICU --enable-debug --disable-release Linux --disable-renaming --enable-tracing
@ -120,16 +115,9 @@ matrix:
- CPPFLAGS="-fsanitize=thread"
- LDFLAGS=-fsanitize=thread
os: linux
dist: trusty
dist: xenial
sudo: true
compiler: clang
addons:
apt:
update: true
sources:
- llvm-toolchain-trusty-5.0
packages:
- clang-5.0
script:
- cd icu4c/source
- ./runConfigureICU --enable-debug --disable-release Linux --disable-renaming

View file

@ -64,38 +64,14 @@ uprv_free(void *mem);
U_CAPI void * U_EXPORT2
uprv_calloc(size_t num, size_t size) U_MALLOC_ATTR U_ALLOC_SIZE_ATTR2(1,2);
/**
* This should align the memory properly on any machine.
* This is very useful for the safeClone functions.
*/
typedef union {
long t1;
double t2;
void *t3;
} UAlignedMemory;
/**
* Get the least significant bits of a pointer (a memory address).
* For example, with a mask of 3, the macro gets the 2 least significant bits,
* which will be 0 if the pointer is 32-bit (4-byte) aligned.
*
* ptrdiff_t is the most appropriate integer type to cast to.
* size_t should work too, since on most (or all?) platforms it has the same
* width as ptrdiff_t.
* uintptr_t is the most appropriate integer type to cast to.
*/
#define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask))
/**
* Get the amount of bytes that a pointer is off by from
* the previous UAlignedMemory-aligned pointer.
*/
#define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1)
/**
* Get the amount of bytes to add to a pointer
* in order to get the next UAlignedMemory-aligned address.
*/
#define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
#define U_POINTER_MASK_LSB(ptr, mask) ((uintptr_t)(ptr) & (mask))
/**
* Create & return an instance of "type" in statically allocated storage.

View file

@ -134,7 +134,7 @@ doInsertionSort(char *array, int32_t length, int32_t itemSize,
static void
insertionSort(char *array, int32_t length, int32_t itemSize,
UComparator *cmp, const void *context, UErrorCode *pErrorCode) {
UAlignedMemory v[STACK_ITEM_SIZE/sizeof(UAlignedMemory)+1];
alignas(max_align_t) char v[STACK_ITEM_SIZE];
void *pv;
/* allocate an intermediate item variable (v) */
@ -238,7 +238,7 @@ subQuickSort(char *array, int32_t start, int32_t limit, int32_t itemSize,
static void
quickSort(char *array, int32_t length, int32_t itemSize,
UComparator *cmp, const void *context, UErrorCode *pErrorCode) {
UAlignedMemory xw[(2*STACK_ITEM_SIZE)/sizeof(UAlignedMemory)+1];
alignas(max_align_t) char xw[2*STACK_ITEM_SIZE];
void *p;
/* allocate two intermediate item variables (x and w) */
@ -252,6 +252,7 @@ quickSort(char *array, int32_t length, int32_t itemSize,
}
}
// TODO ICU-20650 check alignment of 2nd ptr.
subQuickSort(array, 0, length, itemSize,
cmp, context, p, (char *)p+itemSize);

View file

@ -25,6 +25,8 @@
#if !UCONFIG_NO_CONVERSION
#include <memory>
#include "unicode/ustring.h"
#include "unicode/ucnv.h"
#include "unicode/ucnv_err.h"
@ -158,7 +160,6 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
UConverter *localConverter, *allocatedConverter;
int32_t stackBufferSize;
int32_t bufferSizeNeeded;
char *stackBufferChars = (char *)stackBuffer;
UErrorCode cbErr;
UConverterToUnicodeArgs toUArgs = {
sizeof(UConverterToUnicodeArgs),
@ -225,22 +226,18 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
}
/* Pointers on 64-bit platforms need to be aligned
* on a 64-bit boundary in memory.
/* Adjust (if necessary) the stackBuffer pointer to be aligned correctly for a UConverter.
*/
if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) {
int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars);
if(stackBufferSize > offsetUp) {
stackBufferSize -= offsetUp;
stackBufferChars += offsetUp;
size_t altStackBufferSize = stackBufferSize; // Incompatible types for passing by reference.
if (stackBuffer) {
if (std::align(alignof(UConverter), bufferSizeNeeded, stackBuffer, altStackBufferSize)) {
stackBufferSize = static_cast<int32_t>(altStackBufferSize);
} else {
/* prevent using the stack buffer but keep the size > 0 so that we do not just preflight */
stackBufferSize = 1;
}
}
stackBuffer = (void *)stackBufferChars;
/* Now, see if we must allocate any memory */
if (stackBufferSize < bufferSizeNeeded || stackBuffer == NULL)
{
@ -475,7 +472,7 @@ ucnv_setSubstString(UConverter *cnv,
const UChar *s,
int32_t length,
UErrorCode *err) {
UAlignedMemory cloneBuffer[U_CNV_SAFECLONE_BUFFERSIZE / sizeof(UAlignedMemory) + 1];
alignas(UConverter) char cloneBuffer[U_CNV_SAFECLONE_BUFFERSIZE];
char chars[UCNV_ERROR_BUFFER_LENGTH];
UConverter *clone;

View file

@ -3571,20 +3571,11 @@ _ISO_2022_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorC
/*
* Structure for cloning an ISO 2022 converter into a single memory block.
* ucnv_safeClone() of the converter will align the entire cloneStruct,
* and then ucnv_safeClone() of the sub-converter may additionally align
* currentConverter inside the cloneStruct, for which we need the deadSpace
* after currentConverter.
* This is because UAlignedMemory may be larger than the actually
* necessary alignment size for the platform.
* The other cloneStruct fields will not be moved around,
* and are aligned properly with cloneStruct's alignment.
*/
struct cloneStruct
{
UConverter cnv;
UConverter currentConverter;
UAlignedMemory deadSpace;
UConverterDataISO2022 mydata;
};
@ -3602,6 +3593,10 @@ _ISO_2022_SafeClone(
UConverterDataISO2022 *cnvData;
int32_t i, size;
if (U_FAILURE(*status)){
return nullptr;
}
if (*pBufferSize == 0) { /* 'preflighting' request - set needed size into *pBufferSize */
*pBufferSize = (int32_t)sizeof(struct cloneStruct);
return NULL;
@ -3619,7 +3614,7 @@ _ISO_2022_SafeClone(
/* share the subconverters */
if(cnvData->currentConverter != NULL) {
size = (int32_t)(sizeof(UConverter) + sizeof(UAlignedMemory)); /* include size of padding */
size = (int32_t)sizeof(UConverter);
localClone->mydata.currentConverter =
ucnv_safeClone(cnvData->currentConverter,
&localClone->currentConverter,

View file

@ -518,19 +518,11 @@ _HZ_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorCode *e
/*
* Structure for cloning an HZ converter into a single memory block.
* ucnv_safeClone() of the HZ converter will align the entire cloneHZStruct,
* and then ucnv_safeClone() of the sub-converter may additionally align
* subCnv inside the cloneHZStruct, for which we need the deadSpace after
* subCnv. This is because UAlignedMemory may be larger than the actually
* necessary alignment size for the platform.
* The other cloneHZStruct fields will not be moved around,
* and are aligned properly with cloneHZStruct's alignment.
*/
struct cloneHZStruct
{
UConverter cnv;
UConverter subCnv;
UAlignedMemory deadSpace;
UConverterDataHZ mydata;
};
@ -545,12 +537,12 @@ _HZ_SafeClone(const UConverter *cnv,
int32_t size, bufferSizeNeeded = sizeof(struct cloneHZStruct);
if (U_FAILURE(*status)){
return 0;
return nullptr;
}
if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */
*pBufferSize = bufferSizeNeeded;
return 0;
return nullptr;
}
localClone = (struct cloneHZStruct *)stackBuffer;
@ -561,7 +553,7 @@ _HZ_SafeClone(const UConverter *cnv,
localClone->cnv.isExtraLocal = TRUE;
/* deep-clone the sub-converter */
size = (int32_t)(sizeof(UConverter) + sizeof(UAlignedMemory)); /* include size of padding */
size = (int32_t)sizeof(UConverter);
((UConverterDataHZ*)localClone->cnv.extraInfo)->gbConverter =
ucnv_safeClone(((UConverterDataHZ*)cnv->extraInfo)->gbConverter, &localClone->subCnv, &size, status);

View file

@ -567,7 +567,7 @@ enum {
struct ExtendedUText {
UText ut;
UAlignedMemory extension;
max_align_t extension;
};
static const UText emptyText = UTEXT_INITIALIZER;
@ -582,7 +582,7 @@ utext_setup(UText *ut, int32_t extraSpace, UErrorCode *status) {
// We need to heap-allocate storage for the new UText
int32_t spaceRequired = sizeof(UText);
if (extraSpace > 0) {
spaceRequired = sizeof(ExtendedUText) + extraSpace - sizeof(UAlignedMemory);
spaceRequired = sizeof(ExtendedUText) + extraSpace - sizeof(max_align_t);
}
ut = (UText *)uprv_malloc(spaceRequired);
if (ut == NULL) {

View file

@ -35,6 +35,9 @@
#define MAX_FILE_LEN 1024*20
#define UCS_FILE_NAME_SIZE 512
/* Similar to C++ alignof(type) */
#define ALIGNOF(type) offsetof (struct { char c; type member; }, member)
/*returns an action other than the one provided*/
#if !UCONFIG_NO_LEGACY_CONVERSION
static UConverterFromUCallback otherUnicodeAction(UConverterFromUCallback MIA);
@ -1821,7 +1824,7 @@ static void TestConvertSafeClone()
/* close the original immediately to make sure that the clone works by itself */
ucnv_close(cnv);
if( actualSizes[idx] <= (bufferSizes[j] - (int32_t)sizeof(UAlignedMemory)) &&
if( actualSizes[idx] <= (bufferSizes[j] - (int32_t)ALIGNOF(UConverter)) &&
err == U_SAFECLONE_ALLOCATED_WARNING
) {
log_err("ucnv_safeClone(%s) did a heap clone although the buffer was large enough\n", names[idx]);

View file

@ -90,7 +90,7 @@ group: system_locale
group: stdio_input
fopen fclose fgets fread fseek ftell rewind feof fileno
# Additional symbols in an optimized build.
__fgets_chk __fread_chk
__fgets_chk __fread_chk fread_unlocked
group: stdio_output
fflush fwrite

View file

@ -509,19 +509,15 @@ void UObjectTest::testIDs()
void UObjectTest::testUMemory() {
// additional tests for code coverage
#if U_OVERRIDE_CXX_ALLOCATION && U_HAVE_PLACEMENT_NEW
union {
UAlignedMemory align_;
char bytes_[sizeof(UnicodeString)];
} stackMemory;
char *bytes = stackMemory.bytes_;
alignas(UnicodeString) char bytes[sizeof(UnicodeString)];
UnicodeString *p;
enum { len=20 };
p=new(bytes) UnicodeString(len, (UChar32)0x20ac, len);
p=new(bytes) UnicodeString(len, (UChar32)U'', len);
if((void *)p!=(void *)bytes) {
errln("placement new did not place the object at the expected address");
}
if(p->length()!=len || p->charAt(0)!=0x20ac || p->charAt(len-1)!=0x20ac) {
if(p->length()!=len || p->charAt(0)!=u'' || p->charAt(len-1)!=u'') {
errln("constructor used with placement new did not work right");
}

View file

@ -243,7 +243,7 @@ struct UToolMemory {
char name[64];
int32_t capacity, maxCapacity, size, idx;
void *array;
UAlignedMemory staticArray[1];
alignas(max_align_t) char staticArray[1];
};
U_CAPI UToolMemory * U_EXPORT2