Segfault при компиляции с g ++ с оптимизацией - PullRequest
0 голосов
/ 12 сентября 2018

У меня действительно странный сбой в моем коде (с g ++ версии 7.3):

При компиляции с -o0 все работает нормально. Но при компиляции с -O1 / O2 / O3 я получаю ошибку segfault. Работая в GDB, похоже, что сразу после возврата из функции по какой-то причине происходит вызов _unwind_resume, что приводит к ошибкам. Я не видел ни одного вызова _unwind_resume в том же месте в моем коде с кодом, скомпилированным с -O0.

Но есть еще:

  • Я попытался запустить его с помощью valgrind, чтобы узнать, получу ли я какую-либо полезную информацию. Он сообщает о «нераспознанной инструкции по адресу», но никаких проблем с памятью.

  • Я пытался использовать разные флаги оптимизации по отдельности, чтобы увидеть, есть ли конкретная оптимизация, которая вызывает это. Я использовал все оптимизации, перечисленные g ++ -Q -O1 -help = optimizer. Без падений. Я попытался использовать все соответствующие флаги -f вместе. По-прежнему без сбоев.

  • Я попытался скомпилировать clang ++ вместо g ++ с любым уровнем оптимизации. Опять же, работает нормально, без сбоев.

Я полагаю, что стек вызовов каким-то образом поврежден оптимизированным кодом в g ++, но я понятия не имею, почему или что с этим делать. Есть идеи как подойти?

Примечание: к сожалению, я не могу поделиться кодом, и он слишком большой для того, чтобы делиться им здесь в любом случае.

Редактировать: мне удалось уменьшить код, который вызывает ошибку. Вот репродуктор:

#include <iostream>
#include <vector>

using namespace std;

class Expr;

typedef std::vector<Expr*> ExprVec;


enum class Ops {
    Search
};

enum class ExprKind {
    Const,
    Function,
    Unknown
};

namespace Values {
class Value
{
public:
        virtual ~Value() {};
};

class String : public Value
{
public:
   String(const string& v): _val(v) {}
   String(const char* s): _val(s) {}

   ~String() {
   }

   static const string name;

private:
    string _val;
};

const string String::name = "String";

} // Values

class Expr
{
public:
   Expr() {}
   Expr(const ExprVec& args)
     : _args(args) {}

   virtual ~Expr() {
    for (auto arg: _args) {
        delete arg;
    }
   };

   virtual Values::Value* run() = 0;

protected:
   ExprVec _args;
};

template<class ValType>
class ConstExpr: public Expr
{
public:
    ConstExpr() {}
    ConstExpr(ValType* val)
       : _val(val) {}

    ~ConstExpr() {
        delete _val;
    }
    virtual Values::Value* run() {
        return _val;
    }


private:
   ValType* _val;
};

typedef ConstExpr<Values::String> StringExpr;

// This is a template for all expression nodes. Instantiate for each expression
template <ExprKind Kind, Ops Name, class RetVal, class Arg1>
class ExprT: public Expr
{
public:

    ExprT() {}

    ExprT(const ExprVec& args)
      : Expr(args) {}

    virtual Values::Value* run() {
        Arg1* arg1= dynamic_cast<Arg1*>(_args[0]->run());
        return run(arg1);
    }

    RetVal* run(Arg1* arg1);
};

typedef ExprT<ExprKind::Function, Ops::Search, Values::String, Values::String> Search;

template<>
Values::String* Search::run(Values::String* arg1)
{
}

int main()
{
    Values::String* str = new Values::String("blahbla");
    Expr* se = new StringExpr(str);
    ExprVec args({se});
    Expr* search = new Search(args);
    search->run();
    cout<<"Done\n";

    return 0;
}

Edit2: Я только что понял, что это не настоящий репродуктор. Search :: run здесь не возвращает значения, а в исходном коде возвращает значение. Я постараюсь создать лучший репродуктор.

Обновление: Я наконец-то понял это ... приведенный выше пример не сможет воспроизвести конкретную ошибку, потому что для этого требуются как минимум два исходных файла и один заголовочный файл. Проблема заключалась в том, что у меня была некоторая функция с неспециализированными определениями шаблонов в заголовочном файле и полностью специализированными экземплярами этих функций в одном из исходных файлов.

Я не объявлял специализации во включаемом файле, который был источником проблемы ... Я понял это только когда попытался скомпилировать его в Windows (вместо Linux), и получил ошибки компоновки из-за нескольких экземпляры тех же функций.

...