怎样才能取消引用在C中的NULL指针不会崩溃的程序? [英] How can dereferencing a NULL pointer in C not crash a program?

查看:158
本文介绍了怎样才能取消引用在C中的NULL指针不会崩溃的程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个真正的C大师帮忙分析崩溃在我的code。没有固定的碰撞;我可以很容易地解决这个问题,但这样做之前,我想明白这是如何崩溃甚至有可能,因为它似乎完全不可能给我。

I need help of a real C guru to analyze a crash in my code. Not for fixing the crash; I can easily fix it, but before doing so I'd like to understand how this crash is even possible, as it seems totally impossible to me.

此崩溃只发生一个客户机上,我不能在本地重现它(这样我就可以通过code。使用调试器不步),因为我不能获得此用户的数据库的副本。我公司也不会允许我只需更改几行的code和使自定义生成此客户(所以我不能添加一些printf的线条,让他下再运行$ C $),当然客户有没有调试符号的生成。换句话说,我的debbuging能力是非常有限的。但是我可以明确崩溃,并得到一些调试信息。然而,当我看着这些信息,然后在code我不明白如何程序流程所能达到的问题就行了。在code应该让长到该行之前已坠毁。我完全失去了这里。

This crash only happens on a customer machine and I cannot reproduce it locally (so I cannot step through the code using a debugger), as I cannot obtain a copy of this user's database. My company also won't allow me to just change a few lines in the code and make a custom build for this customer (so I cannot add some printf lines and have him run the code again) and of course the customer has a build without debug symbols. In other words, my debbuging abilities are very limited. Nonetheless I could nail down the crash and get some debugging information. However when I look at that information and then at the code I cannot understand how the program flow could ever reach the line in question. The code should have crashed long before getting to that line. I'm totally lost here.

让我们开始与相关code。这是非常小code:

Let's start with the relevant code. It's very little code:

// ... code above skipped, not relevant ...

if (data == NULL) return -1;

information = parseData(data);

if (information == NULL) return -1;

/* Check if name has been correctly \0 terminated */
if (information->kind.name->data[information->kind.name->length] != '\0') {
    freeParsedData(information);
    return -1;
}

/* Copy the name */
realLength = information->kind.name->length + 1;
*result = malloc(realLength);
if (*result == NULL) {
    freeParsedData(information);
    return -1;
}
strlcpy(*result, (char *)information->kind.name->data, realLength);

// ... code below skipped, not relevant ...

这已经是。它崩溃的strlcpy。我可以告诉你strlcpy甚至是如何的真正的在运行时调用。 strlcpy实际上是所谓的有以下PARAMATERS:

That's already it. It crashes in strlcpy. I can tell you even how strlcpy is really called at runtime. strlcpy is actually called with the following paramaters:

strlcpy ( 0x341000, 0x0, 0x1 );

认识到这一点是相当明显的为什么strlcpy崩溃。它会尝试读取NULL指针一个字符,当然崩溃的意愿。而且,由于最后一个参数具有值1,原始长度一定是0.我的code明明已经在这里的一个bug,它未能检查名称的数据是NULL。我可以解决这个问题,没有问题的。

Knowing this it is rather obvious why strlcpy crashes. It tries to read one character from a NULL pointer and that will of course crash. And since the last parameter has a value of 1, the original length must have been 0. My code clearly has a bug here, it fails to check for the name data being NULL. I can fix this, no problem.

我的问题是:结果
如何解决这个code永远能在第一时间编写的strlcpy?结果
为什么这个code不在if语句崩溃?

我试了一下本地我的机器上:

I tried it locally on my machine:

int main (
    int argc,
    char ** argv
) {
    char * nullString = malloc(10);
    free(nullString);
    nullString = NULL;

    if (nullString[0] != '\0') {
    	printf("Not terminated\n");
    	exit(1);
    }
    printf("Can get past the if-clause\n");

    char xxx[10];
    strlcpy(xxx, nullString, 1);
    return 0;	
}

这code永远不会被通过的if语句。它崩溃的if语句,而且是绝对的预期。

This code never gets passed the if statement. It crashes in the if statement and that is definitely expected.

因此​​,谁能想到的任何理由,第一个code能获得通过,如果没有如果的名字 - 崩溃的if语句>数据真的是NULL?这完全是神秘的给我。似乎不确定性。

So can anyone think of any reason why the first code can get passed that if-statement without crashing if name->data is really NULL? This is totally mysterious to me. It doesn't seem deterministic.

