2

I have the following code:

#include <iostream>
#include <stdint.h>
#include <stdio.h>

// Structure from 3rd party that cannot be modified
typedef struct  {
   uint32_t flags;
   uint32_t len;
   uint8_t padding[120];
} mystruct_t __attribute__ ((aligned(128)));

// Classes used internally
class Matcher {
};

class MatcherEQ : public Matcher {
  mystruct_t _bson;
};

Matcher* factory() {
  return new MatcherEQ();
}

// Structure used for C/C++ interface
typedef void* Match_t;

// Pure C API
extern "C" {
void CreateMatch(Match_t *pm) {
  *pm = NULL;
  Matcher *b = factory();
  *pm = (Match_t)b;
}
}

int main(void) {

  // C style code
  puts("C\n");
  Match_t m;

  CreateMatch(&m);

  // C++ code
  std::cout << "C++" << std::endl;
  Matcher *pm = factory();

  return 0;
}

I compile it with the internal toolchain of my work environment that uses gcc 4.3.2 + Sanitizer. The generated command line looks like:

g++ -fsanitize=undefined -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wno-unused-local-typedefs -Wno-deprecated -Wformat=2 -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++98 -DDISABLE_MEMORY_ALLOCATORS=1 -march=k8 -pipe -fPIC -fno-strict-aliasing -Wall -Wpointer-arith -Wshadow -Wcast-align -Wimplicit -fno-tree-sra -g -Wno-write-strings -Wno-cast-qual -g3 -O0 -D__UNIX64__ -D__64BIT__ -D__LINUX64__ -D_LP64 -DSLES_10 alignissue.cpp

When running it I have the following output:

C

../Sources/Tests/C/alignissue.cpp:48: runtime error: store to misaligned address 0x613000000040 for type 'struct MatcherEQ', which requires 128 byte alignment
0x613000000040: note: pointer points here
 01 00 00 62  be be be be be be be be  be be be be be be be be  be be be be be be be be  be be be be
              ^ 
../Sources/Tests/C/alignissue.cpp:41:7: runtime error: member access within misaligned address 0x613000000040 for type 'struct MatcherEQ', which requires 128 byte alignment
0x613000000040: note: pointer points here
 01 00 00 62  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00
              ^ 
../Sources/Tests/C/alignissue.cpp:41:7: runtime error: member access within misaligned address 0x613000000040 for type 'struct MatcherEQ', which requires 128 byte alignment
0x613000000040: note: pointer points here
 01 00 00 62  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  d8 c3 12 a3
              ^ 
C++

=================================================================
==21777==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 384 byte(s) in 1 object(s) allocated from:
    #0 0x7f4aa347500f in operator new(unsigned long) (../../libasan.so+0x10c00f)
    #1 0x403d05 in factory() ../Sources/Tests/C/alignissue.cpp:48
    #2 0x40402e in main ../Sources/Tests/C/alignissue.cpp:75
    #3 0x7f4aa19f5c35 in __libc_start_main (/lib64/libc.so.6+0x1ec35)

Direct leak of 384 byte(s) in 1 object(s) allocated from:
    #0 0x7f4aa347500f in operator new(unsigned long) (../../libasan.so+0x10c00f)
    #1 0x403d05 in factory() ../Sources/Tests/C/alignissue.cpp:48
    #2 0x403e31 in CreateMatch ../Sources/Tests/C/alignissue.cpp:60
    #3 0x403f17 in main ../Sources/Tests/C/alignissue.cpp:71
    #4 0x7f4aa19f5c35 in __libc_start_main (/lib64/libc.so.6+0x1ec35)

SUMMARY: AddressSanitizer: 768 byte(s) leaked in 2 allocation(s).

The cause of memory leaks are obvious.

But I want to understand and fix the misaligned address issues.

The typedef void* Match_t is here because in my work environment I can export only pure C APIs. So it's a workaround that I found to export functions working on C++ classes.

I have as well no choice on the gcc compiler version :-(

user2655800
  • 141
  • 10
  • Hm, on the earliest gcc version on godbolt that doesn't have [this](https://stackoverflow.com/questions/6329887/compiling-problems-cannot-find-crt1-o) error with execution, I get this: https://godbolt.org/z/zJRjEs – Max Langhof Jan 23 '20 at 10:48
  • 1
    The alignment attribute will probably only be honoured by objects on the stack. A much more recent version of gcc, with C++17 new / delete (heap) storage, should honour the `alignas` keyword. – Brett Hale Jan 23 '20 at 10:54
  • Please [edit] your question and add details how exactly you compile, link and run your program. I just tried it with the default g++ 8.3.0 on my Ubuntu system and cannot reproduce the problem. I used `-fsanitize=address` and `-lasan` as mentioned in https://stackoverflow.com/questions/37970758/how-to-use-addresssanitizer-with-gcc – Bodo Jan 23 '20 at 11:03
  • I tried same code with `-fsanitize=address` and i didn't get any error. but with `-fsanitize=undefined` there is a similar error. update question with details – K_peanutButter Jan 23 '20 at 12:06
  • @Bodo Command line added. As you can see I am stuck with gcc 4.3.2 and C++98 – user2655800 Jan 23 '20 at 13:47
  • When I use your compile command with g++ 8.3.0, I get several warnings. These may be relevant: `alignment.cpp: In function ‘Matcher* factory()’:` `alignment.cpp:21:24: warning: ‘new’ of type ‘MatcherEQ’ with extended alignment 128 [-Waligned-new=] return new MatcherEQ();` `alignment.cpp:21:24: note: uses ‘void* operator new(std::size_t)’, which does not have an alignment parameter` Apparently the compiler knows that the `new` operator does not observe the stricter alignment for your structure. I don't know if it is possible to fix the problem with your compiler version. – Bodo Jan 23 '20 at 17:32
  • Do you know where the alignment of `mystruct_t` is required? I guess it is somewhere in the 3rd party code. Can you wrap the interface to the 3rd party code in a way that you allocate an aligned structure on the stack and `memcpy` the data between an aligned structure for the 3rd party interface and an unaligned structure for your own code? – Bodo Jan 23 '20 at 17:40
  • @Bodo 128bits alignment for `mystruct_t` is required for the numerous optimizations inside the 3rd party code. I will implement your solution of stack allocation + `memcpy`, if I don't manage to implement an over-aligned new operator. – user2655800 Jan 24 '20 at 09:49

1 Answers1

0

GCC 4.7.3 (the earliest version of gcc with currently working execution support on godbolt) has (https://godbolt.org/z/Ndvkkf):

  • alignof(MatcherEQ) = 128

  • alignof(max_align_t) = 16

(using the C++11 alignof operator and no particular platform specified).

I cannot find any pertinent wording regarding alignment other than "suitably aligned" anywhere in the C++2003 standard. In C++11 (which was not completed when your gcc 4.3.2 was released), we have this wording (emphasis mine):

[basic.align]/3

An extended alignment is represented by an alignment greater than alignof(std::max_align_t). It is implementation-defined whether any extended alignments are supported and the contexts in which they are supported (7.6.2). A type having an extended alignment requirement is an over-aligned type. [Note: every over-aligned type is or contains a class type to which extended alignment applies (possibly through a non-static data member).— end note]

While this is inconclusive for your case (because C++11 does not apply to gcc 4.3.2), it's safe to assume that gcc simply does not support over-aligned types, at least for the case of dynamic allocation (note that there appears to be no problem for stack allocation).

Community
  • 1
  • 1
Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • Thanks! So with C++98, it seems that my only solution is to implement a heap allocater that support over-alignment... if possible. – user2655800 Jan 24 '20 at 09:42