Ich habe das sehr alte (und sehr große) Win32-Projekt, das massive Prüfungen mit NULL-Zeiger verwendet, indem er den Zeiger auf den dereferenzierten Zeiger wirft. Wie folgt aus:Force erlauben Dereferenzierung von NULL-Zeiger
int* x = NULL; //somewhere
//... code
if (NULL == &(*(int*)x) //somewhere else
return;
Und ja, weiß ich, dass dieser Code ist dumm und müssen Refactoring werden. Aber es ist unmöglich wegen der großen Menge an Code. Im Moment muss ich dieses Projekt unter MacOS Sierra in Xcode kompilieren, was zu großen Problemen führt ... Es stellt sich heraus, dass die Bedingung im Release-Modus (mit Code-Optimierung) mit falschem Verhalten ausgeführt wird (sogenanntes undefiniertes Verhalten wegen Dereferenzierung von NULL) Zeiger).
Nach this document for GCC gibt es eine Option -fno-delete-null-pointer-checks, aber es scheint, funktioniert nicht für LLVM wenn O1, O2 oder O3 Optimierung aktiviert. Die Frage ist also: Wie kann ich den LLVM 8.0-Compiler zwingen, solche Dereferenzierungen zuzulassen?
UPDATE. Das echte Arbeitsbeispiel, um das Problem zu überprüfen.
//somewhere 1
class carr
{
public:
carr(int length)
{
xarr = new void*[length];
for (int i = 0; i < length; i++)
xarr[i] = NULL;
}
//some other fields and methods
void** xarr;
int& operator[](int i)
{
return *(int*)xarr[i];
}
};
//somewhere 2
carr m(5);
bool something(int i)
{
int* el = &m[i];
if (el == NULL)
return FALSE; //executes in debug mode (no optimization)
//other code
return TRUE; //executes in release mode (optimization enabled)
}
Bei -O0
und -O1
, something
keeps the null check, und der Code "funktioniert":
something(int): # @something(int)
pushq %rax
movl %edi, %eax
movl $m, %edi
movl %eax, %esi
callq carr::operator[](int)
movb $1, %al
popq %rcx
retq
Aber -O2
und oben, the check is optimized out:
something(int): # @something(int)
movb $1, %al
retq
[Entsprechender Fehlerbericht] (https://llvm.org/bugs/show_bug.cgi?id=9251). Es ist nicht vielversprechend: Die Flagge wird in der Tat ignoriert (es wurde zuerst nicht erkannt). – Quentin
'-fno-delete-null-pointer-checks' soll nicht' & * (int *) x' beeinflussen, das immer noch 'NULL' sein darf. Mit clang auf http://gcc.godbolt.org/ überprüfen, mit einfach 'bool b (short * p) {zurückgeben 0 == & * (int *) p; } ', erzeugt clang korrekten Code. Bitte posten Sie ein minimales vollständiges Programm, in dem Ihr Compiler falschen Code erzeugt. – hvd
@hvd Ich habe ein echtes Beispiel gepostet. Ich bin mir nicht sicher, ob dieses Problem mit GCC zu tun hat, ich habe nur in Apple LLVM 8.0 gesehen –