3 ms·
I used to work on lower level stuff a place with a large C++ codebase designed by a bunch of C guys. We had tight memory requirements, so a custom operator new
by logicchop 7y ago
I used to work on lower level stuff a place with a large C++ codebase designed by a bunch of C guys. We had tight memory requirements, so a custom operator new (not nothrow) was supplied; but exceptions were also disabled, so the supplier of operator new couldn't throw in their implementation.
So that's how it was, and the code base was littered with lots of little checks on what new expressions were returning, things like:
int *p = new int[1024];
if (!p) return SOME_ERROR;
doSomething(*p);
Of course, the C++ standard says that operator new will never return null (it's supposed to throw if it fails). So the compiler sees this code and says "hey, that if (!p) check isn't necessary.." and so none of those little checks gets emitted. Sure enough, it happens that the operator new returns null now and then because everyone is on a tight memory budget, but instead of catching it and returning an error, the code just goes on to crash.
- MaxBarraclough 7y agoThe answer seems to be to use std::nothrow, which looks like: [0] int *p = new (std::nothrow) int[5]; // gives null if alloc fails A related question: Many C++ coding standards, including Google's, prohibit use of C++ exceptions. Do they have to use the nothrow syntax everywhere the new operator is used? [0] https://www.cplusplus.com/reference/new/operator%20new[]/ https://www.cplusplus.com/reference/new/operator%20new[]/
- jfkebwjsbx 7y agoYou can also abort the program, which is what most programs do on OOM anyway.
- twic 7y agoMy guess would be that they lean on the fact that "malloc never fails" [1]. Under that model, new and malloc always give you a pointer you can use, it's just that sometimes, using it will give you a segfault. [1] https://scvalex.net/posts/6/ https://scvalex.net/posts/6/
- MaxBarraclough 7y agoThat blog post describes Linux's default 'memory overcommitment' behaviour. Oddly it fails to mention the term 'overcommit'. As the post says, malloc can return null even where overcommit is used; it's not true that malloc never fails when overcommit is enabled. Even if it were true that malloc/calloc/realloc/new/new[] could never fail on your OS+compiler, it doesn't seem wise to write code that relies on that non-standard guarantee. Poor robustness and portability.
- saagarjha 7y agoNot a Googler, but I believe that exceptions coming from the standard library (which must support exceptions, of course…) are allowed.
- klodolph 7y agoVarious folks working on C++ tooling at Google and e.g. Abseil have commented in talks—no, the standard library is not required to support exceptions. They are in fact disabled. Code which would throw an exception instead aborts the program.
- saagarjha 7y agoAh, I see that Microsoft's implementation does allow this. I wonder if you could still call that standards compliant?
- klodolph 7y agoThe C++ requires exceptions, so with -fno-exceptions, the compiler is not standards compliant. However, the big companies like Apple, Facebook, and Google simply don’t care about standards compliance in their internal C++ code bases. At least, not as an end goal. There are a lot of good talks about this.
- klodolph 7y agoInstead of throwing, you just abort the program. If you are running part of a backend service this is reasonable, under some assumptions. If you fail to allocate memory, there’s a good chance that your process can’t continue servicing requests anyway. So, it’s a good tradeoff to abort. The client can retry later or with a different backend, and the job scheduler can start another instance of the process.
- pif 7y agoNo excpetions allowed? Than using "new" is the wrong choice! Redefining the "new" operator only makes sense when you can reuse existing code, but if you must add that check for everey "new" invocation, then you are forced to parse all your existing code and using a separate function makes sense. Sorry for your colleagues, but this is not a problem with undefined behaviour: it's the original developer fault! And I'd hate if compilers were forced to restrain themselves from helping smart developers in order to please loosy developers.
- deleted 7y ago[deleted]