Ошибка выравнивания с указателем C на класс C ++, содержащий выровненную структуру C - PullRequest
2 голосов
/ 23 января 2020

У меня есть следующий код:

#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;
}

Я скомпилировал его с внутренней цепочкой инструментов моей рабочей среды, которая использует g cc 4.3.2 + Sanitizer. Сгенерированная командная строка выглядит следующим образом:

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

При ее запуске я получаю следующий вывод:

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).

Причина утечек памяти очевидна.

Но я Я хочу понять и исправить проблемы с неправильным адресом .

typedef void* Match_t здесь, потому что в моей рабочей среде я могу экспортировать только чистые C API. Так что я нашел обходной путь для экспорта функций, работающих с классами C ++.

У меня также нет выбора для версии компилятора g cc: - (

1 Ответ

0 голосов
/ 23 января 2020

G CC 4.7.3 (самая ранняя версия g cc с работающей в данный момент поддержкой исполнения на Годболте) имеет (https://godbolt.org/z/Ndvkkf):

  • alignof(MatcherEQ) = 128

  • alignof(max_align_t) = 16

(с использованием оператора C ++ 11 alignof и без указания конкретной платформы).

Я не могу найти какую-либо подходящую формулировку относительно выравнивания, кроме "надлежащим образом выровненной", в стандарте C ++ 2003. В C ++ 11 (которая не была завершена, когда был выпущен ваш g cc 4.3.2), у нас есть такая формулировка (выделение моя):

[basic.align]/3

расширенное выравнивание представлено выравниванием, большим alignof(std::max_align_t). Определяется реализацией, поддерживаются ли какие-либо расширенные выравнивания, и контексты, в которых они поддерживаются (7.6.2). Тип, имеющий требование расширенного выравнивания, является тип с чрезмерным выравниванием, [ Примечание: каждый тип с выравниванием является или содержит тип класса, к которому применяется расширенное выравнивание (возможно, с помощью элемента данных, не относящегося к состоянию c) .— конец примечания ]

Хотя это не является окончательным для вашего случая (поскольку C ++ 11 не применяется к g cc 4.3.2), можно с уверенностью предположить, что g cc просто не поддерживает over-align типы, по крайней мере, для случая динамического распределения c (обратите внимание, что для выделения стека проблем не возникает).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...