Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Visual Studio 2013 - Natychmiastowe powiadamianie o wystąpieniu wyjątku

Ostatnio zmodyfikowano 2015-02-02 15:33
Autor Wiadomość
RazzorFlame
Temat założony przez niniejszego użytkownika
Visual Studio 2013 - Natychmiastowe powiadamianie o wystąpieniu wyjątku
» 2015-02-01 18:44:28
Trochę to zagmatwany problem, dziś od jakoś 3 godzin (tak, 3 godzin i nie przesadzam) męcze się z bardzo dziwną dla mnie akcją. Może najpierw kod:
C/C++
void VideoDriver3D::draw( SceneNode * obj )
{
   
    XMFLOAT4X4 objWorld;
    xmset( objWorld, obj->getTransformationMatrix() );
   
    //Set world matrix to WVP
    XMFLOAT4X4 worldViewProjection;
    XMStoreFloat4x4( & worldViewProjection,
    XMLoadFloat4x4( & objWorld ) *( XMLoadFloat4x4( m_parentDevice->getCamera()->getView() ) ) *( XMLoadFloat4x4( m_parentDevice->getCamera()->getProjection() ) ) );
    //Set WVP to constant_buffer::PerObject
    XMMATRIX temp = XMMatrixTranspose( XMLoadFloat4x4( & worldViewProjection ) );
    fx::Shader::getInstance().setGlobalVariable( "WorldViewProjection", temp );
    temp = XMMatrixTranspose( XMLoadFloat4x4( & objWorld ) );
    fx::Shader::getInstance().setGlobalVariable( "World", temp );
   
   
    m_rasterizer.setState( obj->getRasterizer() );
    m_rasterizer.apply( this );
   
   
    Model * model = ModelManager::getInstance().getModel( obj->getModelPath() );
    if( !model ) return;
   
    m_deviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
   
    if( model->getSubsets().size() > 0 )
    for( UINT i = 0; i < model->getSubsets().size(); i++ )
    {
        simplyDraw( &( model->getSubsets()[ i ] ) );
    }
}

Ta funkcja po prostu wyświetla obiekt (SceneNode). Program wysypuje się (jak podaje Debugger) na linijce:
m_rasterizer.apply( this );
Tak więc sprawdziłem czy jest jakaś możliwość by używać tam błędnego wskaźnika (bo dostaje Access Violation) i takowej nie ma!
Oto kod:
C/C++
void Rasterizer::apply( VideoDriver3D * wnd )
{
    if( !wnd )
         return;
   
    if( m_dxActualState != NULL )
         wnd->getDeviceContext()->RSSetState( * m_dxActualState );
    else wnd->getDeviceContext()->RSSetState( m_solidNonefacingNoncounter );
   
}
Jak możecie zauważyć, sprawdzam tutaj czy wszystkie wskaźniki są poprawne.
Co ciekawe, kiedy sprawdziłem "coutami" do jakiego momentu dochodzi program to okazało się że leci nawet za podaną przez debugger linijkę.
Zauważyłem też, że gdy wykomentuję całą zawartość funkcji VideoDriver3D::draw(SceneNode*) to program zacina całkowicie komputer i musze go restartować, ten problem występuje tylko na moim komputerze (karta AMD Radeon HD 6300M) a na komputerze mojego brata (karta NVidia GeForce GTX 780) śmiga nieźle (chociaż też się wysypuje, jednak nie freezuje mu całego komputera).

Kiedy najechałem debuggerem na linijkę m_rasterizer.apply(this); i na "this" to pisało "0x00000000" czyli wskaźnik this był zerowy, jednak gdy linijkę wcześniej i linijkę później wypisywałem wartość this to dostawałem adres.
Wyglądało to jakoś tak:
C/C++
cout << "This = " << this << endl; // tutaj był jakis adres np. 0x00C4C010
m_rasterizer.apply( this ); // po najechaniu na "this" dostawalem 0x00000000
cout << "This = " << this << endl; // tutaj tez 0x00C4C010

Wszystko wskazuje na to, że dostałem wcześniej jakiś wyjątek (tak mi się przynajmniej wydaje).
Bardzo mnie irytuje ta sytuacja, bo debugger pokazuje na coś całkowicie bezsensownego.

Dodam też, że debugger pokazuje _memcpy jako funkcję która powoduje Access Violation, więc dlaczego pokazuje też na tą linijkę u góry?

Chciałbym, żeby Debugger wywalił mi aplikację przy pierwszym lepszym wyjątku. Jest jakaś możliwość by to zrobić?

Tutaj screen z Call Stack i Disassembly po zakomentowaniu tych dwóch linijek:
C/C++
m_rasterizer.setState( obj->getRasterizer() );
m_rasterizer.apply( this );
Call Stack
Call Stack
P-125844
DejaVu
» 2015-02-01 20:42:15
spróbuj przebudować projekt. poza tym w metodzie nie sprawdzasz czy wszystkie wskazniki sa rozne od nulla jak wywolujesz sznurek metod
P-125848
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2015-02-02 09:13:19
Kurczę, teraz już jestem pewny, że to jest wyjątek i nie występuje on nawet w funkcji VideoDriver3D::draw(SceneNode*).
Do mojego silnika napisałem Scenę tj. prosty menedżer obiektów na scenie. Gdy używam sceny program się wysypuje, jednak gdy wyświetlam obiekt (jak na razie mam 1 obiekt na scenie) bezpośrednio za pomocą VideoDriver3D to problem znika, wszystko wtedy działa pięknie.
Mój kod wcześniej:
C/C++
m_scene->drawSorted();
Tutaj kod metody drawSorted (argumenty funkcji są z góry ustalane na (-1, NULL) gdyby użytkownik chciał wyświetlić wszystkie obiekty a nie tylko parę):
C/C++
void Scene::drawSorted( int count, UINT * iTab )
{
    if( getParentWindow() )
    {
        if( m_voObjects.size() > 0 )
        {
            if( count == - 1 )
            {
                std::vector < UINT > sorted = privGetSortedObjectArray( m_voObjects );
               
                for( unsigned int i = 0; i < sorted.size(); i++ )
                     privDrawObject( i );
               
            }
            else
            {
                std::vector < SceneNode *> objTab;
                for( int x = 0; x < count; x++ )
                {
                    objTab.push_back( at( iTab[ x ] ) );
                }
                std::vector < UINT > sorted = privGetSortedObjectArray( objTab );
               
                for( unsigned int i = 0; i < sorted.size(); i++ )
                     privDrawObject( i );
               
            }
        }
    }
}
Jako, że wyświetlałem wszystkie obiekty na scenie interesuje nas to:
C/C++
if( count == - 1 )
{
    std::vector < UINT > sorted = privGetSortedObjectArray( m_voObjects );
   
    for( unsigned int i = 0; i < sorted.size(); i++ )
         privDrawObject( i );
   
}
No to jedziemy najpierw do privGetSortedObiectArray(vector<SceneNode*>&) która sortuje obiekty według odległości od kamery.
C/C++
std::vector < UINT > Scene::privGetSortedObjectArray( std::vector < SceneNode *> & vec )
{
    static std::vector < UINT > sorted;
    if( !m_bMustResort ) return sorted;
    else
    {
        m_bMustResort = true;
        if( vec.size() > 0 )
        {
           
            float maxLength = 0;
            UINT maxId = 0;
            Device * device = dynamic_cast < Device *>( getParentWindow() );
            if( !device )
                 return sorted;
           
            uVector3F camPos = device->getCamera()->getPosition();
            while( sorted.size() < vec.size() )
            {
                for( unsigned int i = 0; i < vec.size(); i++ )
                {
                    float distX = vec[ i ]->getPosition().x - camPos.x;
                    float distY = vec[ i ]->getPosition().y - camPos.y;
                    float distZ = vec[ i ]->getPosition().z - camPos.z;
                   
                    float dist = distX * distX + distY * distY + distZ * distZ;
                   
                    if( dist > maxLength )
                    {
                        maxLength = dist;
                        maxId = i;
                    }
                }
                sorted.push_back( maxId );
            }
            return sorted;
           
        }
        else return std::vector < UINT >();
       
    }
   
}
Nie wiem jak wy, ale ja tu żadnego błędu nie widzę.
Dlatego przejdźmy do drugiej części kodu używanej w Scene::drawSorted() a mianowicie:
C/C++
for( unsigned int i = 0; i < sorted.size(); i++ )
     privDrawObject( i );

Dla każdego obiektu w sorted używam funkcji privDrawObject(UINT id) No to przyjżyjmy się jej:
C/C++
void Scene::privDrawObject( UINT id )
{
    Device * device = dynamic_cast < Device *>( getParentWindow() );
    if( !device )
         return;
   
    VideoDriver3D * dest = device->getVideoDriver3D();
    if( !dest )
         return;
   
    dest->draw(( * this )[ id ] );
}
Ja tutaj nie widzę, żebym gdziekolwiek naruszał dostęp. Nie wiem nawet co podejrzewać o ten karalny czyn.
P-125856
DejaVu
» 2015-02-02 11:27:03
Uhm... dlaczego zakładasz, że count może być ujemny? Może w innym kodzie nie sprawdzasz tego czy wartość jest ujemna? Moim zdaniem skoro uzyskujesz this=0x0 to bym zakładał, że wywołujesz metodę na wskaźniku nullowym. Jeżeli callstack 'urywa się' w złym miejscu jak to pokazałeś na screenie to znaczy, że piszesz gdzieś po pamięci (wychodzisz poza zakres tablicy).
P-125858
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2015-02-02 13:04:28
Uhm... dlaczego zakładasz, że count może być ujemny?
Tutaj kod metody drawSorted (argumenty funkcji są z góry ustalane na (-1, NULL) gdyby użytkownik chciał wyświetlić wszystkie obiekty a nie tylko parę):
Tak wygląda deklaracja:
void drawSorted( int count = - 1, UINT * iTab = NULL );

A co do wychodzenia poza zakres - przecież iteruje po każdym elemencie vectora "sorted", czyli nie powinno tego być. Jak widać na kodzie u góry sprawdzam też czy Device != NULL i VideoDriver3D != NULL.

Jest możliwość żeby program się wysypał jeżeli rzutuje w dół pusty wskaźnik? Pytam bo w kodzie jest:
C/C++
Device * device = dynamic_cast < Device *>( getParentWindow() );
Gdyby getParentWindow() (który zwraca wskaźnik na klasę Window, nie Device) zwrócił NULL to jest taka możliwość?
P-125863
Monika90
» 2015-02-02 13:16:05
dynamic_cast z argumentem równym NULL po prostu zwraca NULL
P-125865
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2015-02-02 13:55:21
Nie widzę tutaj innych możliwości :(
P-125868
DejaVu
» 2015-02-02 14:42:30
Twój callstack mówi, że popisałeś po pamięci. Jeżeli nie jesteś w stanie określić który kod się sypie to powycinaj najpierw kod tak, aby działał poprawnie. Potem skompiluj w release i sprawdź czy również działa poprawnie, bo to, że aplikacja się nie wysypuje i zaczyna działać wcale nie oznacza, że w tym fragmencie był błąd w kodzie. Może się bowiem zdarzyć, że Twoje ewentualne nadpisanie callstacka nie wywołuje skutków ubocznych.
P-125869
« 1 » 2
  Strona 1 z 2 Następna strona