> On Jul 4, 2016, at 11:09, Dmitry Markman <dmark...@mac.com> 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
clarkc...@gmail.com


 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list      (Xcode-users@lists.apple.com)
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/xcode-users/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to