C++ "Stack Smashing Detected" Hatası

Varyemez

Hectopat
Katılım
3 Şubat 2018
Mesajlar
199
Yer
Türkiye
Daha fazla  
Cinsiyet
Erkek
Meslek
Lise Öğrencisi
C++ ile yazdığım uygulamayı açtığım zaman belirli işlemlerden sonra " *** stack smashing detected ***: <unknown> terminated Aborted (core dumped) " hatasını alıyorum. İnternette -fno-protector flag'ını eklemem gerektiği yazıyordu. Bunu yazınca stack smashing hatası gitti, ancak "segmentation fault (core dumped)" hatası almaya başladım. Bu stack smashing hatası neden oluşur? Nasıl düzeltirim?
İnşallah konuma cevap gelir, çünkü bu hata gerçekten başımı ağrıtmaya başladı.

C++:
 COLLADA (dae) yukleyicisi
#include <iostream>
#include <vector>
#include <fstream>
#include <string>

#include <SDL2/SDL.h>

class ObjectData {
public:
    std::vector<float> Position;
    std::vector<float> Indices;
    std::vector<float> TexCoord;
    std::vector<float> Normal;
  
    inline float* PositionPointer() { return &Position[0]; }
    inline float* IndicesPointer() { return &Indices[0]; }
    inline float* TexCoordPointer() { return &TexCoord[0]; }
    inline float* NormalPointer()   {  return &Normal[0];  }

    void LoadFileCOLLADA(const char* FilePath, unsigned int Returns);
    bool FAILURE;
    char* INFO;
private:
    void ReadFLOATCOLLADA ();
    std::ifstream File;
    int CursorPos;
};

/*
Function loads "float-array"
Cursor must start at  ...>HERE3.1415 5.21...
*/

void ObjectData::ReadFLOATCOLLADA () {

    int y = CursorPos, z;
    char character, FloatLine[12];
    while(character != '<') {
        memset(FloatLine, '0', 12);
        z = 0;
        for (CursorPos; character != ' '; CursorPos++, z++) {
            File.seekg(CursorPos);
            File.get(character);
            if (character == '<')
                break;
            FloatLine[z] = character;
            std::cout<<"Char = "<<character<<" Cursor = "<<CursorPos<<std::endl;
            std::cout<<"FLOAT_ARRAY = "<<FloatLine<<std::endl;
        }
        ObjectData::Position.push_back(atof(FloatLine));
        File.seekg(CursorPos);
        File.get(character);
    }
    std::cout<<"VECTOR LOADING END"<<std::endl;
    for (int i=0; i < Position.size(); i++)
        std::cout<<Position[i]<<std::endl;
} //End of function

void ObjectData::LoadFileCOLLADA(const char* FilePath, unsigned int Returns) {
    File.open(FilePath, std::ios::in);
    if (Returns == 0) {
        if (true) {
            char Character;
            char line[64];
            int x;
            CursorPos = 0;
            while (true) {
                memset(line, ' ', 80);
                for (CursorPos; Character != '<'; CursorPos++) {
                    File.seekg(CursorPos);
                    File.get(Character);
                    std::cout<<"Char: "<<Character<<" Cursor:"<<CursorPos<<std::endl;
                }
                x = 0;
                for (CursorPos; Character != '>'; CursorPos++) {
                    File.get(Character);
                    line[x] = Character;
                    File.seekg(CursorPos);
                    std::cout<<"NOTFLOATARRAY "<<"Char: "<<Character<<" Cursor:"<<CursorPos<<std::endl;
                    x++;
                }
                std::cout<<line<<std::endl;
                if (strstr(line, "float_array") != NULL && strstr(line, "mesh-positions-array") != NULL && strstr(line, "count=") != NULL) {
                    CursorPos--;
                    ObjectData::ReadFLOATCOLLADA();
                    std::cout<<"Position Vector is ready!"<<std::endl;
                    File.close();
                    std::cout<<"Position Vector is ready!"<<std::endl;
                    return;
                }
            }
        }
    }
}
C++:
 //GameObject.cpp
    ...
    ...
    ObjectData DataOfGameObject;
    GameObject::Name = GameObjectName;

    if (FileType == 1) {
        std::cout<<"GameObject::"<<GameObject::Name<<" = Loading 3D model..."<<std::endl;
        DataOfGameObject.LoadFileCOLLADA(ModelPath, 0); //HATA BURADA OLUSUYOR GIBI GOZUKUYOR, CUNKU TERMINAL ASAGIDAKI YAZIYI (COLLADA LOADED) YAZDIRMIYOR.
        std::cout<<"COLLADA LOADED"<<std::endl;
        if (DataOfGameObject.FAILURE) {
            std::cout<<"GameObject::"<<GameObject::Name<<" = "<<DataOfGameObject.INFO<<std::endl;
            GameObject::FAILURE = true;
            return;
        }
    }
    else
    {
        std::cout<<"GameObject::"<<GameObject::Name<<" = Only COLLADA supported."<<std::endl;
    }
    ...
    ...
 
Son düzenleme:
Çözüm
Kodunda ObjectData'nın LoadFileCOLLADA foksiyonununda line diye 64 karakter uzunluğunda bir karakter dizisi tanımlamışsın.
C++:
char line[64];
Sonraki satırlarda memset kullanarak, bu 64 büyüklüğündeki diziye 80 uzunluğundaki bir harf dizisi kopyalamışsın.
C++:
memset(line, ' ', 80);
Burada arabellek taşması (buffer overflow) hatası var. Bunu yapınca; o fonksiyonun, kendisini çağıran fonksiyona geri dönmek için kullandığı adres bilgisinin üzerine yazmış oluyorsun. Fonksiyonun çalışması tamamlandığında, geri dönmesi gereken adresi değiştirdiğin için saçma bir yere gitmeye çalıştığından bu hatayı alıyorsun. Bunun en basit halini aşağıdaki C kodunda bulabilirsin.
C:
#include <stdio.h>
#include <string.h>

void func()
{
    char arr[5]; // 5'lik bir dizi
    printf("a\n");
    fflush(stdout); // 'a' harfinin konsola yazmasını sağlamak için
    memset(arr, ' ', 6); // diziye 6 tane ' ' yaz
    printf("b\n");
    fflush(stdout); // 'b' harfinin konsola yazmasını sağlamak için
}

int main()
{
    func();
    printf("OK\n");
    fflush(stdout);
    return 0;
}
Kod:
$ ./a.out
a
b
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
Bunu çözmek için tanımladığın karakter dizisine, kendisinden büyük bir veriyi kopyalamamaya dikkat etmelisin.

Sonraki satırlarda aynı arabellek taşması hatasını tekrar yapıyorsun.
C++:
for (CursorPos; Character != '>'; CursorPos++) {
    File.get(Character);
    line[x] = Character;
    File.seekg(CursorPos);
    std::cout<<"NOTFLOATARRAY "<<"Char: "<<Character<<" Cursor:"<<CursorPos<<std::endl;
    x++;
}
Anladığım kadarıyla bir dosyadan yazı okuyorsun ve o yazıyı, tanımladığın karakter dizisine belli bir karakter gelene kadar kopyalıyorsun. Bunu yaparken de benzer şekilde tanımladığın line karakter dizisinin boyutunu aşma ihtimalin var. Örneğin, dosyanın içinde istediğin karakter 100. harften sonra gelebilir.

Bunu çözmek için boyutu dinamik olarak değişen bir dizi kullanabilir veya karakter dizisi yerine karakterleri, std::stringstream'a atıp; kullanacağın zaman karakter dizisine çevirebilirsin. Bunlar şimdi aklıma gelen çözümler. Başka çözüm yolları da vardır.
Kodunda ObjectData'nın LoadFileCOLLADA foksiyonununda line diye 64 karakter uzunluğunda bir karakter dizisi tanımlamışsın.
C++:
char line[64];
Sonraki satırlarda memset kullanarak, bu 64 büyüklüğündeki diziye 80 uzunluğundaki bir harf dizisi kopyalamışsın.
C++:
memset(line, ' ', 80);
Burada arabellek taşması (buffer overflow) hatası var. Bunu yapınca; o fonksiyonun, kendisini çağıran fonksiyona geri dönmek için kullandığı adres bilgisinin üzerine yazmış oluyorsun. Fonksiyonun çalışması tamamlandığında, geri dönmesi gereken adresi değiştirdiğin için saçma bir yere gitmeye çalıştığından bu hatayı alıyorsun. Bunun en basit halini aşağıdaki C kodunda bulabilirsin.
C:
#include <stdio.h>
#include <string.h>

void func()
{
    char arr[5]; // 5'lik bir dizi
    printf("a\n");
    fflush(stdout); // 'a' harfinin konsola yazmasını sağlamak için
    memset(arr, ' ', 6); // diziye 6 tane ' ' yaz
    printf("b\n");
    fflush(stdout); // 'b' harfinin konsola yazmasını sağlamak için
}

int main()
{
    func();
    printf("OK\n");
    fflush(stdout);
    return 0;
}
Kod:
$ ./a.out
a
b
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
Bunu çözmek için tanımladığın karakter dizisine, kendisinden büyük bir veriyi kopyalamamaya dikkat etmelisin.

Sonraki satırlarda aynı arabellek taşması hatasını tekrar yapıyorsun.
C++:
for (CursorPos; Character != '>'; CursorPos++) {
    File.get(Character);
    line[x] = Character;
    File.seekg(CursorPos);
    std::cout<<"NOTFLOATARRAY "<<"Char: "<<Character<<" Cursor:"<<CursorPos<<std::endl;
    x++;
}
Anladığım kadarıyla bir dosyadan yazı okuyorsun ve o yazıyı, tanımladığın karakter dizisine belli bir karakter gelene kadar kopyalıyorsun. Bunu yaparken de benzer şekilde tanımladığın line karakter dizisinin boyutunu aşma ihtimalin var. Örneğin, dosyanın içinde istediğin karakter 100. harften sonra gelebilir.

Bunu çözmek için boyutu dinamik olarak değişen bir dizi kullanabilir veya karakter dizisi yerine karakterleri, std::stringstream'a atıp; kullanacağın zaman karakter dizisine çevirebilirsin. Bunlar şimdi aklıma gelen çözümler. Başka çözüm yolları da vardır.
 
Çözüm
Uyarı! Bu konu 6 yıl önce açıldı.
Muhtemelen daha fazla tartışma gerekli değildir ki bu durumda yeni bir konu başlatmayı öneririz. Eğer yine de cevabınızın gerekli olduğunu düşünüyorsanız buna rağmen cevap verebilirsiniz.

Geri
Yukarı