1

I'm using UBSAN and am getting the following error. Note that I'm compiling with clang 6.0.1 with -fsanitize=undefined. I've read a number of background questions on SO and still can't solve my particular issue. Here are the background questions for reference:

Here are some things to note about class C:

  • the object of type C is created using new (C* o = new C();)
  • type C has a member of type A that has 64 byte alignment. I verified this using alignof.
  • C is declared using class alignas(64) C -- but that doesn't solve my problem

My current hypothesis is that I need to use the C++11 equivalent of the C++17 std::aligned_alloc to create the object using aligned storage. But, I'm not sure how to best do this or if it will actually solve my problem. I would prefer to solve the problem once in the definition of class C as opposed to every time I create a C, if possible. What is the recommended approach to solve this issue to remove the UBSAN error?

Kulluk007
  • 902
  • 2
  • 10
  • 24
  • Sounds like you're on the right track, extended alignment is generally implementation-defined and may require some hand-holding. Even C++17's extended alignment support is ultimately implementation defined, and you implementation may or may not call `aligned_alloc` for 64. (What's new in C++17 is that your implementation *may* now call `aligned_alloc`.) – Kerrek SB Nov 26 '18 at 16:23

1 Answers1

1

If your class already has a member that requires 64 Byte alignment, then the class will already also have 64 Byte alignment out of necessity. So adding an explicit alignas(64) is not really gonna change anything.

The basic problem here is that allocation functions (in C++11) are only required to return memory aligned to fundamental alignment. C++11 left it implementation-defined whether over-aligned types are supported by new or not [expr.new]/1. C++17 introduced new-extended alignment and additional allocation functions to deal with that (if and which new-extended alignments are supported, however, is still implementation-defined).

If you can switch to a compiler that supports C++17, chances are that your code will just work. Otherwise you will probably have to either use some implementation-specific function to allocate aligned memory or just roll your own solution, e.g., based on std::align and placement new (which would work in C++11 too)…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • Thanks. A couple questions: 1) I'm using clang 6, so I can specify a different standard `-std=c++17`. Are you saying that may just work without changing the code? – Kulluk007 Nov 26 '18 at 21:16
  • 2) I typically create aligned dynamically allocated memory in c++11 using posix_memalign. Would that, plus placement-new, be the recommended c++11 approach to solve this? – Kulluk007 Nov 26 '18 at 21:24
  • @Kulluk007 I didn't test it, so I'm not sure; but it could be worth a try. If it doesn't work, you can resort to just using `posix_memalign` if a non-portable solution is sufficient for your needs. You could overload the operator new/delete functions for this particular type to use `posix_memalign` under the hood so that everything works just as it normally would and you don't have to orchestrate the correct allocation manually every time you instantiate such an object via new. That should also allow `unique_ptr` etc. to work just as usual… – Michael Kenzel Nov 26 '18 at 22:03
  • Thanks. I was able to get the UBSAN errors to go away by switching to C++14 and using posix_memalign and placement-new. I wasn't able to upgrade to C++17 yet because of some macOS libs I'm currently relying on. However, I'm getting a possibly innocuous warning from ASAN now about mismatch between malloc and delete because I'm malloc'ing the buffer and then using placement new, but calling delete on the created object. I'm not calling free on the buffer because delete should also delete the malloced buffer (right?). Is my understanding correct that the ASAN alloc-dealloc-mismatch is innocuous? – Kulluk007 Nov 27 '18 at 13:46
  • 1
    @Kulluk007 No, your understanding is not correct. You cannot use `delete` to free memory that was allocated with `malloc()`. You have to use `free()`. – Michael Kenzel Nov 27 '18 at 13:56
  • Ok thanks. The issue is that I need to call the destructor of the object that is created using placement new (it does a variety of other cleanups). When I tried to call BOTH free of the raw buffer that is used as well as delete on the object, I get `malloc: *** error for object 0x7f996ad09300: pointer being freed was not allocated` I tried putting the free both before and after the delete. When I remove the delete call the error goes away -- but of course I don't get the other benefits of my destructor. What's the recommended approch here? – Kulluk007 Nov 27 '18 at 16:12
  • @Kulluk007 When you construct an object via placement new, you have to call the destructor manually: `myobj.~MyClass();` – Michael Kenzel Nov 27 '18 at 16:50