- To: gcc-help@xxxxxxxxxxx
- Subject: Odd code generated for non-virtual function call (leads to SIGSEGV)
- From: Scott Lurndal <scott@xxxxxxxxxxx>
- Date: Tue, 13 Mar 2012 15:03:10 -0700
- Comment: DKIM? See http://www.dkim.org
- Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys
- Dkim-signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1332281012; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Date:From:To:Subject:Message-ID:Mime-Version:Content-Type: Content-Disposition:User-Agent:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=oFAc+FitfE+S5DWNpyKpq9kgFGc=; b=g/5MOeN+gymVNpj sh7Z0N7dPgg52glfPFEKmZif2Hh1Ar3IO329GEUpmSifW6xrW/yAy15Fr1LoQftJ eIEMJrjHnvJk0qFxXsAk1ShopCcjeUMxCd+VPjK+Q7zJcLcCXQedPB3QFdZk6sKM O4aRy9vCWZb+tt4Vd51O/Zy8IcHU=
- User-agent: Mutt/1.4.2.2i
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
[Linux C Programming]
[Linux Kernel]
[eCos]
[Fedora Development]
[Fedora Announce]
[Autoconf]
[The DWARVES Debugging Tools]
[Yosemite Campsites]
[Yosemite News]
[Linux GCC]