Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Ian_Mallett1
Beginner
284 Views

Alignment in x86 is Broken for Inheritance

Here is a simple program demonstrating the problem. Both "static_assert"s should pass, but only the first does.

//__declspec(align(16)) class Vec3 {}; //For testing purposes on Windows
//class Vec3 {} __attribute__((__aligned__(16))); //For testing purposes on *nix

class Base { public:
    Vec3 v;
};
class Child : public Base {};

static_assert(alignof( Base)>=16,"Check 1");
static_assert(alignof(Child)>=16,"Check 2");
0 Kudos
13 Replies
Kittur_G_Intel
Employee
284 Views

Hi Ian,
I tried your test case and it does pass. I tried with the 16.0.0 and the latest 16.0.1 releases as well:

============================
$ icpc -std=c++14 main.cpp

% cat main.cpp
 

/__declspec(align(16)) class Vec3 {}; //For testing purposes on Windows
class Vec3 {} __attribute__((__aligned__(16))); //For testing purposes on *nix

class Base { public:

    Vec3 v;
};
class Child : public Base {};
static_assert(alignof(Base)>16,"Check 1");
static_assert(alignof(Child)>16,"Check 2");

$ icpc -std=c++14 main.cpp
$
$

$ cat main.cpp

//__declspec(align(16)) class Vec3 {}; //For testing purposes on Windows
class Vec3 {} __attribute__((__aligned__(16))); //For testing purposes on *nix

class Base { public:

    Vec3 v;
};
class Child : public Base {};
static_assert(alignof(Base)>16,"Check 1");
static_assert(alignof(Child)>16,"Check 2");

$ icpc -std=c++14 main.cpp
main.cpp(11): error: static assertion failed with "Check 1"

  static_assert(alignof(Base)>16,"Check 1");
  ^
main.cpp(12): error: static assertion failed with "Check 2"

static_assert(alignof(Child)>16,"Check 2");
  ^
compilation aborted for main.cpp (code 2)
==================================================

If you think otherwise, can you attach a preprocessed file (.i file generated when you use -P option) and the version of the compiler you're using (icpc -V would output), thx.,
_Kittur

Ian_Mallett1
Beginner
284 Views

The main reason you haven't been able to reproduce the problem is that you used ">" instead of ">=" in the checks.

I wasn't able to easily output the preprocessed file or version. However, the compiler was updated recently; it should be version 2016.1.146.

Kittur_G_Intel
Employee
284 Views

Yes, you're right Ian. Typo on my part and when corrected, I could reproduce. I'll file this issue with the product team and will keep you updated accordingly. Appreciate your patience till then, thanks.

_Kittur

Ian_Mallett1
Beginner
284 Views

Thanks for the quick attention. I highly anticipate a patch.
Best,
Ian

Kittur_G_Intel
Employee
284 Views

Sure Ian, I've passed your feedback to the team and will keep you updated, thanks

_Kittur

Kittur_G_Intel
Employee
284 Views

Hi Ian,
BTW, I was trying the same snippet with g++ (different versions) and it failed to assert as well. Did you try g++?  

Also, since I've filed this issue it'll only be addressed in the product release as we don't provide patches per-se, just letting you know. I'll keep you updated as soon as I hear feedback on the issue filed with  the team, thanks.

_Kittur

Ian_Mallett1
Beginner
284 Views

Yes. I tried gcc 5.2.0, 5.1.0, 4.9.2, and also Clang 3.7, 3.6, 3.5.1. I can't reproduce the problem. Which versions did you try?

In any case, the problem should be reasonably clear, no? How can a child class have weaker alignment than its parent?

284 Views

Interesting issue, I cannot reproduce the issue on windows and linux, with both v15.0 and v16.0 compilers, and also gcc...Means, all compilers I have (gcc, icc, MS compiler) can pass the test case in my environment...

Ian, I'll suggest you to run below commands and paste the raw results here:

$ gcc -v
$ icc -v
$ gcc temp.cpp -std=c++14 -c
$ icc temp.cpp -std=c++14 -c

Thanks,

Shenghong

 

Ian_Mallett1
Beginner
284 Views

The issue occurs with version 16 of the Intel compiler, but does not occur on GCC or Clang; that's the point.