重要的额外信息:结果
两个注释之间的code是真正的完成,一切都没有被排除在外。此外,该应用程序的单线程,所以没有其他的线程可能会意外改变背景中的任何记忆。其中,发生这种情况的平台是PPC CPU(一G4,以防可能起到任何作用)。而如果有人想知道一下,这是因为信息包含一个联盟为种的名字是再一个结构(一种是工会,每一个可能的工会值是不同类型的结构体)的一种。但是这一切应该不是真正的问题在这里。

Important extra information:
The code between the two comments is really complete, nothing has been left out. Further the application is single threaded, so there is no other thread that could unexpectedly alter any memory in the background. The platform where this happens is a PPC CPU (a G4, in case that could play any role). And in case someone wonders about "kind.", this is because "information" contains a "union" named "kind" and name is a struct again (kind is a union, every possible union value is a different type of struct); but this all shouldn't really matter here.

我在这里的任何想法感谢。我即使它不只是一个理论更加感激,但如果有一种方法,我可以验证这个理论确实也是如此为客户着想。

I'm grateful for any idea here. I'm even more grateful if it's not just a theory, but if there is a way I can verify that this theory really holds true for the customer.

我已经接受了正确的答案,但以防万一有人发现在谷歌这个问题,这里到底发生了什么:

I accepted the right answer already, but just in case anyone finds this question on Google, here's what really happened:

该指针指向了记忆,一个已经被释放。释放内存不会让这一切为零或导致进程把它还给系统一次。因此,即使内存已经释放了错误,它包含正确的价值观。有问题的指针不为空的时候了的如果检查的执行。

The pointers were pointing to memory, that has already been freed. Freeing memory won't make it all zero or cause the process to give it back to the system at once. So even though the memory has been erroneously freed, it was containing the correct values. The pointer in question is not NULL at the time the "if check" is performed.

这检查后我分配一些新的内存,调用malloc。不知道究竟是什么做的malloc这里,但每次调用函数malloc或自由可以有深远的影响到进程的虚拟地址空间的所有动态内存。 malloc调用后,指针其实NULL。不知怎的的malloc(或某些系统调用malloc使用)归零已经释放的内存在指针本身的位置(不是它所指向的数据,指针本身就是动态内存)。归零内存,指针现在有值为0x0,这等于为NULL我的系统,当strlcpy被调用,它当然会崩溃的。

After that check I allocate some new memory, calling malloc. Not sure what exactly malloc does here, but every call to malloc or free can have far-reaching consequences to all dynamic memory of the virtual address space of a process. After the malloc call, the pointer is in fact NULL. Somehow malloc (or some system call malloc uses) zeros the already freed memory where the pointer itself is located (not the data it points to, the pointer itself is in dynamic memory). Zeroing that memory, the pointer now has a value of 0x0, which is equal to NULL on my system and when strlcpy is called, it will of course crash.

因此​​,真正的错误造成这种奇怪的行为是在我的code完全不同的位置。永远不要忘记:释放的内存保持其价值,但它是你无法控制多久。要检查你的应用程序在访问已释放存储器的存储错误,只是确保它被释放之前释放的内存始终是零。在OS X中,你可以通过设置在运行时的环境变量(不需要重新编译任何东西)做到这一点。当然这减慢程序相当一点,但你会抓住这些bug早得多。

So the real bug causing this strange behavior was at a completely different location in my code. Never forget: Freed memory keeps it values, but it is beyond your control for how long. To check if your app has a memory bug of accessing already freed memory, just make sure the freed memory is always zeroed before it is freed. In OS X you can do this by setting an environment variable at runtime (no need to recompile anything). Of course this slows down the program quite a bit, but you will catch those bugs much earlier.

推荐答案

这是可能的结构位于内存中已免费()'D,或堆已损坏。在这种情况下,的malloc()可修改记忆,思维,它是免费的。

It is possible that the structure is located in memory that has been free()'d, or the heap is corrupted. In that case, malloc() could be modifying the memory, thinking that it is free.

您可以尝试一个内存检查下运行您的程序。支持Mac OS X的一个内存检查程序是的valgrind ,虽然它仅支持英特尔,而不是在PowerPC的Mac OS X。

You might try running your program under a memory checker. One memory checker that supports Mac OS X is valgrind, although it supports Mac OS X only on Intel, not on PowerPC.

这篇关于怎样才能取消引用在C中的NULL指针不会崩溃的程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