Checking string allocations (was Re: String literals, ASCII vs UTF-8)

Caolán McNamara caolanm at redhat.com
Mon Mar 5 08:34:00 PST 2012


On Mon, 2012-03-05 at 15:29 +0000, Michael Meeks wrote:
> On Fri, 2012-03-02 at 17:16 +0000, Caolán McNamara wrote:
> At the most banal level, I suspect that:
> 
> 	struct Empty { int unused; };
> 	Empty *p = new Empty();
> 	delete p;
> 
> 	can't legitimately be optimised away if we have a throwing constructor,
> but of course I can dig out some compiler people who know what they're
> on about here.

In the general case presumably you then need to run around sticking
throw()/nothrow onto loads of things in order to tell the compiler that
stuff isn't going to throw exceptions, and/or disabling exceptions to
get the compiler to do something different.

Amusingly, for the trivial example

#include <new>
void foo()
{
        struct Empty { int unused; };
#ifdef TESTNOTHROW
        Empty *p = new(std::nothrow) Empty();
#else
        Empty *p = new Empty();
#endif
        delete p;
}

and pure .o size.
g++ -O2 -DTESTNOTHROW -c test.cxx gives a 1060byte .o
while
g++ -O2 -c test.cxx gives a 996 byte .o
and
g++ -O2 -fno-exceptions -c test.cxx
gives a 996 byte .o as well. Doesn't appear to be the case that gcc
optimizes out the call to new regardless of what optimization level or
-fno-exceptions that might let it know it could do it if it wanted.

> 	Consistently calling std::abort() somewhere rather than waiting for a
> SEGV sounds fine, though preferably not in-lined into many tens if not
> hundreds of thousands of duplicate compare/branch/call-function sides at
> every object construction.

Looking at std::abort vs std::throw for new, assuming something is built
with -fexceptions, and once there's *something* in a function called
that might throw an exception I *guess* you pay a fixed penalty and it
doesn't really matter how many things in that function might throw
something ?, that's the way I internalized it anyway.

Anyway, FWIW I'm not massively interested in the allocate, "oh we don't
have enough, lets try and release some" unrealistic path, just the load
binary file format scenario of
int32_t foo = read_foo();
new Foo[foo] where foo is approx MAX_SIZE, and new should immediately
throws without even making any effort to allocate, given that the number
to allocate would overflow and the .wmf/.doc or whatever import is
aborted with a toplevel import-level catch without the app exiting. If
we didn't have a single-process-app none of this would matter much I
suppose.

> 	I guess I now need to go and characterise how much of the saving is
> from removing tens of thousands of in-lined 'if (baa) throw
> std::bad_alloc();' calls vs. the exception unwind and knock-on optimiser
> impact of having all that there.

hmm, initially I would have said that the savings must all be from the
removal of the inlining of the "check for NULL and throw itself" given
that the compiler can only see the body of rtl_uString2String when
building one object file and not for any of the others, but I see now
that rtl_uString2String is marked as nothrow so the compiler could make
use of that I guess.

C.



More information about the LibreOffice mailing list