2011-01-26 9 views
10

Pracowałem nad moim programem i postanowiłem włączyć pewne optymalizacje, używając g++ -O3. Nagle mój program zaczął się kruszyć. Upolowałem problematyczny kod i zminimalizowałem program do czegoś, co nadal się kruszy (tylko przy zastosowaniu optymalizacji poziomu 3). Miałem nadzieję, że ktoś mógłby wziąć szybki zerknąć na kod (próbowałem minimalizując go tyle, ile to możliwe):Włączenie optymalizacji g ++ powoduje segfault - nie rozumiem

// src/main.cpp 
#include "rt/lights/point.hpp" 
int main(int argc, char **argv) 
{ 
    rt::Light *light = new rt::light::Point(alg::vector(.0f, 5.0f, 5.0f), rt::Color(1.0f), .5f); 
    return 0; 
} 


// include/rt/lights/point.hpp 
#ifndef RT_LIGHT_POINT_HPP_ 
#define RT_LIGHT_POINT_HPP_ 

#include "rt/accelerator.hpp" 
#include "rt/color.hpp" 
#include "rt/intersection.hpp" 
#include "rt/light.hpp" // abstract 

namespace rt { 
namespace light { 

class Point : public Light 
{ 
    public: 
    Point(alg::vector pos, Color color, float intensity) : Light(intensity * color), pos(pos) {} 

    Color get_contrib(const Intersection&, const Accelerator&, const alg::vector& toViewer) const; 

    private: 
    alg::vector pos; 
}; 

} // namespace light 
} // namespace rt 

#endif 


// include/rt/light.hpp 
#ifndef RT_LIGHT_HPP_ 
#define RT_LIGHT_HPP_ 

#include "algebra/vector.hpp" 
#include "rt/color.hpp" 

namespace rt { 

class Intersection; 
class Accelerator; 

class Light 
{ 
    public: 
    Light(Color intensity) : intensity(intensity) {} 

    virtual Color get_contrib(const Intersection&, const Accelerator&, const alg::vector& toViewer) const = 0; 

    Color get_intensity() const {return intensity;} 

    protected: 
    Color intensity; 
}; 

} // namespace rt 

#endif 

chciałbym pewne wyobrażenie o tym, dlaczego ten kod zwraca błąd tylko w przypadku korzystania z optymalizacji i jak go zatrzymać od tego. Dzięki!

$ find src/ -name "*.cpp" | xargs g++ -I include/ -O3 
$ ./a.out 
Segmentation fault 

Edit: Na życzenie, konstruktorzy dla alg :: vector

 
struct vector 
{ 
    float x, y, z; 
    vector() : x(.0f), y(.0f), z(.0f) {} 
    explicit vector(float f) : x(f), y(f), z(f) {} 
    vector(float x, float y, float z) : x(x), y(y), z(z) {} 
    // ... 

Edit2: Dodawanie wyjście gdb przy kompilacji z -g

 
(gdb) file a.out 
Reading symbols from /home/rob/devel/gbug/a.out...done. 
(gdb) run 
Starting program: /home/rob/devel/gbug/a.out 

Program received signal SIGSEGV, Segmentation fault. 
rt::light::Point::Point (this=0x804b008, pos=..., color=..., intensity=0.5) 
    at src/rt/lights/point.cpp:13 
13 Point::Point(alg::vector pos, Color color, float intensity) : Light(intensity * color), pos(pos) 
(gdb) bt 
#0 rt::light::Point::Point (this=0x804b008, pos=..., color=..., intensity=0.5) 
    at src/rt/lights/point.cpp:13 
#1 0x08048898 in main (argc=1, argv=0xbffff3e4) at src/main.cpp:5 

Edit3: Źródła do rt :: Kolor .

 
// include/rt/color.hpp 
#ifndef RT_COLOR_HPP_ 
#define RT_COLOR_HPP_ 

#include "algebra/vector.hpp" 

namespace rt { 

/******************************************************************************* 
* CLASS DEFINITION 
*/ 

struct Color 
{ 
    float r, g, b; 
    Color() : r(.0f), g(.0f), b(.0f) {} 
    explicit Color(float f) : r(f), g(f), b(f) {} 
    Color(float r, float g, float b) : r(r), g(g), b(b) {} 

