On Tue, 8 Mar 2005, Richard B. Kreckel wrote:
On Mon, 7 Mar 2005, Ralf Goertz wrote:
The following program segfaults
%--------------------------------- #include<iostream> #include<cln/cln.h>
using namespace cln; using namespace std;
main(){ cl_modint_ring R=find_modint_ring(9811); cl_univpoly_modint_ring P=find_univpoly_ring(R); return 0; } %--------------------------------------
Using the 1.1.9-debug.rpm on a SuSE 9.2 linux, this is the output of gdb
Program received signal SIGSEGV, Segmentation fault. 0x400fe50c in cln::cl_make_univpoly_ring (r=@0xbfffefb0) at object.h:475 475 { return heappointer->type; }
Ouch! This is an ugly bug and I'm not quite sure how to fix it.
The problem is with the descendants of struct cl_heap. In include/cln/object.h:164 there is:
struct cl_heap { int refcount; // reference count for garbage collection const struct cl_class * type; // type tag for dynamic typing };
But in include/cln/modinteger.h:209 there is:
class cl_heap_modint_ring : public cl_heap { // ... // This class is intented to be subclassable, hence needs a virtual destructor. virtual ~cl_heap_modint_ring () {} private: virtual void dummy (); };
At this point, the two virtual functions introduce a vptr to each object of class cl_heap_modint_ring. By the way, note that the same happens to class cl_heap_univpoly_ring.
Now, in your program you call find_univpoly_ring(const cl_ring& r) where r is of dynamic type cl_modint_ring. It determines that the ring does not exist yet and calls cl_make_univpoly_ring(const cl_ring& r) with in turn invokes r.pointer_type(). But that is actually:
const cl_class * cl_rcpointer::pointer_type() const { return heappointer->type; }
Since heappointer is of static type cl_heap but of dynamic type cl_heap_modint_ring (with vptr!), referencing cl_heap::type member variable is undefined.
No it isn't undefined. My analysis above was incorrect, I'm afraid. Rather, some debugging has revealed that we are having some sort of type-punning problem in include/cln/modinteger.h. It happens in the ctor from cl_modint_ring*: inline cl_modint_ring::cl_modint_ring (cl_heap_modint_ring* r) : cl_ring ((cl_private_thing) (cl_inc_pointer_refcount((cl_heap*)r), r)) {} The code generated by this function stomps on the type* member variable of cl_heap_modint_ring (inherited from cl_heap). I am unable to see why, though. Anyone else sees clearer? Oh, yes, the fact that it stomps on type* has something to do with the vptr being there or not. But what? For one thing, there is a little inversion problem, as becomes apparant by the need to cast r to a cl_heap*. That should not be needed, because cl_heap is the base class of cl_heap_modint_ring. However, cl_heap_modint_ring is defined further down in that header file! So, the compiler could hardly guess that the two are related. So, if we put that ctor below the definition of cl_heap_modint_ring we get away without the cast. But that doesn't seem to be enough, though. Rewriting it in a dumb straightforward way: inline cl_modint_ring::cl_modint_ring (cl_heap_modint_ring* r) { heappointer = r; cl_inc_pointer_refcount(heappointer); } Theoretically, this solves the crash observed by Ralf. However, it introduces another one because the immediate base class of cl_modint_ring is cl_ring and we're now calling the base class' default ctor which tries to reference cl_no_ring (see include/cln/ring.h:373). Maybe this can be cured by introducing CL_PROVIDE(cl_no_ring) in include/cln/modinteger.h... Anyway, this is not a solution. It's no more than a poorly understood workaround. Can anybody shed some light on this issue? -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>