Hi Clark what do you mean by "Malloc effectively *never* returns NULL”
I’m looking at malloc man page (from Developer tools for Xcode 7.3.1) and I can read the following RETURN VALUES If successful, calloc(), malloc(), realloc(), reallocf(), and valloc() functions return a pointer to allocated memory. If there is an error, they return a NULL pointer and set errno to ENOMEM. anything else is “urban legends” :))) and BTW malloc that returns NULL isn’t failing (strictly speaking) it’s just following its contract if malloc SEGV then it would be failing. how about C++ code: #include <iostream> int main(int argc, const char * argv[]) { size_t need_size = 0x1000000000000; unsigned char *chars = nullptr; try { chars = new unsigned char[need_size]; std::cout << "allocation success" << std::endl; delete [] chars; chars = nullptr; } catch (std::bad_alloc &) { std::cout << "allocation error" << std::endl; } return 0; } release build returns allocation success Program ended with exit code: 0 if we follow your logic than new never throws, which is clearly wrong see C++ standard 18.6.1.1.3 Required behavior: Return a non-null pointer to suitably aligned storage (3.7.4), or else throw a bad_- alloc exception. This requirement is binding on a replacement version of this function. as I can see that’s not what happening with clang++ and standard doesn’t say anything about difference between optimized and non optimized code (in relation to operator new at least) thanks dm > On Jul 4, 2016, at 3:58 PM, Clark Cox <clarkc...@gmail.com> wrote: > > >> 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 > Dmitry Markman _______________________________________________ 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