Odd code generated for non-virtual function call (leads to SIGSEGV)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

  gcc 4.3.3 -> gcc 4.6.latest

  target native x86 m32

  I did a quick bugzilla search, and archive search and found nothing
relevent.

  I've a class with overloaded functions, one of which is virtual,
and code is being generated to call the incorrect member function
on the x86 32-bit architecture.   The code is generated correctly on the
x86 64-bit architecture.

---- Class:-----

class c_logger {

    bool    l_debug;

public:
    c_logger(bool d)                { l_debug = d; }
    virtual ~c_logger(void) {};

    void        log(const char *, ...)
            __attribute__((format(printf, 2, 3)));
    size_t      trace(const char *, ...)
            __attribute__((format(printf, 2, 3)));

    virtual void   log(const char *, va_list) = 0;
    virtual size_t trace(const char *, va_list) = 0;

    void   set_tracing(bool d=false)   { l_debug = d; }
    bool   is_tracing(void)            { return l_debug; }
};

-----------------

The code in question:

----------------
bool
c_telcom_dlp::control(int argc, const char **argv, c_logger *lp)
{
    ulong unit = parse_unit(argv[0]);

    if (argc < 2) {
        if (unit == INVALID_UNIT) {
            unit = 0;
        }
        lp->log("%4.4lu/%2.2lu Argument required for control command\n",
                d_channel, unit);
        return true;
    }


    if (strcasecmp(argv[1], "line") == 0) {
        char  *cp;
        ulong line;

        if (unit != 0) {
            if (unit == INVALID_UNIT) {
====>           lp->log("%s Unit # must be supplied\n", t_dlp_name);
            } else {
                lp->log("%s Invalid Unit\n", t_dlp_name);
            }
            return true;
        }

----------------

The first call to c_logger::log(const char *, ...) is generated as:

        lp->log("%4.4lu/%2.2lu Argument required for control command\n",
                d_channel, unit);

.globl _ZN12c_telcom_dlp7controlEiPPKcP8c_logger
        .type   _ZN12c_telcom_dlp7controlEiPPKcP8c_logger, @function
_ZN12c_telcom_dlp7controlEiPPKcP8c_logger:
.LFB579:
        .loc 13 1074 0
        pushl   %ebp
.LCFI139:
        movl    %esp, %ebp
.LCFI140:
        pushl   %edi
.LCFI141:
        pushl   %esi
.LCFI142:
        pushl   %ebx
.LCFI143:
        subl    $236, %esp
.LCFI144:
        call    __i686.get_pc_thunk.bx
        addl    $_GLOBAL_OFFSET_TABLE_, %ebx
.LBB9:
        .loc 13 1076 0
        movl    16(%ebp), %eax
        movl    (%eax), %eax
        movl    8(%ebp), %edx
        movl    %eax, 4(%esp)
        movl    %edx, (%esp)
        call    _ZN5c_dlp10parse_unitEPKc@PLT
        movl    %eax, -64(%ebp)
        .loc 13 1078 0
        cmpl    $1, 12(%ebp)
        jg      .L132
        .loc 13 1079 0
        cmpl    $65535, -64(%ebp)
        jne     .L133
        .loc 13 1080 0
        movl    $0, -64(%ebp)
.L133:
        .loc 13 1083 0
        movl    8(%ebp), %eax
        movl    208(%eax), %edx
        movl    -64(%ebp), %eax
        movl    %eax, 12(%esp)
        movl    %edx, 8(%esp)
        leal    .LC7@GOTOFF(%ebx), %eax
        movl    %eax, 4(%esp)
        movl    20(%ebp), %eax
        movl    %eax, (%esp)
====>   call    _ZN8c_logger3logEPKcz@PLT
        .loc 13 1084 0
        movb    $1, -194(%ebp)
        jmp     .L134

-----------------------------

The second call to c_logger::log (the marked line above):

====>           lp->log("%s Unit # must be supplied\n", t_dlp_name);

.LBB10:
        .loc 13 1147 0
        cmpl    $0, -64(%ebp)
        je      .L137
        .loc 13 1148 0
        cmpl    $65535, -64(%ebp)
        jne     .L138
        .loc 13 1149 0
        movl    20(%ebp), %eax
        movl    (%eax), %eax
        addl    $8, %eax
        movl    (%eax), %edx
        movl    8(%ebp), %eax
        addl    $374, %eax
        movl    %eax, 8(%esp)
        leal    .LC12@GOTOFF(%ebx), %eax   # %s Unit # must be supplied\n
        movl    %eax, 4(%esp)
        movl    20(%ebp), %eax
        movl    %eax, (%esp)
====>   call    *%edx

The second invocation is invoking the virtual member function
c_logger::log(const char *, va_list) instead of the base-class
c_logger::log(const char *, ...) member.  The result is a segmentation
violation because the va_args structure hasn't been initialized.

Adding an additional argument to the second lp->log() call will cause the
correct (and working) code to be generated.

t_dlp_name (the single argument to the second log call) is a data member
in the class calling lp->log() and is defined as:

      char             t_dlp_name[MAX_DLP_NAME+1];

I've compiled this with 4.3.3 and the most recent 4.6 from subversion and
in both cases the virtual function is called when the base member should
be called.

thanks for any pointers,

scott


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux