Beim TMemoryStream EAccessViolation -> Zugriffsverletzung
-
Hallo,
Ich weiß nicht wo das jetzt herkommt. Ich habe mir ein Neuen Rechner gekauft.
MemTest läuft ohne Fehler.Ich habe den CPP Builder 11.3 CE und C++Builder XE4 auf den VirtualBox 7.014 am laufen mit Win10.
Wen ich jetzt
std::auto_ptr<TMemoryStream> pss(new TMemoryStream());
oder
TMemoryStream *pss = new TMemoryStream();
hinzufüge, kommen die EAccessViolation -> Zugriffsverletzung entweder beim Lesen oder Schreiben.
Sogar bei beiden Version von CPP Builder. Selbst wen ich ein Neues Projekt mache.Habe keine Ahnung
Ich Hoffe es hat einer ein Rat für mich.
MfG Rave
-
@Rave1703 sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Win10
Ich ahne Schlimmes. Wieso nicht 11?
-
@noLust sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Ich ahne Schlimmes. Wieso nicht 11?
Weil es doch mit dem Alten Rechner lief.
Meinst du Win11 auf den Neuen Rechner und/oder VirtualBox dann mit Win11?
-
@noLust sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Ich ahne Schlimmes
Was meinst du damit?
-
Zeig mal den ganzen Code, an den beiden Zeilen liegt's sicher nicht.
-
Weil:
@Rave1703 sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Neuen Rechner
Und weil: EOL, vermutlich ...
@DocShoe sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Zeig mal den ganzen Code, an den beiden Zeilen liegt's sicher nicht.
Ja, das wäre sinnvoll.
Welche Versionsverwaltung hast du? Oft ändert man ja etwas und weiß gar nicht mehr, was.
-
@Rave1703 sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
TMemoryStream *pss = new TMemoryStream();
Rufst du auf dem raw pointer eigentlich auch anschließend
delete
auf?... Und der Smart-Pointer sollte eigentlich so sein:
std::unique_ptr<TMemoryStream> pss(new TMemoryStream());
Aber zum Rätselraten ist mir meine Zeit eigentlich zu schade.
-
@noLust sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Und der Smart-Pointer sollte eigentlich so sein:
std::unique_ptr<TMemoryStream> pss(new TMemoryStream());Wenn schon, dann doch bitte gleich mit
std::make_unique
, alsoauto pss = std::make_unique<TMemoryStream>();
Muss der
TMemoryStream
überhaupt ein Pointer sein? Das klingt so, als würde der intern bereits rumpointern. Andererseits: diese T...-Typen, da weiß ich nie so genau, ist ja was C++-Builder spezifisches.
-
Ja, muss es, leider. Alles, was von
TObject
erbt, kann man nicht auf dem Stack erzeugen.
-
@DocShoe sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Ja, muss es, leider. Alles, was von
TObject
erbt, kann man nicht auf dem Stack erzeugen.Ist das denn dann korrekt, da noch einen eigenen Auto-Pointer (oder manuelles delete) drumherum zu machen? Klingt doch sehr danach, als ob da eigene Ressourcenverwaltungsmagie passiert, mit entsprechend katastrophalen Folgen, wenn man sich da einmischt.
-
Doch, das ist leider immer noch der aktuelle Stand bei der VCL (entweder manuell
delete
aufrufen oder aber einen Smartpointer benutzen), selbst im zugehörigen Code-Beispiel von TMemoryStream wird in ComponentToString noch derstd::auto_ptr<...>(...)
(auch wenn dieser inzwischen veraltet ist) benutzt.
-
Kommt drauf an. Es gibt Objekthierarchien mit und ohne Ownership. Die mit Ownership zerstören ihre Objekte automatisch mit, wenn sie selbst zerstört werden, da reicht es aus, wenn man das top-level Objekt in einen smart pointer verpackt. Objekte ohne Ownership (zB.
TMemoryStream
) können ohne Probleme in smart pointer verpackt werden.
std::make_shared
ist aber generell problematisch, da Delphi Objekte nicht einfach perdelete
freigibt, sondern noch irgendwelchen Hokuspokus im Hintergrund veranstaltet (siehe hier: TComponent und make_unique/make_shared) und bei einem placement new in's Straucheln kommt.
-
Danke für die Antworten
war mein Fehler habe Versucht ein String in den MemoryStream zu Speichern und dann in ZipForge.
Dann wieder auszulesen ging leider schief
std::auto_ptr<TMemoryStream> pss(new TMemoryStream()); try { // __finally try { ZipForge1->FileName = UV_sArchivZIPFile; ZipForge1->OpenArchive(fmOpenRead); ZipForge1->ExtractToStream("Datei", pss.get()); } catch (Exception& e) { ... } catch (...) { ... } } __finally { ZipForge1->CloseArchive(); } System::UnicodeString sBuffer = EmptyStr; pss->Seek(0, soFromBeginning); pss->Read(&sBuffer, pss->Size); <- Da kommt der Fehler
Wen ich das so mache
std::auto_ptr<TStringStream> pss(new TStringStream()); ... sBuffer = pss->ReadString(pss->Size);
geht es
-
@Rave1703 sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
pss->Read(&sBuffer, pss->Size); <- Da kommt der Fehler
Hast du ne Ahnung, was da passiert? Nicht, was passieren soll, sondern das, was tatsächlich passiert?
Tipp: pss->Size ist nicht das Problem.
-
@DocShoe sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Hast du ne Ahnung, was da passiert? Nicht, was passieren soll, sondern das, was tatsächlich passiert?
Hmm ... Ehrlich leider ne
-
@Rave1703 sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
@DocShoe sagte in Beim TMemoryStream EAccessViolation -> Zugriffsverletzung:
Hast du ne Ahnung, was da passiert? Nicht, was passieren soll, sondern das, was tatsächlich passiert?
Hmm ... Ehrlich leider ne
Ich steige hier zwar gerade quer ein, aber die Klasse
UnicodeString
sieht vermutlich so oder ähnlich aus:class UnicodeString { ... int length; WideChar* string_data; ... };
Mit
&sBuffer
erhältst du die Adresse der obigen Datenstruktur, die wahrscheinlich nur wenige Bytes groß ist. Eine Schreiboperation auf diese (was du mit dempss->Read(&sBuffer, ...)
machst), wird also wahrscheinlich erstmal Länge, den Pointer auf die String-Daten und dann munter weiter den Stack überschreiben - z.B. irgendwelche nachfolgenden lokalen Variablen die da noch liegen.Der Effekt ist, dass du entweder mit der Schreiboperation über die letzte Speicherseite des Stack hinausschießt, dann gibt es sofort eine Zugriffsverletzung, oder dass danach im Stack nur noch Müll steht. Besonders in der Länge des Strings und dem
string_data
-Pointer. Beides wird mit dann hoher Wahrscheinlichkeit ebenfalls zu einer Zugriffsverletzung führen - spätestens wenn du irgendwas mit dem String machst - z.B. ihn ausgeben oder anderweitig lesen/schreiben (lesen von "kaputter" Speicheradresse instring_data
oder "out of bounds" Read durch fehlerhaftelength
).Wenn du richtig Pech hast, merkst du auch erstmal gar nichts, weil du mit den fehlerhaften Speicherzugriffen in den Speicherseiten bleibst, die dein Prozess reserviert hat. Dann kann es sein, dass sich das Problem erst später und an einer ganz anderen Stelle manifestiert. Das ist dann kein Spaß zu debuggen
Was du wohl eigentlich machen wolltest, ist ein
pss->Read(string_data, ...)
, da ich mich aber nicht wirklich mit VCL auskenne, weiß ich nicht genau wie man da ran kommt. Außerdem muss dabei sichergestellt werden, dass der reservierte Speicherbereich vonstring_data
groß genug ist, um die Daten aufzunehmen - da weiß ich leider auch nicht ob einUnicodeString
auch so etwas wiestd::string::reserve
/resize
kennt. Besser du bleibst also beiReadString
, das sieht erstmal okay aus - auch wenn es vielleicht nicht die effizienteste Lösung ist.
-
Ich idi durch die ganze Sache mit dem Neuen Rechner dache ich das es am Rechner liegt.
Hätte ich auch darf kommen können, da ich ein Test mit 11 Byte gemacht habe da hat es funktioniert und
bei ca. 2000 Byte kam der Fehler.Aber trozdem ... Danke dir