Re: malloc was optimized out
Re: malloc was optimized out
- Subject: Re: malloc was optimized out
- From: Clark Cox <email@hidden>
- Date: Mon, 04 Jul 2016 12:58:31 -0700
> On Jul 4, 2016, at 11:09, Dmitry Markman <email@hidden> wrote:
>
> Hi all
>
> in the Xcode 7.3.1 the following simple code
>
> #include <iostream>
>
> int main(int argc, const char * argv[]) {
> size_t need_size = 0x1000000000000;
>
> void *data = malloc(need_size);
>
> if(data == NULL) {
> std::cout << "data == NULL" << std::endl;
> return 1;
> } else {
> std::cout << "data != NULL" << std::endl;
> }
> free(data);
>
> return 0;
> }
>
> reports for the release build
>
> data != NULL
> Program ended with exit code: 0
Malloc effectively *never* returns NULL. In cases where that is known to be the case, the compiler is absolutely within it’s rights to remove the malloc call altogether and take the "!= NULL” path.
> which is clearly wrong, because right answer would be
It’s only wrong in the abstract sense. That is, conforming C code is not allowed to assume that malloc never returns NULL, but a platform (I.e. OS + compiler + libraries, etc) *can*.
> data == NULL
> Program ended with exit code: 1
>
>
> g++ behaves correctly
>
> recently I found out that we reported that problem to Apple
>
> and we got an answer
>
> ""Engineering has determined that this issue behaves as intended based on the following information:
>
> The compiler "knows" how malloc works, and is allowed to optimize as if it never fails.
>
> We are now closing this bug report.”
>
> clearly in my situation clang knows nothing :((
>
> clang can’t optimize malloc here, because result of the malloc is used.
No it isn’t.
- The only way you “use” it is to check it against NULL
- The compiler is free to optimize away the check and the entire “== NULL” branch, as it knows it will never happen
- Once that check is removed, there are no other uses of data (aside from the initialization and the free)
In other words, after that optimization, your code is functionally equivalent to:
#include <iostream>
int main(int argc, const char * argv[]) {
size_t need_size = 0x1000000000000;
void *data = malloc(need_size);
std::cout << "data != NULL" << std::endl;
free(data);
return 0;
}
- The compiler knows that data is never used between the malloc and the free, in which case, it is free to reorder things like so:
#include <iostream>
int main(int argc, const char * argv[]) {
size_t need_size = 0x1000000000000;
free(malloc(need_size));
std::cout << "data != NULL" << std::endl;
return 0;
}
- The compiler also knows that free(malloc(…)) is a no-op (in terms of observable behavior within a standard C program), so it is free to change that to:
#include <iostream>
int main(int argc, const char * argv[]) {
size_t need_size = 0x1000000000000;
std::cout << "data != NULL" << std::endl;
return 0;
}
- Also, size is now not used, so, after optimization, your code is functionally equivalent to:
#include <iostream>
int main(int argc, const char * argv[]) {
std::cout << "data != NULL" << std::endl;
return 0;
}
>
> we have much more complex use case where
>
> malloc was optimized out,
In your actual code, is the value of data actually used (I.e. Does something happen that requires its value other than calling free or checking against NULL)?
>
> I just simplified the code
>
> Note: -fno-builtin flag solve the problem
>
>
> also if I use
>
> std::cout << "data != NULL" << data << std::endl;
>
> malloc wasn’t optimized
That is because the actual value of data is now used (rather than just its "NULL-ness”), and the compiler can’t optimize that use away any more.
--
Clark Smith Cox III
email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden