Partage
  • Partager sur Facebook
  • Partager sur Twitter

Violation d'accès avec la STL

Exception non gérée à 0x10002742 (BmpLoader.dll) dans Ex_Loader.exe : 0xC0000005

Sujet résolu
    27 mai 2007 à 11:12:53

    Salut les Zér0s.

    Je suis confronté depuis hier à un problème qui m'échappe totalement. Lorsque j'exécute mon programme, il bugue avec ce message d'erreur (en mode debug) :

    Citation : Debuggeur Visual C++


    Exception non gérée à 0x10002742 (BmpLoader.dll) dans Ex_Loader.exe : 0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0xccccccd0.



    Je vous explique un peu mon programme car c'est un peu compliqué : un programme va aller charger des sortes de plugins (appelés Loaders dans mon code car ils servent à charger des fichiers :) ) qui sont sous forme de fichiers .dll . Ces dll exportent une fonction, Instance() qui va renvoyer une instance d'une classe abstraite ILoader spécialisée dans le chargement d'un fichier. Pour obtenir des informations sur le loader, le programme peut lui demander de ce présenter en lui passant une référence vers une structure Presentation et une référence vers une map contenant les infos sur les fichiers pouvant être chargés.

    Je vais poster mon code, attention c'est long (et mal codé en plus :D ) :
    Loader.h, qui contient l'interface commune à tous les loaders :

    #ifndef LOADER_H_DEFINED
    #define LOADER_H_DEFINED

    #include <string>
    #include <vector>
    #include <map>

    namespace Loader
    {
            enum FileTypes
            {
                    SCRIPT,
                    MODEL,
                    TEXTURE,
                    PROJECT,
                    FX,
                    CHARACTER,
                    OBJECT,
                    SOUND
            };

            struct Texture
            {
                    unsigned long w, h;
                    unsigned char* data;
                    unsigned long data_size;
                    bool loaded;
            };

            typedef std::map<std::string, FileTypes> LoadableFiles;

            struct Presentation
            {
                    std::string author;
                    std::string name;
                    std::string description;
                    std::string release_date;
                    std::string release_version;
            };

            class ILoader
            {
            public:
                    virtual void GetPresentation(Presentation& pre, LoadableFiles& f) = 0;
                    virtual bool Load(const std::string& file, void* buffer, size_t max_size) = 0;
            };
    };

    #endif


    Maintenant, BmpLoader.cpp, qui contient l'implémentation d'un chargeur de fichier .bmp (je vous épargne le .h, il vous sera totalement inutile) :

    #include "BmpLoader.h"

    #include <cstdio>
    #include <cstdlib>

    struct BitmapFileHeader
    {
            unsigned short type;
            unsigned int size;
            unsigned short reserved1, reserved2;
            unsigned int offset_bits;
    };

    struct BitmapInfoHeader
    {
            unsigned int size;
            unsigned long width, height;
            unsigned short planes, bit_count;
            unsigned int compression, image_size;
            unsigned long x_pels_per_meter, y_pels_per_meter;
            unsigned long clr_used, clr_important;
    };

    struct RgbQuad
    {
            unsigned char r, g, b, reserved;
    };

    void BmpLoader::GetPresentation(Loader::Presentation &pre, Loader::LoadableFiles& f)
    {
            memset(&pre, 0, sizeof(pre));
            pre.author = std::string("Delroth");
            pre.name = std::string("Bitmap Loader");
            pre.description = std::string("Load Windows bitmap files (*.bmp)");
            pre.release_version = std::string("0.1");
            pre.release_date = std::string("2007/05/26");
           
            // LE BUG EST EN DESSOUS
            f.clear(); // LE BUG EST ICI !
            // LE BUG EST AU DESSUS

            f["bmp"] = Loader::TEXTURE;
    }

    bool BmpLoader::Load(const std::string &file, void *buffer, size_t max_size)
    {
            if(max_size != sizeof(Loader::Texture)) return false;
            Loader::Texture* ret = reinterpret_cast<Loader::Texture*>(buffer);
            ret->loaded = false;

            FILE* fp = fopen(file.c_str(), "rb");
            if(!fp) return false;

            unsigned long file_size;
            fseek(fp, 0, SEEK_END);
            file_size = ftell(fp);
            fseek(fp, 0, SEEK_SET);

            BitmapFileHeader bmfh;
            fread(&bmfh, sizeof(bmfh), 1, fp);
            if(bmfh.type != 19778) { fclose(fp); return false; }
            if(bmfh.size != file_size) { fclose(fp); return false; }

            BitmapInfoHeader bmih;
            fread(&bmih, sizeof(bmih), 1, fp);
            if(bmih.size != sizeof(bmih)) { fclose(fp); return false; }
            if(bmih.planes != 1) { fclose(fp); return false; }
            if(bmih.compression != 0) { fclose(fp); return false; }

            RgbQuad* colors = NULL;
            unsigned long number_colors = 1 << bmih.bit_count;
            if(bmih.bit_count == 8)
            {
                    colors = new RgbQuad[number_colors];
                    if(!colors) { fclose(fp); return false; }
                    fread(colors, sizeof(*colors), number_colors, fp);
            }
            else if(bmih.bit_count != 24) { fclose(fp); return false; }

            long size = bmfh.size - bmfh.offset_bits;
            unsigned char* temp_data = new unsigned char[size];
            if(!temp_data) { fclose(fp); return false; }
            fread(temp_data, sizeof(unsigned char), size, fp);

            unsigned long byte_width, pad_width;
            byte_width = pad_width = (unsigned long)((float)bmih.width * (float)bmih.bit_count / 8.0);
            while(pad_width % 4 != 0) ++pad_width;

            unsigned int diff;
            int offset;
            long height = bmih.height;
            diff = height * byte_width;

            unsigned char* pixel_data = new unsigned char[diff];
            if(pixel_data == NULL) { fclose(fp); return false; }

            if(height > 0)
            {
                    int j = size - 3;
                    offset = pad_width - byte_width;
                    for(int i = 0; i < size; i += 3)
                    {
                            if((i + 1) % pad_width == 0)
                                    i += offset;

                            pixel_data[j + 2] = temp_data[i];
                            pixel_data[j + 1] = temp_data[i + 1];
                            pixel_data[j] = temp_data[i + 2];
                            ++j;
                    }
            }
            else
            {
                    height = height * -1;
                    offset = 0;
                    do
                    {
                            memcpy(&pixel_data[offset * byte_width], &temp_data[offset * pad_width], byte_width);
                            ++offset;
                    } while(offset < height);
            }

            ret->loaded = true;
            ret->w = bmih.width;
            ret->h = abs(bmih.height);
            ret->data = pixel_data;
            ret->data_size = diff;
            return true;
    }

    __declspec(dllexport) BmpLoader* __cdecl Instance()
    {
            return new BmpLoader();
    }


    J'ai donc une DLL BmpLoader.dll, qui contient ce Loader. Je la place dans un dossier "Loaders". Ensuite, le programme qui va venir charger ce loader :

    #include <cstdio>
    #include <cstdlib>
    #include <windows.h>
    #include <tchar.h>

    #include "..\LoaderBase\Loader.h"

    using namespace Loader;

    typedef ILoader*(__stdcall *GETINSTANCEPROC)();

    int main()
    {
            CreateMutex(NULL, FALSE, _T("}}DrEaM{-}CrEaToR{{"));
            HMODULE hMod = LoadLibrary(_T("Loaders\\BmpLoader.dll"));
            if(!hMod)
            {
                    printf("ERROR: Loader not found.\n");
                    exit(EXIT_SUCCESS);
            }

            GETINSTANCEPROC pInstance = (GETINSTANCEPROC)GetProcAddress(hMod, "Instance");
            if(!pInstance)
            {
                    printf("ERROR: Corrupted loader.\n");
                    exit(EXIT_SUCCESS);
            }

            ILoader* loader = pInstance();
            Presentation p;
            LoadableFiles f;
            // LE BUG EST EN DESSOUS
            loader->GetPresentation(p, f); // <---- BUG ICI !!!
            // LE BUG EST AU DESSUS

            printf("Information on the BmpLoader.dll module :\n"
                    "Name: %s\nDescription: %s\nVersion: %s %s\nAuthor: %s\n",
                    p.name, p.description, p.release_version, p.release_date, p.author);

            printf("\nExtension handled:");

            for(LoadableFiles::const_iterator i = f.begin(); i != f.end(); ++i)
            {
                    char* filetype = new char[256];
                    switch(i->second)
                    {
                    case SCRIPT: strcpy(filetype, "Script"); break;
                    case MODEL: strcpy(filetype, "Model"); break;
                    case TEXTURE: strcpy(filetype, "Texture"); break;
                    case PROJECT: strcpy(filetype, "Project"); break;
                    case FX: strcpy(filetype, "Special effect"); break;
                    case CHARACTER: strcpy(filetype, "Character"); break;
                    case OBJECT: strcpy(filetype, "Object"); break;
                    case SOUND: strcpy(filetype, "Sound"); break;
                    default: strcpy(filetype, "Unknown"); break;
                    }

                    printf("\t- %s - %s\n", i->first, filetype);
                    delete[] filetype;
            }
    }


    La ligne où se produit l'erreur est indiquée dans le code.

    J'offre un carambar à celui qui me trouvera l'erreur (mais vous payez les frais de port, hein ^^ ).
    • Partager sur Facebook
    • Partager sur Twitter
      27 mai 2007 à 16:01:13

      j'ai pas regarder le code mais çà doit venir d'un pointeur foireux
      • Partager sur Facebook
      • Partager sur Twitter
        27 mai 2007 à 18:17:07

        J'aimerais savoir un truc: pourquoi tu met ça?
          pre.author = std::string("Delroth");
                pre.name = std::string("Bitmap Loader");
                pre.description = std::string("Load Windows bitmap files (*.bmp)");
                pre.release_version = std::string("0.1");
                pre.release_date = std::string("2007/05/26");

        et pas plutôt ça o_O :
          pre.author = "Delroth";
                pre.name = "Bitmap Loader";
                pre.description = "Load Windows bitmap files (*.bmp)";
                pre.release_version = "0.1";
                pre.release_date = "2007/05/26";
        • Partager sur Facebook
        • Partager sur Twitter
          27 mai 2007 à 19:49:05

          Sans les std::string(""), j'avais un autre bug :) . Je vois vraiment pas d'où ça peut venir sachant que je n'utilise par moi même aucun pointeur (je laisse tout à la STL, moi au moins je suis tranquille (normalement ^^ )).
          • Partager sur Facebook
          • Partager sur Twitter
            27 mai 2007 à 20:14:50

            Je me souviens que STL + DLL ça ne faisait pas bon ménage.

            Microsoft le signale

            Plus d'infos si tu tapes STL DLL dans Google.
            • Partager sur Facebook
            • Partager sur Twitter
              27 mai 2007 à 21:51:41

              memset, reinterpret_cast, ... sur des non-POD, c'est du suicide!
              • Partager sur Facebook
              • Partager sur Twitter
              C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                27 mai 2007 à 22:57:27

                Le reinterpret_cast, j'aurais tout aussi bien pu mettre un static_cast, mais c'était histoire de montrer que le cast est pas forcèment sur.

                D'après vous en reprogrammant la classe map je pourrait m'en sortir ?

                PS: J'ai oublié de le préciser, le mutex créé dans mon programme sert à ce que la DLL ne puisse être chargée que lorsque mon programme est lancé.
                • Partager sur Facebook
                • Partager sur Twitter
                  27 mai 2007 à 23:51:24

                  Vires le memset; interdiction de s'en servir sur des objets. Il invalide complètement les strings que tu vas affecter.

                  Et assures-toi que DLL et exécutable sont bien compilés avec les mêmes options.
                  • Partager sur Facebook
                  • Partager sur Twitter
                  C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                    28 mai 2007 à 0:32:56

                    Tout est compilé avec les mêmes options, sans le memset j'ai toujours les mêmes problèmes.
                    J'ai aussi essayé plein d'autres choses : mettre des pointeurs, des références, mettre que des pointeurs dans ma structure, séparer la std::map de ma structure, et plein d'autres choses, mais rien ne marche.

                    Conclusion: Je vais utiliser boost ou reprogrammer la classe map :p . Enfin je me souviendrais que encore une fois Microsoft m'a fait perdre 1 jours et demi :) (** rajoute cela à son carnet de bug de windows **).
                    • Partager sur Facebook
                    • Partager sur Twitter

                    Violation d'accès avec la STL

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown