Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

Pure Virtual Function Incorrectly Inlined by IPO w/ Anonymous Union

Sawin__Matthew
1,481 Views

It appears that the compiler is incorrectly inlining calls to pure virtual functions in certain situations where IPO is enabled and an anonymous union is declared. The simplest example I can come up with is below. Removing the anonymous union or compiling without IPO resolves the issue.This issue is present in compiler versions 14.0.1 and 15.0.1 on CentOS 6.6 with gcc 4.4. Please advise on any known workarounds or fixes in upcoming releases.

This example should print out "hello world" but instead crashes with "pure virtual method called". The program runs successfully when compiled with gcc 4.4 or 4.8.

abstract.h:

#ifndef ABSTRACT_H_
#define ABSTRACT_H_

//some other struct, must be defined in the cpp
struct other;

class abstract
{
public:

  //the abstract must have a virtual destructor
  virtual ~abstract() { }

  //this is the pure virtual function the concrete class defines
  virtual void bar(const char *s) = 0;

  //the abstract class must have a non virtual function which calls the virtual function
  void foo(const char *s);

  //the abstract class must reference a another struct for some reason
  other *o;
};

#endif

abstract.cpp:

#include "abstract.h"

//the other struct must be defined
struct other { };

void abstract::foo(const char *s)
{
  //this is the part that breaks
  //the compiler should produce a virtual function call to bar()
  //instead, it inlines a call to a __cxa_pure_virtual
  bar(s);
}

function.h:

#ifndef FUNCTION_H_
#define FUNCTION_H_

//this function only exists to provide another layer of indirection to confuse ipo
void function();

#endif

function.cpp:

#include "function.h"

#include "abstract.h"

#include <stdio.h>

//there must be some other interface to inherit from
class interface
{
public:
  virtual ~interface() { }
};

//there must be a concrete class,
//inheriting from both the interface and the abstract class
class concrete : public interface, public abstract
{
public:

  //the concrete implementation of abstract::bar
  //should be called but it never is
  void bar(const char *s) override
  {
    printf("%s world\n", s);
  }
};

void function(abstract *a)
{
  //call to abstract::foo, which calls abstract::bar
  a->foo("hello");
}

void function()
{
  //call the other function with an instance of concrete,
  //implicitly converted to abstract
  function(new concrete());
}

main.cpp:

#include "function.h"

//there must be a class or struct
struct my_struct
{
  //it must declare a constructor but it does not need to be defined
  my_struct();
};

//there must be something else that wraps the struct in an anonymous union
struct my_union
{
  union
  {
    int i;
    my_struct s;
  };
};

int main(int argc, char *argv[])
{
  //the call to function() creates and uses an of an object with a complex class hierarchy
  //using this object should print out "hello world"
  //instead the program crashes with "pure virtual method called"

  //this appears to be the simplest program that can reproduce the error
  //if any part of the anonymous union above is removed
  //or if any part of the class hierarchy is removed
  //then the program works as expected

  //the function must be defined in a separate library to confuse ipo
  function();

  return 0;
}

Makefile:

CXX := icpc
CXXFLAGS := -std=c++11 -ipo
AR := xiar
ARFLAGS := rcs
LDFLAGS := -ipo

main: main.o library.a
	$(CXX) $(LDFLAGS) $^ -o $@

library.a: abstract.o function.o
	$(AR) $(ARFLAGS) $@  $^

%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

.PHONY: all
all: main

.PHONY: clean
clean:
	rm -f main *.a *.o
0 Kudos
20 Replies
Kittur_G_Intel
Employee
1,466 Views

Hi, 

I tried with the latest 15.0 version as well as others including 14.X versions and couldn't reproduce the issue. Tried with compatible RH EL 6.X systems (don't have Cent OS)  with gcc 4.4.X and icc was successful as well.

%icc -V
Intel(R) C Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 15.0.1.133 Build 20141023

%sysinfo
Linux Distro:   Red Hat Enterprise Linux Server release 6.3 (Santiago)
GNU C Library:  /lib/libc-2.12.so
GCC Version:    gcc (GCC) 4.4.6 20120305 (Red Hat 4.4.6-4)
Kernel Release: 2.6.32-279.el6.x86_64
Architecture:   x86_64

 

%make
icpc -std=c++11 -ipo -c main.cpp -o main.o
icpc -std=c++11 -ipo -c abstract.cpp -o abstract.o
i
cpc -std=c++11 -ipo -c function.cpp -o function.o
i
xiar rcs library.a  abstract.o function.o
xiar: executing 'ar'
icpc -ipo main.o library.a -o main

%./main
hello world

Also tried on RH EL 7.0  and couldn't reproduce also.  

Can you provide the following:

1) %icc -V

2) %uname -a

3) Can you compile the files with -P option to generate the pre-processed i files and attach to this issue so I can try to reproduce on my system?

% icpc -std=c++11 -P main.cpp abstract.cpp function.cpp

%icpc -std=c++11 -o main main.i abstract.i function.i

%./main

hello world

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

_Thanks, Kittur 

 

 

0 Kudos
Sawin__Matthew
1,466 Views

Thanks for the quick response. The .i files are attached. Let me know if there is any other system info you need.

$ which icc
/opt/intel/composer_xe_2015.1.133/bin/intel64/icc

$ icc -V
Intel(R) C Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 15.0.1.133 Build 20141023
Copyright (C) 1985-2014 Intel Corporation.  All rights reserved.

$ icc -v
icc version 15.0.1 (gcc version 4.4.7 compatibility)

$ gcc -v
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC)

