RAD Studio 2007 C++: Übergebene Parameter einer Funktion werden (manchmal) zerstört?!?
-
Hallo zusammen,
ich hab da mal wieder ein Problem. Gegeben ist folgendes Szenario:
class Foo { private: int FuncA(void); public: int FuncB(void); }Extern in einer Library FuncC(void *Parameter)
In FuncA und FuncB wird diese externe Funktion "FuncC" aufgerufen. Nun passiert folgendes bei den verschiedenen Calls:
1. FuncA call't FuncC -> alles OK
2. FuncA call't FuncB, die wiederrum FuncC call't -> Parameter defekt.Der Parameter ist in jedem Fall ein Array-of-char, das Innerhalb FuncA und FuncB unabhängig voneinander erstellt wird (lokale Variable in der jeweiligen Funktion).
Soweit ich das Debuggen konnte, zerstört der Aufruf der FuncC aus der FuncB heraus den Parameter. Also vor dem Aufruf der FuncC stimmt der Wert des Parameters bei beiden Aufrufen (in FuncA und FuncB), aber nur beim Aufruf aus FuncA heraus kommt der Parameter auch richtig in FuncC an.
FuncC-Aufrufe sind in beiden Fällen absolut identisch, genauso die Erzeugung des Parameters.
Woran könnte es liegen, das dieser Fehler Auftritt? FuncA und FuncB sind in einer gemeinsamen Klasse, nur private/public ist der Unterschied. Stört das das RAD Studio, und wenn ja, warum?
So, hoffe ich konnte das noch halbwegs erklären, ich hänge da schon seid 14 Stunden dran und hab echt keine Idee mehr...
Danke!!!!
-
Könntest du mal ein vollständiges Minimalbeispiel, das dein Problem demonstriert, posten?
Ansonsten ist es ggf. ratsam, in der CPU-Ansicht mitzuverfolgen, was genau mit dem Parameter geschieht.
-
soooo.. dann mal ein paar codeschnippsel...
class DBFileDef { private: // ... int open_file(int reorganize, int restore); // ... public: // ... int reorganize_file(stdtypes::LongWord n_rec, int current_buflen, int current_versionnr); // ... };int DBFileDef::open_file(int reorganize, int restore) { // ... FullNameTyp fullname; // um diesen Parameter gehts // ... memset(fullname,0,sizeof(fullname)); fullnamecpy(fullname,m_Index); // ... err = BTRV(B_OPEN, ares::files[m_Index].posBlock, ares::files[m_Index].ownername, &dLen, fullname, B_NORMAL); // hier klappt die übergabe // ... err = reorganize_file(n_rec, current_fixlen, current_version); // ...int DBFileDef::reorganize_file(LongWord n_rec, int current_fixlen, int current_version) { // ... FullNameTyp rf_fullname; // und um diesen // ... memset(rf_fullname,0,sizeof(rf_fullname)); fullnamecpy(rf_fullname,m_Index); // ... err = BTRV(B_OPEN, ares::files[m_Index].posBlock, ares::files[m_Index].ownername, &dLen, rf_fullname, READONLY); // hier gehts schief // ...Nur der Parameter "rf_fullname" geht kaputt, alles andere wird richtig übergeben...
in "fullname" und "rf_fullname" steht "c:\\test\\daten.dta". Beim BTRV-Call in "open_file" bleibt das auch so, beim BTRV-Call in "reorganize_file" kommt inetwa "\0\0€$§&%st\\daten.dta" an. Es wird immer der Anfang des Strings mit "Müll" überschrieben.
Was mich am meisten fertig macht, ist die Tatsache, das das ganze vor ca. 3 oder 4 Jahren zusammen mit "virtual Realisticer" entwickelt wurde (unter BCB6) und 100%ig auch funktionierte. Seither wurde diese Funktion aber nicht wirklich verwendet, und nu klappts nicht mehr. Obs am RAD Studio liegt?
Werde das mit der CPU-Ansicht mal am Montag versuchen, hier (auf der couch
) habe ich im Moment kein voll funktionsfähiges Development-System....
-
Dein Code ist leider nicht vollständig. Wie ist FullNameTyp definiert; ist es ein POD-Typ, falls nicht, wie lauten die Konstruktoren, insbesondere der Kopierkonstruktor? Wie sieht die Funktionssignatur von BTRV() aus; ist die Funktion überladen?
Jedenfalls kann ich dir für solche Fälle das bereits erwähnte Debugging auf Assembler-Level sowie die Verwendung von Datenhaltepunkten nahelegen.
-
Hallo und guten Morgen,
ja, ich weis, ich wollte nur nicht den Rahmen sprengen... und es war schon spät in der nacht...oder früh am morgen....
Ich werde mich heute da nochmal schwerpunktmäßig durchdebuggen, und meine erkenntnisse dann posten...
erstmal vielen Dank!!!
-
Soooo,
Fehler weiter eingegrenzt. Es liegt NICHT am call der BTRV-Funktion, sondern am call einer beliebigen Funktion!!!
Habe mit einfach mal parallel zur lokalen Variable "fullname" bzw "rf_fullname" eine globale Variable angelegt, mit der ich genau das gleiche mache. Und siehe da, mit der globalen klappts. Und dann ist mir aufgefallen, das es Jacke-wie-Hose ist, was für eine Funktion ich zwischen "fullnamecpy" und "BTRV" in der Funktion "reorganize_file" aufrufe, alleine durch den Aufruf wird "rf_fullname" zerstört. Selbst wenn ich den Quellcode auf "minimal" ändere dann Tritt der Fehler nur in der funktion "reorganize_file" auf.
So, nun bin ich verwirrt...
Hier der "minimierte" Code, der genau den gleichen Fehler verursacht:
FullNameTyp ist ein char[98]
fullnamecpy ist im prinzip nur ein strncpyint DBFileDef::open_file(int reorganize, int restore) { FullNameTyp fullname; memset(fullname,0,sizeof(fullname)); fullnamecpy(fullname,m_Index); err = BTRV(B_OPEN, ares::files[m_Index].posBlock, ares::files[m_Index].ownername, &dLen, fullname, B_NORMAL); // hier klappt alles err = reorganize_file(n_rec, current_fixlen, current_version); return err; }int DBFileDef::reorganize_file(LongWord n_rec, int current_fixlen, int current_version) { FullNameTyp rf_fullname; memset(rf_fullname,0,sizeof(rf_fullname)); fullnamecpy(rf_fullname,m_Index); err = BTRV(B_OPEN, ares::files[m_Index].posBlock, ares::files[m_Index].ownername, &dLen, rf_fullname, READONLY); // hier ist "rf_fullname" kaputt return err; }Wenn ich nun die globale variable ins spiel bringe, dann klappts wieder:
int DBFileDef::reorganize_file(LongWord n_rec, int current_fixlen, int current_version) { FullNameTyp rf_fullname; memset(rf_fullname,0,sizeof(rf_fullname)); fullnamecpy(rf_fullname,m_Index); // hier ist rf_fullname noch OK memset(glb_fullname,0,sizeof(glb_fullname)); // und hier nicht mehr fullnamecpy(glb_fullname,m_Index); // glb_fullname klappt immer err = BTRV(B_OPEN, ares::files[m_Index].posBlock, ares::files[m_Index].ownername, &dLen, glb_fullname, READONLY); // damit gehts return err; }Dabei ist es egal welche (sinnvolle) reihenfolge ich einhalte, sobald nach "fullnamecpy(rf_fullname,m_Index)" eine funktion aufgerufen wird, ist die Variable "rf_fullname" kaputt.
Name habe ich schon mehrfach geändert, daran liegts nicht. Aus der CPU-Ansicht werde ich nicht so wirklich schlau, ich habe nur den Eindruck, das "rf_fullname" an einer (relativ) anderen Position im Speicher steht, als bei anderen aufrufen der BTRV-Funktion... Stolpert der Compiler da vieleicht über irgendwas? Aber wenn ich doch 2 Funktionen mit offensichtlich gleichem Quellcode habe, warum kommt es dann zu so einem Fehler?
Ich bin für jeden Tipp dankbar!!
-
FrankBach schrieb:
Dabei ist es egal welche (sinnvolle) reihenfolge ich einhalte, sobald nach "fullnamecpy(rf_fullname,m_Index)" eine funktion aufgerufen wird, ist die Variable "rf_fullname" kaputt.
Dann schau dir mal an, was diese Funktion mit dem Stack anstellt. Es wäre z.B. denkbar, daß bei Implementation und Verwendung unterschiedliche Aufrufkonventionen verwendet werden, so daß die Parameter entweder überhaupt nicht oder zweimal vom Stack entfernt werden. Oder fullnamecpy() überschreibt mit dem strncpy()- oder memcpy()-Aufruf Parameter auf dem Stack.
Zeige mal die exakte Deklaration von fullnamecpy() sowie von FullNameTyp.
Grundsätzlich ist anzunehmen, daß sich viele deiner Probleme lösen, sobald du nicht mehr C, sondern C++ programmierst

-
jetzt muss ich mich mal ganz blöd anstellen....
was meinst du damit? ich glaub ich bin schon so "vermurkst" durch den quelltext, das ich das nicht mehr so ganz auseinanderhalten kann....

ich hab vor, ähm, 12 Jahren mal auf "Turbo C++" programmieren gelernt, aber ich glaube da hat sich so ein bischen was geändert ...
-
Die Frage ist einfach, was ist FullNameTyp?
Warum brauchst du für diesen Typen memset und dies unbekannte Funktion fullnamecpy. Das ist eigentlich C-ähnlicher Syntax (wie bei char*). Bei einer ordentlichen Klasse braucht man derartige Verrenkungen nicht (Konstruktor, Zuweisungsoperator).
-
hm....
also fullnamecpy führt eine pfadangabe und einen dateinamen zu einem "kompletten" dateinamen zusammen und zwar so (bitte nicht schlagen):
static std::string FullNameCpy( const char *Name, const char *Path ) { std::string FullName ( Path ); if(FullName.empty()) return FullName; if ( FullName.at ( FullName.size () - 1 ) != OSPATHSEPA ) FullName += OSPATHSEPA; FullName.insert ( FullName.length (), Name ); return FullName; } void fullnamecpy(char *FullName, const char *Name, const char *Path) { std::string NFullName = FullNameCpy ( Name, Path ); memcpy ( FullName, NFullName.c_str (), NFullName.length () + 1 ); } void fullnamecpy(char *FullName, int Index) { if (ares::files[Index].flags & FILEDEF_DDFFILE) fullnamecpy(FullName, ares::files[Index].name, WWSGlb::Instance().wwsglb.path_ddf); else if (ares::files[Index].flags & FILEDEF_SYSFILE) fullnamecpy(FullName, ares::files[Index].name, WWSGlb::Instance().wwsglb.path_system); else fullnamecpy(FullName, ares::files[Index].name, WWSGlb::Instance().wwsglb.path_data); return; }denke mal ihr meint alle char* nach string zu "übersetzen", oder?
Edit: Warum klappt das nie mit dem einrücken bei mir....
-
Warum verwendest du nicht durchgängig std::string und schaufelst deine Daten ständig zwische string und char* hin und her?
In fullnamecpy ist nicht sicher, dass in FullName überhaupt genug Speicher alloziert wurde um den String aufzunehmen. Zum Kopieren von char-Arrays nimmt man eh besser strncpy. Das achtet wenigstens auf das abschließende 0-Byte.
Falls du viel mit Files (Filenamen etc.) hantieren musst und beim Standard bleiben willst schau di mal boost::filesystem an.
-
so, ich wieder,
also das mit std::string steht jetzt ganz oben auf meiner Liste. Allerdings muss ich dafür ein paar tausend programmzeilen überarbeiten - und dafür ist im moment keine zeit.
ich hab' nun einfach den betreffenden "string" in das globale array, aus dem auch der name der datei komme, abgelegt. und so scheints zu funktionieren.
Warum der fehler auftritt ist mir allerdings immer noch nicht klar....egal, erstmal sind andere dinge wichtiger.
noch eine letzte frage: diese BTRV-Funktion verlangt den Dateinamen als "void ", weil dieser Parameter auch für andere Sachen geutzt wird. (nein ich kann das nicht ändern, leider). wie bekomme ich nun den std::string nach void gecastet? ich habs schon mit
const_cast<void *>(MeinString.c_str())versucht, und variationen davon mit/ohne const. aber nur
(void *)MeinString.c_str()konnte den Compiler besänftigen. Aber 2. Variante ist doch "C", oder? "C++" wäre der const_cast?
Muss ehrlich gestehen, meine "c++" spezifischen Programmierkenntnise sind doch etwas magelhaft...
Dankeschön an alle Helfer!!!
-
Der richtige C++Cast hierfür heißt reinterpret_cast. Also:
reinterpret_cast<void *>(MeinString.c_str())Das ist aber gefährlich, weil du erstens über die Gültigkeit dieses Zeigers in der Funktion keine Aussage machen kannst (Speicher könnte gleich danach freigegeben sein) und zweitens c_str einen const char* zurückgibt. Hier muss sicher sein, dass die Funktion da nichts hineienschreibt, da sie ja auch die Größe des allozierten Speichers nicht kennt.