Строгий псевдоним в гибком элементе массива? - PullRequest
0 голосов
/ 15 февраля 2019

Я пишу Arena Allocator, и он работает, но я чувствую, что он нарушает строгие правила наложения имен.Я хочу знать, прав я или нет.Вот соответствующая часть кода:

typedef struct ArenaNode ArenaNode;
struct ArenaNode {
    ArenaNode *next;
    size_t dataSize;
    u8 data[];
};

typedef struct {
    ArenaNode *head;
    ArenaNode *current;
    size_t currentIndex;
} Arena;

static ArenaNode *ArenaNodeNew(size_t dataSize, ArenaNode *next)
{
    ArenaNode *n = malloc(sizeof(ArenaNode) + dataSize);
    n->next = NULL;
    n->dataSize = dataSize;
    return n;
}

void *ArenaAlloc(Arena *a, size_t size)
{
    const size_t maxAlign = alignof(max_align_t);
    size_t offset = nextHigherMultiplePow2(offsetof(ArenaNode, data), maxAlign) - offsetof(ArenaNode, data);
    size_t dataSize = offset + max(size, ARENA_SIZE);
    // first time
    void *ptr;
    if (a->head == NULL) {
        ArenaNode *n = ArenaNodeNew(dataSize, NULL);
        a->head = n;
        a->current = n;
        ptr = n->data + offset;
        a->currentIndex = nextHigherMultiplePow2(offset + size, maxAlign);
    } else {
        // enough space
        if (a->currentIndex + size <= a->current->dataSize) {
            ptr = &a->current->data[a->currentIndex];
            a->currentIndex = nextHigherMultiplePow2(a->currentIndex + size, maxAlign);
        } else {
            ArenaNode *n = ArenaNodeNew(dataSize, NULL);
            a->current->next = n;
            a->current = n;
            ptr = n->data + offset;
            a->currentIndex = nextHigherMultiplePow2(offset + size, maxAlign);
        }
    }
    return ptr;
}

Arena - это связанный список узлов, а узел - это заголовок, за которым следуют данные u8 data[].u8 - беззнаковый символЯ поддерживаю следующий доступный индекс (currentIndex) и продвигаюсь на data по этому индексу и возвращаю его как void * (ptr = &a->current->data[a->currentIndex]).Это нарушает строгое правило алиасинга, потому что я конвертирую указатель на u8 на что-то другое и использую это?

Мое замешательство связано с тем, что память, возвращаемая malloc, не имеет эффективного типа.Но так как я приведу указатель malloc к ArenaNode * и задаю его элементы данных (next и dataSize) после его выделения (в ArenaNodeNew), эффективный тип становится ArenaNode.Или это?Я не установил data поле этого.

В принципе, я думаю, что вопрос можно упростить до следующего: если я выделю область памяти, скажем, размером 10, приведу указатель к struct {int a;} * (предположим, 4 байта int), установите для a значениечто-то, что происходит с остальными 6 байтами?Есть ли у него эффективный тип?Влияет ли присутствие гибкого члена массива на это каким-либо образом?

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Это нарушает правило строгого алиасинга, потому что я конвертирую указатель на u8 на что-то другое и использую это?

Нет, вы не нарушаете строгий алиасинг, но вашкод может нарушать ограничения, налагаемые 7.22.3 Функции управления памятью , абзац 1 :

Указатель, возвращаемый при успешном выделении, выравнивается соответствующим образом, чтобыон может быть назначен указателю на любой тип объекта с фундаментальным требованием выравнивания, а затем использован для доступа к такому объекту или массиву таких объектов в выделенном пространстве ...

Вы не 'Похоже, что вы убедитесь, что память, которую вы используете для любого объекта, «соответствующим образом выровнена» для любого объекта.Дано 6.3.2.3. Указатели , абзац 7 :

Указатель на тип объекта может быть преобразован в указатель на другой тип объекта,Если результирующий указатель неправильно выровнен для ссылочного типа, поведение не определено.

вы рискуете неопределенным поведением.

«Подходящее выравнивание» чрезвычайно зависит от платформы.

0 голосов
/ 15 февраля 2019

Дополнительные байты, являющиеся частью элемента гибкого массива, будут иметь эффективный тип этого элемента при записи в него.

Вы можете безопасно объявить ptr как u8 * и определить свою функцию длятакже верните этот тип.

В вашем примере выделения 10 байтов и обработки первых 4 как структуры данного типа, оставшиеся байты еще не имеют действующего типа.Вы можете использовать их для любого типа, при условии, что указатель, который вы используете, выровнен правильно, т.е. вы можете указать int * на следующие байты, но не long long *.из-за выравнивания.

...