This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

ss980406 -- SIGSEGV when attempting to determine "typeid"


I've got an app that uses a fairly deep hierarchy of interface
classes, all of them hanging off a single "Rendered" interface class.
In one place in my code, I take pointers to objects of derived classes
and pack them into a heterogenous container for storage and eventual
removal.  At the removal end, all I know is that the pointer is of
type "Rendered *" and I need to downcast it to a more specific
interface before I can do work on it.  If "obj" contains the address
of a "Rendered" interface, then the line

    const type_info &ti = typeid(*obj);

should give me the type of the underlying object.  However, the
compiler is giving me the following i586 assembler output (according
to "objdump"):

 2c9:   8b 45 e8        movl   0xffffffe8(%ebp),%eax
 2cc:   8b 50 04        movl   0x4(%eax),%edx
 2cf:   83 c2 04        addl   $0x4,%edx
 2d2:   8b 0a           movl   (%edx),%ecx
 2d4:   89 4d c4        movl   %ecx,0xffffffc4(%ebp)
 2d7:   8b 4d c4        movl   0xffffffc4(%ebp),%ecx
 2da:   ff d1           call   *%ecx
 2dc:   89 45 c8        movl   %eax,0xffffffc8(%ebp)
 2df:   8b 4d c8        movl   0xffffffc8(%ebp),%ecx
 2e2:   89 4d e4        movl   %ecx,0xffffffe4(%ebp)

The segmentation fault occurs at line 0x2d2, where we are
dereferencing %edx (which has the value 0x7 according to the
debugger).  Writing a toy program that does a similar "typeid" on a
pure virtual base pointer produces the following assembler output:

 8048760:       8b 45 fc        movl   0xfffffffc(%ebp),%eax
 8048763:       8b 10           movl   (%eax),%edx
 8048765:       83 c2 04        addl   $0x4,%edx
 8048768:       8b 0a           movl   (%edx),%ecx
 804876a:       89 4d f0        movl   %ecx,0xfffffff0(%ebp)
 804876d:       8b 4d f0        movl   0xfffffff0(%ebp),%ecx
 8048770:       ff d1           call   *%ecx
 8048772:       89 c6           movl   %eax,%esi
 8048774:       89 75 f8        movl   %esi,0xfffffff8(%ebp)

The second line is the important one---we are taking the contents of
%eax as an address and extracting its contents as a long.  In the bad
code, we're getting the address and bumping it by 0x4 before
dereferencing it.  That means we end up getting the (long) value 0x3,
storing it in %edx, bumping *that* by 0x4, and then we're trying to
dereference it.  Blammo.

The working assembler code maps to the following insns:

    (note 55 54 57 ("baz.cc") 40)

    (insn 57 55 59 (set (reg:SI 27)
            (mem:SI (plus:SI (reg:SI 18)
                    (const_int -4)))) -1 (nil)
        (nil))

    (insn 59 57 61 (set (reg:SI 28)
            (plus:SI (mem/s:SI (reg:SI 27))
                (const_int 4))) -1 (nil)
        (nil))

    (insn 61 59 63 (set (reg:SI 29)
            (mem/s:SI (reg:SI 28))) -1 (nil)
        (nil))

    (call_insn 63 61 65 (parallel[ 
                (set (reg:SI 0 %eax)
                    (call (mem:QI (reg:SI 29))
                        (const_int 0)))
                (set (reg:SI 7 %esp)
                    (plus:SI (reg:SI 7 %esp)
                        (const_int 0)))
            ] ) -1 (nil)
        (nil)
        (nil))

    (insn 65 63 67 (set (reg:SI 26)
            (reg:SI 0 %eax)) -1 (nil)
        (nil))

    (insn 67 65 68 (set (mem:SI (plus:SI (reg:SI 18)
                    (const_int -8)))
            (reg:SI 26)) -1 (nil)
        (nil))

while the bad assembler code maps to the following insns:

    (note 186 185 188 ("pick.cc") 66)

    (insn 188 186 190 (set (reg:SI 50)
            (mem:SI (plus:SI (reg:SI 18)
                    (const_int -24)))) -1 (nil)
        (nil))

    (insn 190 188 192 (set (reg:SI 51)
            (plus:SI (mem/s:SI (plus:SI (reg:SI 50)
                        (const_int 4)))
                (const_int 4))) -1 (nil)
        (nil))

    (insn 192 190 194 (set (reg:SI 52)
            (mem/s:SI (reg:SI 51))) -1 (nil)
        (nil))

    (call_insn 194 192 196 (parallel[ 
                (set (reg:SI 0 %eax)
                    (call (mem:QI (reg:SI 52))
                        (const_int 0)))
                (set (reg:SI 7 %esp)
                    (plus:SI (reg:SI 7 %esp)
                        (const_int 0)))
            ] ) -1 (nil)
        (nil)
        (nil))

    (insn 196 194 198 (set (reg:SI 49)
            (reg:SI 0 %eax)) -1 (nil)
        (nil))

    (insn 198 196 199 (set (mem:SI (plus:SI (reg:SI 18)
                    (const_int -28)))
            (reg:SI 49)) -1 (nil)
        (nil))

so the problem is the "(plus:SI (reg:SI 50) (const_int 4))" in
instruction 190.

If this isn't enough to track down the bug, I can send a copy of the
preprocessed file, but it's long enough (440kB) that I don't want to
do it unless necessary.  This is all on an ultra-custom Linux 2.0.33
running EGCS ss980406.

Derek

-- 
Derek Upham
sand@celia.serv.net                                 http://www.serv.net/~sand

"Ha!  Your Leaping Tiger Kung Fu is no match for my Frightened Piglet style!"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]