Frage

, was passiert ist, ich Verschlüsselung Pakete gerade lese, und ich begegne ein beschädigtes Paket, das eine sehr große Zufallszahl für die Länge zurück gibt.

size_t nLengthRemaining = packet.nLength - (packet.m_pSource->GetPosition() - packet.nDataOffset);

seckey.SecretValues.m_data.resize(nLengthRemaining);

In diesem Code m_Data ist ein std::vector<unsigned char>. nLengthRemaining zu groß ist aufgrund eines beschädigten Datenpaketes, damit die Formatfunktion führt. Das Problem ist nicht, dass Resize wirft (wir die Ausnahmen zu behandeln), aber die Resize-Speicher bereits beschädigt ist, und dies führt zu mehr Ausnahmen später.

Was ich tun möchte, ist, ob die Länge zu groß ist, bevor ich die Größe nennen, dann nur rufen Sie die Größe, wenn es in Ordnung ist. Ich habe vor dem Aufruf dieses Codes versucht setzen, um die Größe:

std::vector<unsigned char>::size_type nMaxSize = seckey.SecretValues.m_data.max_size();
if(seckey.SecretValues.m_data.size() + nLengthRemaining >=  nMaxSize) {
    throw IHPGP::PgpException("corrupted packet: length too big.");
}
seckey.SecretValues.m_data.resize(nLengthRemaining);

Dieser Code wird mit der std :: vector max_size Memberfunktion zu testen, ob der nLengthRemaining größer ist. Das muss aber nicht zuverlässig sein, weil nLengthRemaining ist immer noch weniger als nMaxSize, aber anscheinend immer noch groß genug Größe ändern, um zu bewirken, ein Problem zu haben (nMaxSize war 4xxxxxxxxx und nLengthRemaining ist 3xxxxxxxxx).

Außerdem habe ich nicht feststellen, welche Ausnahme Resize wirft. Es ist kein std :: length_error und es ist kein std :: bad_alloc. Welche Ausnahme es wirklich zu werfen ist nicht so wichtig für mich, aber ich bin neugierig, zu wissen.

btw, nur damit Sie wissen, wird dieser Code korrekt funktioniert im Normalfall. Dieser Fall eines beschädigten Datenpaketes ist der einzige Ort, an dem es verrückt geht. Bitte um Hilfe! Dank.

UPDATE:

@ Michael. Denn jetzt werde ich einfach ignorieren das Paket, wenn es als 5 MB größer ist. Ich werde über möglicherweise mit anderen Teammitgliedern besprechen die Pakete Validierung (es schon da sein kann, und ich weiß es einfach nicht). Ich fange an zu denken wirklich um einen Fehler in unserer Version von STL ist, die Ausnahme wirft es ist nicht einmal eine std :: exception, die mich überrascht. Ich werde versuchen, von meinen Vorgesetzten, welche Version von STL, um herauszufinden, wir laufen auch (wie würde ich überprüfen?).

ANOTHER UPDATE: Ich beweisen nur, dass es ein Fehler in der STL-Version ist ich auf meiner Visual Studio 6 Entwicklung Maschine bin mit. Ich schrieb dieses Beispiel-App:

// VectorMaxSize.cpp: Legt den Einstiegspunkt für die Konsolenanwendung. //

#include "stdafx.h"
#include <vector>
#include <iostream>
#include <math.h>
#include <typeinfo>

typedef std::vector<unsigned char> vector_unsigned_char;

void fill(vector_unsigned_char& v) {
    for (int i=0; i<100; i++) v.push_back(i);
}


void oput(vector_unsigned_char& v) {
    std::cout << "size: " << v.size() << std::endl;
    std::cout << "capacity: " << v.capacity() << std::endl;
    std::cout << "max_size: " << v.max_size() << std::endl << std::endl;
}

void main(int argc, char* argv[]) {
    {
        vector_unsigned_char v;

        fill(v);

        try{
            v.resize(static_cast<size_t>(3555555555));
        }catch(std::bad_alloc&) {
            std::cout << "caught bad alloc exception" << std::endl;
        }catch(const std::exception& x) {
            std::cerr << typeid(x).name() << std::endl;
        }catch(...) {
            std::cerr << "unknown exception" << std::endl;
        }

        oput(v);    
        v.reserve(500);
        oput(v);
        v.resize(500);
        oput(v);
    }

    std::cout << "done" << std::endl;
}

Auf meiner VS6 dev Maschine hat es das gleiche Verhalten das Verschlüsselungs Projekt hat, verursacht es alle Arten von Chaos. Als ich bauen und es auf meinem Visual Studio 2008-Maschine laufen, die Größe eine std :: bad_alloc Ausnahme und der Vektor beschädigt wird nicht werfen, so wie wir es erwartet hätte! Zeit für einige EA Sport NCAA Football hehe!

War es hilfreich?

Lösung

Ich denke, dass vector::max_size() ist so ziemlich immer ein ‚hart codiert‘ Ding - es ist unabhängig davon, wie viel Speicher das System / Library ist bereit, dynamisch zuweisen. Ihr Problem scheint ein Fehler in der Vektor-Implementierung zu sein, die Dinge verdirbt, wenn eine Zuweisung fehlschlägt.

‚Bug‘ könnte zu stark sein ein Wort. vector::resize() ist in Bezug auf den vector::insert() definiert und der Standard sagt über vector::insert():

  

Wenn eine Ausnahme anderen geworfen wird, als durch die Kopie Konstruktor oder Zuweisungsoperator von T gibt es keine Auswirkungen

So scheint es, wie es Zeiten geben kann, wenn der resize() Betrieb zu korrumpieren einen Vektor erlaubt ist, aber es wäre noch schön, wenn der Betrieb Ausnahme sicher ist (und ich denke, es ist nicht aus der Reihe sein würde, um die Bibliothek zu erwarten das zu tun, aber vielleicht ist es schwieriger, als ich mich vorstellen).

Sie scheinen ein paar vernünftige Optionen zu haben:

  • Änderung oder Aktualisierung einer Bibliothek, die nicht die Korruption Fehler hat (was für Compiler / Bibliothek Version spielst Du?)
  • anstelle der Prüfung gegen vector::max_size() Satz nMaxSize Ihr eigenes vernünftiges Maximum und das tun, was Sie oben, aber diese Schwelle stattdessen verwenden.

Edit:

Ich sehe, dass Sie VC6 verwenden - es ist auf jeden Fall ein Fehler in vector::resize(), dass etwas mit Ihrem Problem zu tun haben könnte, obwohl bei der Patch-Suche ich ehrlich nicht sehen, wie (es tatsächlich ist ein Fehler in vector::insert(), sondern als erwähnt, resize() nennt insert()). Ich würde vermuten, es sich lohnen würde besuchen Dinkumwares' Seite für Fehlerbehebungen für VC6 und anwenden das Updates.

Das Problem könnte auch etwas hat, auf der Seite mit dem <xmemory> Patch zu tun - es ist unklar, was der Fehler ist, dass es diskutiert wird, aber vector::insert() tut Anruf _Destroy() und vector<> hat den Namen _Ty definieren, so dass Sie in dieses Problem laufen könnten. Eine nette Sache - Sie werden nicht über die Verwaltung der Änderungen an den Header kümmern, da Microsoft nie wird sie wieder zu berühren. Überprüfen Sie einfach die Patches es in die Versionskontrolle machen und zu dokumentieren lassen.

Beachten Sie, dass Scott Meyers in "Effective STL", schlägt mit SGIs oder STLPort der Bibliothek besser STL Unterstützung zu bekommen, als mit VC6 kommt. Ich habe es nicht so nicht sicher, ob ich bin, wie gut diese Bibliotheken arbeiten (aber ich habe auch nicht VC6 mit STL verwendet sehr viel). wenn Sie die Option zu bewegen, auf eine neuere Version von VC, mit allen Mitteln Natürlich müssen es tun.


Ein weiterer edit:

Danke für das Testprogramm ...

VC6 des _Allocate() Implementierung für die Standard-Allocator (in <xmemory>) verwendet eine signierte int die Anzahl der Elemente zu bestimmen, zu vergeben und wenn die Größe gebene negativ ist (was offenbar ist, was Sie tun - sicherlich im Testprogramm Sie sind) die _Allocate() Funktion zwingt die angeforderte Zuordnungsgröße auf Null und geht. Beachten Sie, dass eine Null-Größe Zuweisungsanforderung wird so ziemlich immer erfolgreich (nicht, dass vector prüft, ob ein Ausfall sowieso), so fröhlich die vector::resize() Funktion versucht, seinen Inhalt in den neuen Block zu bewegen, die nicht groß genug ist, gelinde gesagt, . So ist der Heap beschädigt wird, wird es wahrscheinlich eine ungültige Speicherseite getroffen, und zwar unabhängig -. Ihr Programm abgespritzt

So lautet das Fazit ist VC6 nicht immer fragen mehr als INT_MAX Objekte in einem Rutsch zu vergeben. Wahrscheinlich nicht eine gute Idee, in den meisten Fällen (VC6 oder auf andere Weise).

Außerdem sollten Sie bedenken, dass VC6 ein Vornorm Idiom verwendet 0 von new der Rückkehr, wenn eine Zuweisung fehlschlägt ranstatt bad_alloc werfen.

Andere Tipps

Ich würde empfehlen, dass Sie vielleicht mit falschen Argumenten Ihre Daten für Verfälschungen vor dem Aufruf von Bibliotheksfunktionen überprüfen!

