Повреждение памяти из-за несоответствия #define в заголовке

У меня 3 файла
В .h у меня есть #define ENABLE_STR, который оборачивает std :: string str,
Я включаю этот макрос только при определении класса A, но когда я использую A, он пропускается.

Это ситуация, когда a.cpp считает, что есть str член но main.cpp не знает об этом. И когда программа запускается int i перезаписывается string str, Кажется, что ни AddressSanitizer, ни Valgind не определяют это как недопустимый доступ к памяти.

// a.h
#pragma once
#include <string>
class A
{
public:
A();
std::string& get();
#ifdef ENABLE_STR
std::string str;
#endif
int i;
};

// a.cpp
#define ENABLE_STR
#include <iostream>
#include "a.h"
A::A():i(0){ }

std::string& A::get()
{
std::cin >> str;
return str;
}

//main.cpp
#include <iostream>
#include "a.h"
int main()
{
A a;
std::cout << a.get()  << "\n\n i:" << a.i << std::endl;
}
  • В идеале я бы предположил, что компилятор / компоновщик пометит это как ошибку, но это не так.
  • Почему адрес sanitizer / valgrind не может обнаружить это, так как это похоже на перезапись памяти, которой он не владеет.
  • Если не использовать такие макросы в заголовках, как это можно обнаружить?

0

Решение

В идеале я бы предположил, что компилятор / компоновщик пометит это как ошибку, но это не так.

Вы предоставляете компилятору разные определения классов для одного и того же класса для разных единиц перевода. Это неопределенное поведение, поэтому нет компилятора имеет диагностировать это. Как упомянуто в комментариях, разработчики компилятора имеют другие заботы, чем пользователь компилятора, путающий их определения таким способом.

На техническом уровне каждый модуль перевода генерирует объектный файл. Объектные файлы связаны между собой компоновщиком. Но объектные файлы ничего не знают о классах, только о функциях. Таким образом, он не имеет явных знаний о размерах объектов или смещениях элементов.

Можно ли сгенерировать «комментарии компилятора» в объектных файлах, чтобы обнаружить это? Или это может быть частью отладочных символов? Да, но это, вероятно, приведет к значительному увеличению и увеличению времени компиляции. Кроме того, не требуется, чтобы ваш двоичный файл библиотеки имел что-либо подобное, так что в этом случае это не поможет. Так что это будет ненадежная помощь в редком случае, когда пользователь все испортит, со значительными недостатками.

Почему адрес sanitizer / valgrind не может обнаружить это, так как это похоже на перезапись памяти, которой он не владеет.

Я не знаю достаточно о внутренней работе Вальгринда, чтобы дать здесь хороший ответ, но, вероятно, str доступ к этому get предполагает быть где i на самом деле внутри a в main не кажется сразу подозрительным к Вальгринду, потому что начало str все еще находится в памяти, выделенной для A, Если вы только get один символ, небольшая строковая оптимизация также может вызвать main никогда не получить доступ A за пределами тех первых нескольких байтов, зарезервированных для int,

Если не использовать такие макросы в заголовках, как это можно обнаружить?

Это ужасная идея использовать макросы таким образом — именно потому, что эти проблемы почти невозможно обнаружить. Вы сами упомянули о некоторых инструментах, которые могут быстро отлавливать «зловредное» неопределенное поведение (например, std :: vector, пытающийся управлять памятью после перезаписи его структуры управления), и вы можете настроить свою операционную систему и компилятор так, чтобы инструмент вашей программы был более строгим для получить уведомление (например, -fstack-protector-all на gcc, /Gs а также /RTCs на MSVC, эти функции безопасности на новой Windows и так далее) когда делает что-то сомнительное.

Тем не менее, это все еще неопределенное поведение мы говорим о том, что не существует гарантированного способа найти проблему, в основном потому, что «все работает, как ожидается, когда вы пытаетесь выявить проблемы», все еще находится в сфере «все может произойти». Или, другими словами, эти инструменты могут просто не иметь симптомов, обнаруживаемых этими инструментами, даже если ваша программа все еще делает некоторые ошибки.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]