$ uname -a
Linux dev11.s 3.10.42-1.el6.elrepo.x86_64 #1 SMP Sat Jun 7 20:16:58 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Hi Mathew,

Thanks for attaching the files and for the additional info. I tried with the pre-processed files as well on all the equivalent systems I've access to (RH EL6) but I still couldn't reproduce the issue as it worked fine.  The only difference between your environment to mine are: The system (EL 6.3, EL 7.0) isn't Cent-OS but equivalent and it's 6.3 (not 6.6) and 7.0.  So, what I did was to file the issue with our developers to check if they can try on any equivalent system they have and let me know as well. I'll update you accordingly on their investigation.

_Kittur 

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Hi Mathew,
Our developer working on this issue tried on the same configuration you did and still couldn't reproduce the issue as well :-(  If you happen to come up with any other test case(s) that can reproduce the issue I'd be glad to pursue further on this, appreciate much. 
_Kittur 

0 Kudos
Sawin__Matthew
1,466 Views

The problem seems to be in the final ipo/link phase so to help isolate that I've attached main.o and library.a created on CentOS 7.0 system with gcc 4.8 installed.

$ tar -xzf main.tar.gz

$ icpc -ipo main.o library.a -o main

$ ./main
pure virtual method called
terminate called without an active exception
Aborted

I can replicate on CentOS 6 & 7 as well as Linux Mint 17.

 

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Hi Mathew,
Thanks for attaching the files (which is very helpful) and I'll update you soon after further investigation. Appreciate your patience till then.
_Kittur

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Thanks Mathew, I've reproduced the issue and it looks like a compiler bug. I've again escalated to the issue to the product team and will update you as soon I've any info, appreciate much.

_Kittur

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Mathew, can you try and compile with "-no-ansi-alias" option and try your test case and see if that fixes the issue?  Reason, this could be related to ANSI alias rules and needs to be investigated further, thanks. Reason I can't try is because I can only reproduce the issue with the .o files you attached.

_Kittur 

0 Kudos
Sawin__Matthew
1,466 Views

Thanks again for your help, I'm glad you guys were able to reproduce. I tried compiling with -no-ansi-alias and that did not fix the issue. Let me know if there is anything else you would like me to try or if you need any other intermediate files.

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Mathew, for now, we have sufficient info for debugging this issue and will update you as soon as I've an update from our developers, appreciate much.

_Kittur 

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Hi Mathew,

I need your input on why the source code you had attached to this issue for us to reproduce is different from the object files you sent later? We notice some discrepancies between the object files and the source code you had sent:

  1.    The object files have main() starting at line 21. 
  2. The source files have main() at line 18.
  3. The object files have the size of the class "concrete" as 24 bytes.
  4. The source files have "concrete" with 16 bytes.
  5. Also in the source file function.cpp, the call to new in the object files is at line 38, and it's at line 35 in the source files.

May be that's the reason we're not able to reproduce with the source files?  If so, CAN YOU PLEASE REATTACH the source files to this issue which you used for generating the object files (main.o library.a) that you attached later? Appreciate your help.

_Kittur

0 Kudos
Sawin__Matthew
1,466 Views

I've attached the source files and Makefile. You should be able to run make and ./main to reproduce. Thanks!

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Great, thanks Mathew. I am now able to reproduce the issue with the new sources you attached! I've passed it on to the developer(s) and will keep you updated if I need any further info - appreciate much.

_Kittur

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Hi Mathew,

Just letting you know that this issue is a bug in the compiler and a fix is being implemented and should be in  the next update release. I'll let you know as soon as the release with the fix is out. Unfortunately, there's no workaround for this issue other than for you avoiding the anonymous union in your code. Again,.thanks for catching this bug and for the patience through this.

_Kittur 

0 Kudos
Sawin__Matthew
1,466 Views

Thanks for the update. Unfortunately there is such an anonymous union in the <algorithm> header for gcc 4.8 and higher so the compiler is effectively incompatible with recent versions of gcc. gcc 4.4 does not appear to have any anonymous unions so the only way to avoid this bug when compiling against gcc is to use older versions.

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Hi Mathew,
Thanks for your feedback. Yes, this indeed is an issue with the compiler for this particular scenario using -ipo and you'll have to wait for the release with the fix out. With ipo and the <algorithm> standard header and your current version of gcc there's no workaround at present. The only option I can think of may be is to not use ipo till then? I've escalated this with a high priority with the developers and will update you as soon as the release with the fix it out. Appreciate your patience till then.

_Kittur 

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Hi Mathew,
Thanks for your feedback. Yes, this indeed is an issue with the compiler for this particular scenario using -ipo and you'll have to wait for the release with the fix out. With ipo and the <algorithm> standard header and your current version of gcc there's no workaround at present. The only option I can think of may be is to not use ipo till then? I've escalated this with a high priority with the developers and will update you as soon as the release with the fix it out. Appreciate your patience till then.

_Kittur 

0 Kudos
Sawin__Matthew
1,466 Views

Any updates on when a fix for this issue will be realeased? Thanks.

0 Kudos
Kittur_G_Intel
Employee
1,466 Views

Hi Mathew,
Yes, the issue has been fixed in the next major release (16.0). BTW, the 16.0 beta release was just launched as well. You can get all related information on how to participate in  the beta as well at: https://software.intel.com/en-us/forums/topic/549502 

Could you please confirm with the above beta release if the issue is fixed?  Appreciate much, for your patience through this.
_Kittur

0 Kudos
Kittur_G_Intel
Employee
1,298 Views

Hi Mathew,
Just letting you know that this issue is fixed in the latest 16 beta version that you can test it out with, thanks.
_Kittur 

0 Kudos
Reply