Quantcast
Channel: Intel® C++ Compiler
Viewing all articles
Browse latest Browse all 1616

Pure Virtual Function Incorrectly Inlined by IPO w/ Anonymous Union

$
0
0

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

Viewing all articles
Browse latest Browse all 1616

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>