I am currently developing on Windows 7 with Visual Studio 2015. (Therefore, gcc is not installed, so its version is irrelevant. The GCC tests mentioned above were, admittedly, on a different computer (their versions were provided).) Visual Studio encapsulates command line access, making accessing it directly difficult, but the project settings says it's 16.0. Note that nothing below 15 was ever installed on this computer.

---

I wanted to try to reproduce again the error with the example I gave, but somehow, it magically started working. However, I was able to reduce the problem down to an equivalent example (I managed to remove the inheritance, but it only exhibits the problem at runtime):

__declspec(align(16)) class Vec3 {};

class MyClass final {
	private:
		Vec3 _v;

	public:
		MyClass(Vec3 const& v=Vec3()) : _v(v) {}
		virtual ~MyClass() = default;
};

//Notice that both of these static asserts pass, and yet . . .
static_assert(alignof(Vec3)==16,"Implementation error!");
static_assert(alignof(MyClass)>=alignof(Vec3),"Implementation error!");

int main(int /*argc*/, char* /*argv*/[]) {
	MyClass* c1 = new MyClass();
	MyClass* c2 = new MyClass();

	//. . . set a breakpoint here.  Observe that one of "c1" and "c2" is 8-byte aligned, not 16.
	int dummy = 6;

	delete c1; delete c2;
	return 0;
}

For your convenience, I have also attached this as a complete example Visual Studio solution. You should be able to load it, set the breakpoint mentioned, and see the problem. On my machine on one run, "c1" is at "0x00539b58" while "c2" is at "0x00539b80". Notice that "c1" is 8-byte-aligned, not 16. Also note that the problem is specific to x86 builds. x86-64 builds work fine.

Ian_Mallett1
Beginner
284 Views

Here's an even simpler example (closer to the way I found this out) that will cause an actual crash (the destination of the store in the constructor is not aligned):

#include <intrin.h>

class MyClass final { public:
	__m128 _vec; //Note: recall that "__m128" is declared to be 16 byte aligned

	MyClass(__m128 const& vec) : _vec(vec) {}
	~MyClass() = default;
};

int main(int /*argc*/, char* /*argv*/[]) {
	MyClass* c1 = new MyClass(_mm_set1_ps(1.0f));
	MyClass* c2 = new MyClass(_mm_set1_ps(2.0f));
	delete c1; delete c2;
	return 0;
}

As before, the Visual Studio files have been attached.

jimdempseyatthecove
Black Belt
284 Views

While _vec is declared that you want it 16 byte aligned, you made no alignment declaration about MyClass.

You will have to provide your own operator new, if you intend to use new to obtain a new MyClass object that is aligned. Otherwise use _aligned_malloc or other aligned allocation function, then use placement new on the returned pointer.

Jim Dempsey

Ian_Mallett1
Beginner
284 Views

Jim,

Two things:

  1. I was under the impression that a structure's alignment is given as max(n,max(alignof(each member))), where "n" is some compiler option, typically 1. (But basically, the alignment is the maximum alignment of any of its elements.) A number of resources claim that this is the case. The most authoritative I found is this, which shows an example where this happens. I don't know what the standard itself says.

    This applies to my original problem; which unfortunately, as above, I can't reproduce anymore. I have no explanation as to why. However, I am certain I was using the Intel Compiler 16, and a compile-time error was produced. Note: Visual Studio's highlighter still marks the static assert as invalid, but it compiles fine now. Kittur, are you still able to reproduce the problem?
     
  2. You're right. Now that I think about it, I know already that the default operator new doesn't return aligned memory. I was implicitly assuming it would in my second two examples.

So . . . back to work for me. I'll keep this thread updated if I can reproduce the original problem again (or something else relevant turns up).

Thanks,
Ian

Kittur_G_Intel
Employee
284 Views

Hi Ian,
Thanks for the feedback and Jim's suggestion makes sense.  Also, Ian I have to take back my earlier confirmation as I am not able to reproduce the issue with all the latest versions of icc as well as gcc does work properly with the code snippet you'd provided earlier and the assertion doesn't get output since the condition is true and passes. Sorry about my earlier confirmation on reproducing (guess I'd the condition > still or so).  Yes, please update the thread if you can reproduce the original problem since we can't with all the versions of the compiler.
_Kittur

Reply