Note that there are some explanatory texts on larger screens.

plurals
  1. POUnexpected flow of control (compiler-bug?) using errno as argument for exception in C++ (g++)
    primarykey
    data
    text
    <p>When using C++ exceptions to transport errno state, the compiled code that gets generated by g++ (4.5.3) for code such as the following</p> <pre><code>#include &lt;cerrno&gt; #include &lt;stdexcept&gt; #include &lt;string&gt; class oserror : public std::runtime_error { private: static std::string errnotostr(int errno_); public: explicit oserror(int errno_) : std::runtime_error(errnotostr(errno_)) { } }; void test() { throw oserror(errno); } </code></pre> <p>is rather unexpectedly (on Linux, x86_64)</p> <pre><code> .type _Z4testv, @function ... movl $16, %edi call __cxa_allocate_exception movq %rax, %rbx movq %rbx, %r12 call __errno_location movl (%rax), %eax movl %eax, %esi movq %r12, %rdi call _ZN7oserrorC1Ei </code></pre> <p>What this basically means is that errno as an argument to a C++ exception is pretty much useless due to the call to __cxa_allocate_exception preceding the call to __errno_location (which is the macro content of errno), where the former calls std::malloc and does not save errno state (at least as far as I understood the sources of __cxa_allocate_exception in eh_alloc.cc of libstdc++).</p> <p>This means that in the case that memory allocation fails, the error number that was actually to be passed into the exception object gets overwritten with the error number that std::malloc set up. std::malloc gives no guarantee to save an existing errno state, anyway, even in the case of successful exit - so the above code is definitely broken in the general case.</p> <p>On Cygwin, x86, the code that gets compiled (also using g++ 4.5.3) for test() is okay, though:</p> <pre><code> .def __Z4testv; .scl 2; .type 32; .endef ... call ___errno movl (%eax), %esi movl $8, (%esp) call ___cxa_allocate_exception movl %eax, %ebx movl %ebx, %eax movl %esi, 4(%esp) movl %eax, (%esp) call __ZN7oserrorC1Ei </code></pre> <p>Does this mean that for library code to properly wrap errno state in an exception, I'll always have to use a macro which expands to something like</p> <pre><code> int curerrno_ = errno; throw oserror(curerrno_); </code></pre> <p>I actually can't seem to find the corresponding section of the C++ standard which says anything about evaluation order in the case of exceptions, but to me it seems that the g++ generated code on x86_64 (on Linux) is broken due to allocating memory for the exception object <em>before</em> collecting the parameters for its constructor, and that this is a compiler bug in some way. Am I right, or is this some fundamentally wrong thinking on my part?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload