[development-gcc] The GiNaC failure
Jan Hubicka
jh@suse.cz
Sat Aug 30 17:11:00 GMT 2003
> Okay, I think it's a compiler error, but in the C++ frontend (or in some
> later optimization, but hold on). And it happens only very seldom. And
> if it happens one must get unlucky to see any segfaults. That's why we
> don't see it anywhere else.
>
> A testcase is attached below. It was extracted basically from GiNaC, but
> it doesn't exhibit any segfaults, as this requires much more surrouding
> code from GiNaC, for which the libraries and whatnot are needed. One can
> see the error only when it is run under valgrind, when it gives warnings
> about accessing uninitialized data. The uninitialized thing is the
> "bp->refcount". What happens in this function
>
> void ex::construct_from_basic(const basic &b) {
> const ex & tmpex = b.eval();
> bp = tmpex.bp;
> bp->refcount++;
> }
>
> is the following: a temporary is created for the result of b.eval(), and
> because eval might throw (which it then indeed does) a cleanup must also
> be created for this temporary. But it forgets adding any call to
> the ctor of that temporary, or initializing it by any other means,
> therefore when calling the dtor in the cleanup, it accesses uninit memory.
>
> One can see this easily with the added printfs. In the faulting case only
> the dtor, but not the ctor are called.
>
> If one removes the '&', i.e. there is no need for a temporary, no such
> things happen, and valgrind gives no warnings. Indeed if I do exactly
> this change (i.e. going from reference to copied object) in the
> ex::construct_from_basic() function in GiNaC (patch attached, jj you might
> simply want to add it to the package), the testsuite runs through, and all
> is happy.
OK, I found what is gonig on, but the fix does not seem to be easy.
The problem seems to be the patch:
2003-06-19 Mark Mitchell <mark@codesourcery.com>
PR c++/11041
* call.c (initialize_reference): Do not use cp_finish_decl to emit
temporary variables.
* cp-tree.h (static_aggregates): Declare.
(pushdecl_top_level_and_finish): Likewise.
* decl.c (pushdecl_top_level_1): New function.
(pushdecl_top_level): Use it.
(pushdecl_top_level_and_finish): New function.
(initialize_local_var): Remove redundant code.
(cp_finish_decl): Remove support for RESULT_DECLs. Don't check
building_stmt_tree.
* decl.h (static_aggregates): Remove.
* decl2.c (get_guard): Use pushdecl_top_level_and_finish.
* rtti.c (get_tinfo_decl): Use pushdecl_top_level_and_finish.
(tinfo_base_init): Likewise.
Basically we initially generated something like:
const ex temporary = b.eval();
const ex & tmpex = &tempoary;
and attached cleanup to the second statement and forth. The patch
changes it into something like:
const ex temporary;
const ex & tmpex = (temporary=b.eval(), &tempoary);
But we can not get the cleanup to the middle of expression. This is
needed to fix different testcase
class hop
{
public:
hop operator* () const;
};
int main(void)
{
const hop &x = *x;
}
Where we need the variable x already in existence in order to initialize
the temporary.
I am not quite sure how to fix it but for our purposes I would suggest
reverting that patch as ICE is better than misscompilation.
Mark, better ideas?
Honza
More information about the Gcc-bugs
mailing list