简体   繁体   English

armv5中c的指针分配错误

[英]error in pointer assignments in c on armv5

I have the following code in c: 我在c中有以下代码:

LinkedList
MemAllocLinkedList_add(MemAllocLinkedList self, void* data)
{
    LinkedList newElement = (LinkedList)
            MemoryAllocator_allocate(self->ma, sizeof(struct sLinkedList));

    if (newElement == NULL)
        return NULL; 

    newElement->data = data;  

    newElement->next = NULL; 

    LinkedList listEnd = LinkedList_getLastElement((LinkedList) self);

    listEnd->next = newElement;

    return newElement;
}

and

char*
MemoryAllocator_allocate(MemoryAllocator* self, int size)
{
    if (((self->currentPtr - self->memoryBlock) + size) <= self->size) {
        char* ptr = self->currentPtr;
        self->currentPtr += size;
        return ptr;
    }
    else{
        printf("MemoryAllocator_allocate: Out of Memory\n");
        return NULL;
    }
}

being LinkedList a pointer to sLinkedList that is: 被LinkedList指向sLinkedList的指针,即:

struct sLinkedList {
    void* data;
    struct sLinkedList* next;
};

and MemAllocLinkedList a pointer to sMemAllocLinkedList that is: 和MemAllocLinkedList指向sMemAllocLinkedList的指针,该指针是:

struct sMemAllocLinkedList {
    void* data;
    struct sLinkedList* next;
    MemoryAllocator* ma;
};

I have a program who calls this 'MemAllocLinkedList_add' function several times without a problem, but there's one point where, within this function, the assignment 'listEnd->next = newElement' switches the first 16 bits with the las 16, so instead of having on listEnd->next 975912 I have -467140594 which leads to a SISEGEV error when I try to access to last element of that list later. 我有一个程序多次调用此“ MemAllocLinkedList_add”函数,没有问题,但是有一点要注意,在该函数中,赋值“ listEnd-> next = newElement”会在las 16中切换前16位,所以不是在列表末尾->下一个975912上,我有-467140594,当我稍后尝试访问该列表的最后一个元素时,导致SISEGEV错误。

If I compile it and run it on a virtual machine with debian (intel 64bits) and on a raspberry pi (armv6 32 bits) it works perfectly fine. 如果我编译它并在具有debian(intel 64位)的虚拟机上和在树莓派(armv6 32位)上的虚拟机上运行它,则可以正常工作。 But when I try on a NanosG20 with armv5tej it does this thing that I've explained. 但是,当我尝试使用armv5tej的NanosG20时,它完成了我已经解释的事情。 I use gcc 4.6. 我使用gcc 4.6。

Anybody knows why this happens? 有人知道为什么会这样吗?

Thanks. 谢谢。

EDIT: 编辑:

Here´s LinkedList_getLastElement : 这是LinkedList_getLastElement:

LinkedList
LinkedList_getLastElement(LinkedList list)
{int i=0;
    while (list->next != NULL) {
        list = list->next; i++;     
    }
    return list;
}

Type MemoryAllocator: 类型MemoryAllocator:

typedef struct {
    char* memoryBlock;
    char* currentPtr;
    int size;
} MemoryAllocator;

This code is from libiec61850 an implementation of the standard 61850 for subelectric stations so there is a lot more code which is impossible to post here. 该代码来自libiec61850,它是用于子电站的标准61850的实现,因此还有很多代码无法在此处发布。 I'm just posting the part where I get the error, but like I said, only on a board with ARMv5, not on the VM or the Raspberry Pi. 我只是在发布发生错误的部分,但就像我说的那样,仅在带有ARMv5的板上,而不在VM或Raspberry Pi上。

You actually have the same problem on all 3 platforms, it's just that on Intel and ARMv6 you get the "appearing to work correctly" form of undefined behaviour. 实际上,在所有3个平台上都存在相同的问题,只是在Intel和ARMv6上,您会获得“貌似正常工作”形式的不确定行为。

Here's a relevant quote from the C standard (6.3.2.3 in the n1256 draft of C99 I have to hand): 这是C标准的相关报价(我必须要交纳的C99的n1256草案中的6.3.2.3):

A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. 指向对象或不完整类型的指针可以转换为指向不同对象或不完整类型的指针。 If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined. 如果结果指针未针对指向的类型正确对齐,则该行为未定义。

The notion of "correctly aligned" is defined by the ABI for the platform. “正确对齐”的概念由平台的ABI定义。 In this case, the ARM ABI says thar char requires 1-byte alignment, and pointers require 4-byte alignment. 在这种情况下, ARM ABI表示thar char需要1字节对齐,而指针需要4字节对齐。 Since struct sLinkedList consists of two pointers, it must also be aligned at least as strictly as a pointer. 由于struct sLinkedList由两个指针组成,因此它也必须至少与一个指针严格对齐。

Now, since MemoryAllocator_allocate naïvely increments its internal free pointer by size each time, there's no guarantee that the char * it returns is anything better than 1-byte aligned, thus converting that to a struct sLinkedList * leads to undefined behaviour in 3/4 possible cases. 现在,由于MemoryAllocator_allocate都会将其内部空闲指针每次MemoryAllocator_allocate size递增,因此无法保证它返回的char *比1字节对齐要好,因此将其转换为struct sLinkedList *可能导致3/4发生未定义的行为案件。 Since compilers tend to be more pragmatic than vindictive, rather than nasal demons you got the undefined behaviour of "whatever the hardware does for unaligned loads/stores" upon dereferencing it, which may be an alignment fault, returning some nonsense data, or even returning the data you'd expect. 由于编译器往往比报复性更实用,而不是鼻恶魔 ,因此在取消引用后,您会得到“硬件对未对齐的加载/存储执行任何操作”的不确定行为,这可能是对齐错误,返回了一些无用数据甚至返回您期望的数据。

The solution is to make MemoryAllocator_allocate always round up size to the nearest multiple of the largest required alignment - for the ARM ABI, this is 8 bytes, although if you're sure you will never use any 64-bit types (like double or long long ), you can probably get away with 4 bytes. 解决方案是使MemoryAllocator_allocate始终将size四舍五入为最大所需对齐方式的最接近倍数-对于ARM ABI,这是8个字节,尽管如果您确定绝不会使用任何64位类型(例如doublelong long类型) long long ),您可能可以摆脱4个字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM