2012-04-04 3 views
1

Я пытался заставить этот бит кода работать без успеха. GDB говорит мне, что есть где-то в выдаёт ошибку сегментации недействительного Compiler :: GenerateCode_ToFile (символ * имя_файла) функция, и я вручную проследили проблему где-то в строке:Crash/Segfault при вызове виртуального члена подкласса

std::string tempfile = this->code->CodeGen(temp, AST_TYPE_UNDEF, symtab, 0); 

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

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

void Compiler::GenerateCode_ToFile(char* filename){ 

char directory[MAX_PATH]; //Actually represents the full path. 
strcpy(directory, this->cwd.c_str()); 
strcat(directory, filename); 

if(this->isVerboseMode) 
    std::cout << "Source Output: " << directory << '\n'; 

std::fstream file(directory, std::ios::out); 

int* temp = new int; 
Symtable* symtab = new Symtable; 
file << emit_core_code(); 
file << "\n\n"; 
std::string tempfile = this->code->CodeGen(temp, AST_TYPE_UNDEF, symtab, 0); 
file.close(); 
} 

Это определение класса, представленного this-> кода.

/// CollectionExprAST - Expression class for multiple branches. 
class CollectionExprAST : public ExprAST { 
    std::vector<ExprAST*>* Code; 
public: 
    CollectionExprAST(std::vector<ExprAST*>* code) : Code(code) {} 
    virtual std::string CodeGen(int* GeneratedCodeOpType,int WantOpType,Symtable* symtab, int depth); 
    int GetType(void){return AST_TYPE_COLLECTION;}; 
    void* GetCollection(void){return this->Code;}; 
    void DebugPrint(int level); 
}; 

Это его суперкласс:

/// ExprAST - Base class for all expression nodes. 
class ExprAST { 
public: 
    virtual ~ExprAST() {} 
    virtual std::string CodeGen(int* GeneratedCodeOpType,int WantOpType,Symtable* symtab, int depth) {return std::string("");}; 
    virtual void DebugPrint(int level){return;}; 
    virtual int GetType(void){return AST_TYPE_UNDEF;}; 
    virtual void* GetCollection(void){return NULL;}; 
}; 

и, наконец, это виртуальная функция, которая вызывается (хотя, кажется, врезаться перед его запуска):

std::string CollectionExprAST::CodeGen(int* GeneratedCodeOpType,int WantOpType,Symtable* symtab, int depth) 
{ 
Sleep(3000); 
std::string ret; 
int j=0; 
for(;j<this->Code->size();j++){ 
    int temp; 
    int i=0; 
    for(;i<depth;i++) 
     ret += "\t"; 
    ret += (*this->Code)[j]->CodeGen(&temp,WantOpType,symtab, depth+1); 
    ret += '\n'; 
} 
return ret; 
} 

I знайте, что он сработает, прежде чем он запустится, потому что Sleep() никогда не запускается.

Может ли кто-нибудь увидеть ошибку, вызывающую этот таинственный segfault?

Заранее спасибо.

+1

Слишком много кода. Вам необходимо создать [минимальный тестовый сценарий] (http://sscce.org), прежде чем размещать здесь свой код. Но вы уверены, что, например, 'this-> code' является допустимым указателем? –

+0

@OliCharlesworth Я относительно уверен, что это действительный указатель, так как я называю других виртуальных членов без проблем. –

+0

@ 64bit_twitchyliquid: вам нужно построить минимальный тестовый пример, прежде чем кто-нибудь здесь сможет вам помочь. –

ответ

1

Причина в том, что code не выделяется и не повреждается.

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

+0

миллисекунд раньше, вызывается другая виртуальная функция (DebugPrint()), и она работает правильно. Вы уверены, что код является проблемой? –

+0

делает DebugPrint() доступ к любым полям объекта? Если это не так, он вообще не запускается на объекте. –

+0

Да. Он в значительной степени использует их все. –

1

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

Есть и другие проблемы, хотя и не связанные с вашей катастрофой.

Во-первых, вы никогда не удаляете symtab или temp в GenerateCode_ToFile. Это утечка памяти. В этом отношении, почему в мире вы динамически выделяете int? Просто объявите int в стеке и передайте его адрес функции CodeGen. То же самое касается symtab, если это возможно.

int i = 10; 
SomeFuncThatTakesAPointer(&i); 

На самом деле, присмотревшись, вы даже не использовать параметр int* в функции и она нигде не сохраняется, так просто избавиться от него полностью.

Далее ...

std::vector<ExprAST*>* Code; 

Указатели векторов и векторов, которые хранят указатели почти всегда ошибочны. Вы не позволяете вектору манипулировать динамическим распределением памяти и освобождением от вас.Вы можете просто использовать массив в этот момент (хорошо, массив не растет для вас, если вы назначаете что-то за его пределами, но все же, плохая практика).

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

Когда вы храните указатели в векторе, вы еще раз предотвратите освобождение вектора от его сохраненных объектов. Он будет автоматически хранить указатели и вызвать на них delete, но это не освободит то, что указывал оригинальный указатель.

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

Смежные вопросы