eine Art von Hash-Code verwenden oder Summenalgorithmus überprüfen auf Ihre Pakete. Sie können nicht auf die Bibliothek verlassen, Ihnen zu helfen, da sie nicht in der Lage zu tun ist: Es kann sein, dass Sie geben ein beschädigten aber immer noch gültig ist (aus der Sicht der Bibliothek) Größe, die wirklich groß ist, so dass es zum Beispiel 768 MB RAM reserviert. Dies kann funktionieren, wenn es genügend freien Speicher im System ist aber fehlschlagen, wenn es andere Programme laufen, die zu viel Speicherplatz auf Ihrem 1024MB Maschine verbrauchen.

So wie oben gesagt: Überprüfen Sie zuerst

Ich habe keine Ahnung, was Sie meinen, wenn Sie sagen „Resize-Speicher beschädigt hat“. Wie bestimmen Sie das?

FWIW, ich bin nicht einverstanden mit Michaels Antwort . Wenn std::vector<>::resize() auf Vektor-Erweiterung führt, sehe ich zwei Möglichkeiten:

  1. Entweder einer der Konstrukteure verwendet, um den neuen Raum zu füllen (oder die Elemente kopieren) warf oder
  2. der Zuordner verwendet, um den Vektor zu wachsen tat
  3. oder der Vektor bestimmt, bevor Hand, dass die gewünschte Größe zu viel ist und wirft.

Mit std::vector<unsigned char> wir sicher # 1 entlassen können, so dass # 2 verlässt. Wenn Sie keine spezielle allocator verwenden, dann sollten std::allocator verwendet werden, und AFAIK, das wird new rufen Speicher zuzuweisen. Und new würde werfen std::bad_alloc. Aber Sie sagen, Sie dies nicht fangen kann, so dass ich weiß nicht, was passiert.

Was auch immer es ist, sollte es von std::exception abgeleitet werden, so könnte man dies tun, um herauszufinden:

try {
  my_vec.resize( static_cast<std::size_t>(-1) );
} catch(const std::exception& x) {
  std::cerr << typeid(x).name() << '\n';
}

Was ist das Ergebnis das?

Wie auch immer, was auch immer es ist, ich bin ziemlich sicher, dass es sollte nicht beschädigt Speicher. Entweder das ist ein Fehler in Ihrer std lib Implementierung (unwahrscheinlich, wenn Sie mich fragen, wenn Sie einen sehr alten verwenden) oder Sie haben etwas falsch gemacht anderswo.


Bearbeiten jetzt, dass Sie sagen, Sie verwenden VS6 ...

Sie sollten diese früher gesagt haben. VC6 wurde vor mehr als zehn Jahren freigelassen, nachdem MS ihre Abstimmung im std Komitee verloren hatte, weil sie nicht zu lange zu den Sitzungen erschienen waren. Die std lib Umsetzung sie versandt wurde von Dinkumware (gut), aber aufgrund rechtlicher Probleme war es der für VC5 (sehr schlecht), die viele kleinere und größere Bugs hatte und hat nicht einmal Unterstützung für die Mitgliedsvorlagen, auch wenn die VC6 Compiler unterstützt. Ehrlich gesagt, was erwarten Sie von einem solchen alten ein Produkt?

Wenn Sie nicht auf eine anständige VC-Version wechseln (I mindestens VC7.1 aka VS.NET 2003, da dies würde empfehlen, war derjenige, der den großen Sprung in Richtung Standardkonformität gemacht), zumindest zu sehen, ob Dinkumware noch eine VC6t Version ihrer ausgezeichneten Bibliothek verkaufen. (Eigentlich ist überrascht sein würde, aber sie verwendete, eine zu haben und man weiß ja nie ...)

Was die Ausnahmen: In früheren VC-Version (diese VC6 enthalten und beinhaltet nicht VC8 aka VS.NET 2005, ich bin über VC7.1 nicht sicher, obwohl) durch Standardzugriffsverletzungen könnte durch catch(...) gefangen werden. Also, wenn ein solcher Fang Block etwas gefangen, würden Sie nicht wissen, ob dies auch eine C ++ Ausnahme war. Mein Rat wäre, nur catch(...) in confunction mit throw; zu verwenden, um diese Ausnahme zu lassen weiterleiten. Wenn Sie das tun, erhalten Sie einen echten Crash bei AV des und sind in der Lage, um sie im Debugger-Stack-Trace. Wenn Sie dies nicht tun, wird AV des geschluckt und dann bist du mit einer Anwendung fest, die Berserker gegangen ist, ohne dass Sie selbst zu wissen. Aber irgendetwas zu tun, sondern mit einer AV'ed Anwendung Abbruch macht keinen Sinn. Ein AV ist ein Ergebnis von nicht definiertes Verhalten und danach alle Wetten ab.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top