2016-05-24 8 views
0

Also habe ich RapidXML vor kurzem als eine Möglichkeit benutzt, um XML in meinem Programm zu parsen, ich habe es hauptsächlich als Möglichkeit benutzt, herumzualbern, aber ich habe es bekommen einige sehr seltsame Probleme, denen ich wirklich auf die Spur komme. Versuchen Sie, und bleiben Sie dabei, weil ich ziemlich gründlich versucht habe, dieses Problem zu beheben, aber ich muss etwas verpassen.RapidXML, der auf Geschwisterknoten zugreift, verursacht scheinbar keine Gründe für segfaults

Als erstes ist hier die XML:

<?xml version="1.0" encoding="utf-8" ?> 
<resources> 
    <image key="tilemap_roguelikesheet" path="res/media/tilemaps/roguelikesheet.png" /> 
    <image key="tilemap_tiles" path="res/media/tilemaps/tiles.png" /> 
</resources> 

Die Funktion der segfault auftritt:

void TextureManager::LoadResource(const char* pathToFile) 
{ 
    rapidxml::xml_document<>* resource = Resources::LoadResource(pathToFile); 
    std::string imgName; 
    std::string imgPath; 

    if (resource != NULL) 
    { 
     rapidxml::xml_node<>* resourcesNode = resource->first_node("resources"); 

     if (resourcesNode != NULL) 
     { 
      for (rapidxml::xml_node<>* child = resourcesNode->first_node("image"); child; child = child->next_sibling()) 
      { 
       //Crash here on the second loop through. 
       imgName = child->first_attribute("key")->value(); 
       imgPath = child->first_attribute("path")->value(); 
       Astraeus::Log(moduleName, "Image Name: " + imgName); 
       Astraeus::Log(moduleName, "Image Path: " + imgPath); 

       TextureManager::AddTexture(imgName, imgPath); 
      } 
     } 
     else 
     { 
      Astraeus::Error(moduleName, "Resources node failed to load!"); 
     } 

     resource->clear(); 

    } 
    else 
    { 
     std::string fileName(pathToFile); 
     Astraeus::Error(moduleName, fileName + " could not be loaded."); 
    } 
} 

So segfault auf der zweiten Schleife der for-Schleife durch alle Knoten gehen geschieht und Trigger wenn es versucht, die Zuordnung imgName zu tun. Hier wird es etwas merkwürdig. Beim Debuggen des Programms zeigt der erste Kindknotenzusammenbruch, dass er Speicherzeiger auf die nächsten Knoten und seine Elemente/Attribute usw. hat. Wenn Sie diese Knoten untersuchen, können Sie sehen, dass die Werte existieren und rapidxml die Datei erfolgreich analysiert hat.

Wenn jedoch die zweite Schleife auftritt, zeigt Kind, noch genau die gleichen Speicherzeiger zu haben, aber dieses Mal zeigt die Aufschlüsselung in Werten, dass sie im Wesentlichen NULL-Werte sind, das Programm schlägt fehl und wir erhalten den Code 139. Wenn Sie versuchen, den vorherigen Knoten zu betrachten, den wir gerade von den Werten erhalten haben, sind auch NULL.

Jetzt sagen, ich kommentieren die Zeile, die die AddTexture-Funktion aufruft, der Knoten ist in der Lage, alle Knotenwerte überhaupt keine Probleme auszudrucken. (Die Log-Methode druckt im Wesentlichen nur auf die Konsole, bis ich ein paar mehr funky Sachen damit mache.) Also muss das Problem in der Funktion liegen? Hier ist sie:

void TextureManager::AddTexture(const std::string name, const std::string path) 
{ 

    Astraeus::Log(moduleName, "Loading texture: " + path); 
    if (texturesLookup.find(name) != texturesLookup.end()) 
    { 
     Astraeus::Error(moduleName, "Texture Key: " + name + " already exists in map!"); 
    } 
    else 
    { 

     texturesLookup.insert(std::make_pair(name, path)); 
     //Texture* texture = new Texture(); 

     /*if (texture->LoadFromFile(path)) 
     { 
      //textures.insert(std::make_pair(name, texture)); 
     } 
     else 
     { 
      Astraeus::Error(moduleName, "Failed to add texture " + name + " to TextureManager!"); 
     }*/ 
    } 
} 

Das Ignorieren der Tatsache, dass Zeichenketten durchlaufen werden, und so sollte nicht die Knoten in irgendeiner Weise beeinflussen, ist diese Funktion immer noch ein bisschen iffy ist. Wenn ich alles auskommentiere, kann es funktionieren, aber manchmal stürzt es einfach wieder ab. Ein Teil des Codes wurde auskommentiert, da ich den Schlüsselnamen und einen Speicherzeiger für eine Textur direkt hinzufügte, wechselte ich zum Speichern der Schlüssel- und Pfadzeichenfolgen und konnte die Textur später als Workaround in den Speicher laden. Diese Lösung funktionierte ein wenig, aber sie begann wieder zu segfault.

Ich kann nicht wirklich zuverlässig replizieren oder eingrenzen, was das Problem jedes Mal verursacht, so würde jede Hilfe zu schätzen wissen. Geht RapidXML doc irgendwie aus dem Geltungsbereich oder etwas und wird gelöscht?

Für den Datensatz ist die Klasse praktisch nur statisch zusammen mit der Karte, die die Texturzeiger speichert.

Danke!

+1

Ich bin nicht vertraut mit dieser API, aber bedenken Sie, dass die nächsten Geschwister in den meisten XML-APIs, die ich kenne, alle Arten von Knoten und nicht nur Elementknoten zurückgeben können, so dass Sie wahrscheinlich den Textknoten zwischen den beiden Elementen treffen . –

+0

RapidXML unterscheidet sich geringfügig in der Ausführung, da next_sibling() tatsächlich den nächsten richtigen Knoten (in diesem Fall ) erhält, anstatt den Inhalt eines Knotens als seinen eigenen Textknoten zu behandeln. Wenn Sie den Text von diesen erhalten möchten, müssen Sie value() auf dem Knoten aufrufen (in meinem Code, der untergeordnet ist). Ich debuggte auch den Knotenwert, und so weiß ich, dass next_sibling() aufrufen wird und tatsächlich den nächsten richtigen Knoten sehen kann, außer wenn es alle Werte annulliert, bis zu dem Punkt, an dem der Zeiger zum vorherigen Knoten angezeigt wird Der Wert ist null. –

+0

Ihre 'image' Elemente sind leer, aber es gibt nur Leerstellen zwischen den' image' Elementen. Funktioniert Ihr Code, wenn Sie z. ''? –

Antwort

0

Also für jeden, der in der Zukunft wieder zurückkommt, ist hier was passiert.

Ja, es war ein Problem Bereich, aber nicht für die Xml_Document, wie ich anfangs dachte. Die xml_file-Variable, die in der Resources-Load-Funktion war, ging nicht mehr in den Geltungsbereich, was bedeutet, dass RapidXML aufgrund der Art und Weise, wie RapidXML Dinge im Speicher speichert, sobald der Speicher nicht mehr verfügbar ist, den Speicher freigab, was zum nächsten Mal dynamisch wurde Die Zuweisung erfolgte durch eine bestimmte Funktion, die das XML-Dokument verwischte und mit Mülldaten füllte.

Also ich denke, die beste Idee ist sicherzustellen, dass xml_file und xml_document nicht außerhalb des Geltungsbereichs gehen. Ich habe einige der Vorschläge aus früheren Antworten hinzugefügt, aber ich werde auf diese Elemente hinweisen, die im Code enthalten sind, bevor sie entfernt werden, um den Debug-Prozess zu unterstützen.

Vielen Dank für die Hilfe/Beratung.

0

Ich bin mir nicht sicher, aber ich denke, dass Martin Honnen den Punkt gemacht hat.

Wenn next_sibling() Rück den Zeiger auf den Textknoten zwischen den beiden „Bild“ Elemente, wenn man

imgName = child->first_attribute("key")->value(); 

schreiben Sie erhalten, dass child->first_attribute("key") ein Nullzeiger ist, so dass die ->value() wird dereferenzieren einen Nullzeiger. Absturz!

Ich nehme an, Sie sollten das next_sibling("image") Element erhalten; so etwas wie

for (rapidxml::xml_node<>* child = resourcesNode->first_node("image"); 
    child; 
    child = child->next_sibling("image")) 

Und sicher zu sein, nicht einen Null-Zeiger zu verwenden, ich Ihnen dringend empfehlen die Attribut Zeiger zu überprüfen (sind Sie wirklich sicher, dass „Bild“ Elemente immer den „Schlüssel“ tragen und die " Pfad "Elemente?); etwas wie das

  if (child->first_attribute("key")) 
      imgName = child->first_attribute("key")->value(); 
     else 
      ; // do something 

     if (child->first_attribute("path")) 
      imgPath = child->first_attribute("path")->value(); 
     else 
      ; // do something 

S.: Entschuldigung für mein schlechtes Englisch. meine Zähne stumpf

+0

Es ist in Ordnung mit der englischen Front, ich verstehe, was Sie sagen. :) Ich habe oben auf Martin geantwortet, aber was ich sagen werde, dass ich das vorher versucht habe, wird das Problem dann zur for-Schleife-Prüfung, um die Schleifenbildung gleichzusetzen mit wahr, so dass der nächste Knoten niemals richtig geparst wird. Es analysiert also den ersten Knoten, aber nicht den zweiten. –

+0

@ConnallLindsay - danke über die englische Front :); über segfault front ... naja ... ich habe keine Ideen mehr; aber mein Vorschlag zum Überprüfen von 'first_attribute()' bleibt bestehen – max66

0

Diese Linie setzt ...

rapidxml::xml_document<>* resource = Resources::LoadResource(pathToFile); 

LoadResource einen Zeiger zurückgibt, aber man kann nie es überall frei ...?

Sind Sie 100% sicher, dass die Funktion keinen Zeiger auf ein Objekt zurückgibt, das jetzt nicht mehr im Gültigkeitsbereich ist. Wie dieser klassische Bug ...

int * buggy() 
{ 
    int i= 42; 
    return &i; // UB 
} 

Wie @ max66 sagt. Sie sollten next_sibling("image") verwenden. Wenn das scheitert, müssen Sie herausfinden, warum.

Verwandte Themen