C 读取垃圾内存会破坏程序流吗?

C 读取垃圾内存会破坏程序流吗?,c,memory-management,struct,linked-list,heap-corruption,C,Memory Management,Struct,Linked List,Heap Corruption,在我的应用程序中,我有一对嵌套的循环,它们跟随类似的嵌套链表,以便解析数据。我犯了一个愚蠢的错误,投了一个结构作为子结构,例如: if (((ENTITY *) OuterEntityLoop->data)->visible == true) { 而不是: if (((ENTITY_RECORD *) OuterEntityLoop->data)->entity->visible == true) { 这导致了一个问题,大约70%的运行会导致应用程序完全停止——

在我的应用程序中,我有一对嵌套的循环,它们跟随类似的嵌套链表,以便解析数据。我犯了一个愚蠢的错误,投了一个结构作为子结构,例如:

if (((ENTITY *) OuterEntityLoop->data)->visible == true) {
而不是:

if (((ENTITY_RECORD *) OuterEntityLoop->data)->entity->visible == true) {
这导致了一个问题,大约70%的运行会导致应用程序完全停止——不是崩溃,只是坐着旋转。程序流中的Diagnostic
printf
s会以奇怪的顺序启动,或者根本不会启动,尽管它在大多数情况下自发地恢复了几次,但它破坏了应用程序

事情是这样的。即使将内部逻辑削减为绝对,它也不是基于逻辑错误的无限循环,直到循环只包含my
printf
,它仍然被破坏

第二件事:当结构被错误地识别时,它仍然抱怨如果我试图访问一个不存在的属性,即使它没有现存的属性

我的问题是:

  • 为什么会损坏内存?简单地读取垃圾内存会破坏程序的控制结构吗?若并没有,这是否意味着即使电动围栏不再抱怨,我的某处仍有漏洞
  • 我假设它抱怨不存在属性的原因是因为它遵循给定的类型定义,而不是实际存在的属性。现在我已经把它打印出来了,这在我的脑海里就不那么可疑了,但我想确认一下,我在这里没有偏离基准

  • 欢迎来到C,在C中,铸造的力量允许你使任何一块内存看起来像你想要的任何对象,但风险自负。如果您强制转换的对象实际上不是该类型的对象,并且该类型包含指向其他对象的指针,那么您将面临崩溃的风险。因为,即使尝试读取尚未实际映射到进程虚拟内存地址空间的随机内存,也会导致内核,或者从内存中没有读取权限的特定区域读取也会导致内核,如空指针

    例如:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct foo
    {
        int x;
        int y;
        int z;
    };
    
    struct bar
    {
        int x;
        int y;
        struct foo *p;
    };
    
    void evil_cast(void *p)
    {
        /* hmm... maybe this is a bar pointer */
        struct bar *q = (struct bar *)p;
        if (q != NULL) /* q is some valid pointer */
        {
            /* as long as q points readable memory q->x will return some value, */
            /* this has a fairly high probability of success */
            printf("random pointer to a bar, x value x(%d)\n", q->x);
            /* hmm... lets use the foo pointer from my random bar */
            if (q->p != NULL)
            {
                /* very high probabilty of coring, since the likely hood that a */
                /* random piece of memory contains a valid address is much lower */
                printf("random value of x from a random foo pointer, from a random bar pointer x value x(%d)\n", q->p->x);
            }
    
         }
    }
    
    int main(int argc, char *argv[])
    {
        int *random_heap_data = (int *)malloc(1024); /* just random head memory */
        /* setup the first 5 locations to be some integers */
        random_heap_data[0] = 1;
        random_heap_data[1] = 2;
        random_heap_data[2] = 3;
        random_heap_data[3] = 4;
        random_heap_data[4] = 5;
        evil_cast(random_heap_data);
        return 0;
    }
    
    #包括
    #包括
    结构foo
    {
    int x;
    int-y;
    intz;
    };
    结构条
    {
    int x;
    int-y;
    结构foo*p;
    };
    无效邪恶施法(无效*p)
    {
    /*嗯……也许这是一个条形指针*/
    结构条*q=(结构条*)p;
    如果(q!=NULL)/*q是某个有效指针*/
    {
    /*只要q点可读内存q->x会返回一些值*/
    /*这有相当高的成功概率*/
    printf(“指向条的随机指针,x值x(%d)\n),q->x);
    /*嗯…让我们使用我的随机条中的foo指针*/
    如果(q->p!=NULL)
    {
    /*取芯概率非常高,因为*/
    /*随机内存中包含的有效地址要低得多*/
    printf(“来自随机foo指针的随机值x,来自随机条指针的随机值x(%d)\n”,q->p->x);
    }
    }
    }
    int main(int argc,char*argv[])
    {
    int*random_heap_data=(int*)malloc(1024);/*只是随机头内存*/
    /*将前5个位置设置为一些整数*/
    随机堆数据[0]=1;
    随机堆数据[1]=2;
    随机堆数据[2]=3;
    随机堆数据[3]=4;
    随机堆数据[4]=5;
    邪恶施法(随机堆数据);
    返回0;
    }
    
    当程序访问无效内存时,即使是为了读取,也不知道会发生什么。在某些系统上,任何内存读取操作都是有效的,或者会立即导致程序崩溃,但在其他系统上,错误读取可能会被误解为执行某项操作的信号。您没有指定您使用的是PC还是嵌入式系统,但在嵌入式系统上,通常有许多设计上的地址,这些地址在读取时会触发各种动作[例如,将从串行端口接收到的数据排队,或确认中断];错误读取此类地址可能会导致串行数据丢失,或者可能会导致中断控制器认为中断已被处理,而实际上并未被处理


    此外,在一些嵌入式系统中,试图读取无效地址可能会产生其他更糟糕的影响,这些影响不是设计的,而是偶然发生的。例如,在我设计的一个系统上,我必须连接一个内存设备,该设备在一个读取周期后从总线上下来有点慢。如果下一次内存读取是从至少有一个等待状态或位于不同总线上的内存区域执行的,则不会有问题。但是,如果在快速外部内存分区中运行的代码试图读取该区域,则内存设备无法快速脱离总线将损坏下一个获取的指令的某些位。所有这一切的最终效果是,从位于某些位置的代码访问慢速设备没有问题,但从位于快速分区的代码访问它(有意或无意)会导致奇怪的、不可复制的故障。

    但应用程序没有崩溃(直到我链接到Electric Fence)当垃圾内存被读取时,循环停止运行——我知道,因为调试文本停止回显到控制台——但操作系统并没有杀死它。有时,当从错误的类型转换指针访问内存时,你会很幸运,但正如他们所说的“你的里程可能会有所不同”。它在Linux桌面上,因此肯定没有嵌入。不过,这并不是说你的回答就不那么有趣了——我真的很喜欢这段轶事@sudowned:我认为这是一个很好的例子,说明了无效内存读取导致的“未定义行为”实际上意味着任何事情都可能发生。我不知道为什么一个基于x86的Linux机器会因为误读而表现得特别奇怪,尽管我可以想象一些可能性。懒洋洋地分配堆栈空间的操作系统可能会将散乱的内存访问解释为扩展堆栈的请求。根据它所做的验证,这样的堆栈扩展