    Color& operator+= (const Color&); 
    Color& operator*= (const Color&); 
    Color& operator*= (float); 
}; 

/******************************************************************************* 
* MEMBER OPERATORS 
*/ 

inline Color& Color::operator+= (const Color& other) 
{ 
    r += other.r; 
    g += other.g; 
    b += other.b; 
    return *this; 
} 

inline Color& Color::operator*= (const Color& other) 
{ 
    r *= other.r; 
    g *= other.g; 
    b *= other.b; 
    return *this; 
} 

inline Color& Color::operator*= (float f) 
{ 
    r *= f; 
    g *= f; 
    b *= f; 
} 

/******************************************************************************* 
* ADDITIONAL OPERATORS 
*/ 

inline Color operator+ (Color lhs, const Color& rhs) 
{ 
    return lhs += rhs; 
} 

inline Color operator* (Color lhs, const Color& rhs) 
{ 
    return lhs *= rhs; 
} 

inline Color operator* (Color c, float f) 
{ 
    return c *= f; 
} 

inline Color operator* (float f, Color c) 
{ 
    return c *= f; 
} 

} // namespace rt 

#endif 
+1

Czy próbowałeś kompilacji z -g, jak również sprawdzić, czy w ogóle backtrace jest użyteczny? –

+0

Ciekawi mnie dlaczego nie kompiluje się z 'g ++ src/*. Cpp -Iinclude -O3'. W podejściu 'xargs' kompilator skompilowałby każdy plik do' a.out', więc zakładam, że wszystkie mają 'main()'. – chrisaycock

+1

czy możesz wysłać konstruktora kopiowania 'alg :: vector'? – Naveen

Odpowiedz

6

Obliczając intensity * color pośrednio operator nosi nazwę:

inline Color& Color::operator*= (float f) 
{ 
    r *= f; 
    g *= f; 
    b *= f; 
} 

utrzymuje na powrót odniesienie do Color, ale nie. Należy zwrócić odwołanie do *this, podobnie jak inni operatorzy zrobić:

return *this; 
+0

+1. Jak to nie jest błąd kompilatora? Czy brak wartości zwracanej jest ostrzeżeniem w gcc? – James

+1

@James: To ostrzeżenie zostanie włączone, jeśli podasz opcję '-Wall'. – sth

+2

Ah. Chyba jest tu lekcja, której można się nauczyć ... zawsze używaj -Wall. – James

2

Musisz zrozumieć, że to nie jest optymalizacja, która łamie twój kod, kod jest już uszkodzony. Nie mogę zobaczyć, co się dzieje po prostu patrząc na te fragmenty, ale widząc, że jesteś segfault na nowe oświadczenie, spróbuję i skierować moje wysiłki w kierunku sprawdzania parametrów wejściowych swoich nowych funkcji. Wśród wielu rzeczy, które zdarzają się podczas optymalizacji 03, kompilator będzie próbował wbudować wywołania funkcji, rozwinąć pętle i utworzyć nowe zmienne, a także pozbyć się ich w celu przyspieszenia wykonania. Pierwszym krokiem jest podwójne sprawdzenie, gdzie masz pętle i upewnij się, że robisz coś takiego, jak i < strlen (str), że instrukcja nie jest szalona i twierdzą, że parametry wejściowe, które nie powinny mieć wartości NULL, w rzeczywistości nie są NULL.

Mam nadzieję, że to pomoże.

1

Nie jestem pewien, czy to jest kwestia widzisz, ale jeśli masz klasę z funkcji wirtualnych, który jest używany polimorficznie, powinien mieć wirtualny destruktor:

class Light { 
    ... 
    virtual ~Light {} 
    ... 
}; 

Obecnie, jeśli będzie delete zmienna light w twoim głównym, ~Light destruktor zostanie wywołany (ponieważ zmienna ma typ Light*), zamiast poprawnej ~Point jeden. Wykonanie wirtualnego destruktora naprawia to.

+0

Dodałem wirtualny destruktor, na próżno ... Segfault dzieje się zanim obiekt zostanie ponownie zniszczony, dzieje się to na linii z 'new rt :: light :: Point'.Nic poza tym nie jest już wykonywane. – robrene

+0

@robrene: Podejrzewałem tak samo, ponieważ obiekt * nigdy nie został faktycznie zniszczony w przykładowym kodzie ... Ale i tak powinien to być krok we właściwym kierunku. – sth

2

Czas dowiedzieć się, jak debugować za pomocą gdb!

Przekompiluj cały kod źródłowy z -g:

find src/ -name "*.cpp" | xargs g++ -I include/ -O3 -g 

Następnie należy uruchomić gdb, załadować plik i wykonać go:

gdb 
file a.out 
run 

gdb zaprowadzi Cię do wiersza polecenia, gdy program uderza w segfault. W wierszu polecenia (gdb) wpisz "bt" i naciśnij enter. Da ci to ślad stosu. Pierwsza klatka stosu będzie linią kodu, która spowodowała błąd segmentacji.

Stamtąd, jeśli jest to oczywiste, popraw to, w przeciwnym razie dodaj wynik do pytania. Czasami gdb nie jest dobry w debugowaniu kodu, który znajduje się w konstruktorze, ale spróbuj go najpierw i zobacz, co mówi.

+0

Dodałem wyjście gdb do oryginalnego postu. Dzięki za udzielenie mi szybkiego przewodnika po debugowaniu! Nie jestem do końca pewien, w jaki sposób ten wynik pomaga mi, ponieważ już wiedziałem, gdzie się dzieje. Po prostu nie wiem dlaczego ... – robrene

0

Może zaistnieć pewne zamieszanie przy użyciu zmiennej członu pos i przekazanej zmiennej pos, spróbuj nazwać je różnymi nazwami zmiennych.

Point(alg::vector pos, Color color, float intensity) : Light(intensity * color), pos(pos) {}

+1

Nie powinno być żadnych nieporozumień. Argument ukrywa zmienną składową. Często zdarza się, że na liście inicjalizującej znajdują się rzeczy takie jak "pos (pos)". –

Powiązane problemy