Ich habe eine template-Methode erstellt, die einen Default-Parameter verwendet. Durch den Aufruf der Methode zerstöre ich mir den Stack! Allerdings ist mit nicht klar, was hier falsch ist.
template<typename NumericType>
void ForceBug::bar(NumericType value, NumericType step)
{
NumericType dummy = step; // Beim 5. Aufruf von foo.bar ist step != 0.0
}
int main()
{
ForceBug foo;
foo.bar(2);
foo.bar(2.0);
foo.bar(2.0);
foo.bar(2.0);
foo.bar(2.0);
return 0; // hier kommt vom Debugger die Fehlermeldung:
}
Fehler:
Code:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
Code:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
Code:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
Noch ein paar Anmerkungen:
Wenn man den Defaultparamter mit "step=0" definiert, reicht schon ein Aufruf mit einem double-Parameter, um den Fehler zu produzieren. Mit "step=NumericType()" konnte ich es nur reproduzieren, wenn zuerst ein Aufruf mit einem int-Parameter und danach mit einem double-Parameter erfolgt. Der Fehler lässt sich auch nicht bei freien Funktion reproduzieren oder wenn die Methode direkt in der Klasse definiert wird. Ich verwende Visual Studio 2005.
Was mache ich falsch? Falls das ein Compiler-Problem ist, gibt es dazu irgenwo schon einen Fehlerreport? Kann jemand nachvollziehen, ob das Problem in Visual Studio 2008 auch noch besteht?
Das scheint ein Compiler Bug zu sein, denn du machst rein gar nichts, womit du eine Calling Convention missachten könntest.
Unter VS 2010 läuft das ohne Probleme.
VS 2005 hat afaik Probleme mit templates. Kann gut sein, dass es daher kommt, aber mit normalem Code kann man so einen Fehler nicht erzeugen (müsstest z.B inline assembler benutzen oder vlt. mit einem merkwürdigen Pointer hack).
Tatsächlich. Auf Debug krieg ich den Fehler auch. Hatte es aus versehen noch auf Release.
Scheint, dass es Probleme gibt sobald man verschiedene Typen übergibt. Da werden aber korrekt 2 verschiedene Funktionen aufgerufen. Der Fehler scheint von den verschiedenen Grössen der Parameter zu kommen. Aber ich sehe nicht, was an dem Code falsch sein sollte.
Wenn ich x64 Code generieren lasse, dann läufts auch im Debug.
Ja, das Minimalbeispiel macht im Release nichts sichtbares, deshalb scheint alles in Ordnung. Wenn man aber einfach eine Ausgabe einfügt, sieht man, dass da was nicht stimmen kann:
@djohn
Das kommt wahrscheinlich daher, dass bei double irgendwas schief läuft und er irgendwie nicht 2 Wörter liest, sondern so nur ein Teil und dann den Rest von irgend einem anderen Wort liest.
@vermutung
Spielt eigentlich keine Rolle, weil das template 2 Funktionen machen kann. Man kann natürlich beide Parameter angeben, aber das tut ja nichts zur Sache, dass der gezeigte Code einen Fehler generiert.
Ich würde mal vermute, dass hier tatsächlich ein Bug vorliegt. Jemand hier, der GCC installiert hat?
2.0 ist schon richtig, damit soll eine Template-Instance für doube erzwungen werden. (Kann auch jeder andere double-Wert sein.) Als zweiter Parameter soll automatisch der Default-Parameter genommen werden.
Wirklich merkwürdig, bei mir (VS 2010) ist der Fehler ebenfalls reproduzierbar. Ich würde im Microsoft-spezifischen Unterforum nachfragen (oder diesen Thread verschieben), eventuell wissen die dort mehr.
@ vermutung: Kaum, er will halt mit double instanziieren. Der zweite Parameter ist eh ein Default-Parameter.
Ich würde mal vermute, dass hier tatsächlich ein Bug vorliegt. Jemand hier, der GCC installiert hat?
Ja. Läuft hervorrragend mit GNU und Intel-Compiler (beide ziemlich neu). Debugger meldet auch nichts verdächtiges. Und ich sehe auch keinen Fehler im Code.
Zuletzt bearbeitet von SeppJ am 17:41:19 10.02.2011, insgesamt 1-mal bearbeitet
Debuginformationen habe ich mal rausgekürzt um es übersichtlicher zu halten. Ich weiß jetzt aber nicht, was das bringen soll, beide Funktionen arbeiten korrekt und sind im Prinzip identisch, außer dass bei der einen alle Befehle für int sind, bei der anderen für doubles. Wie sehen die Funktionen denn bei VS 2010 aus?
edit: Oh, die Ausgabefunktionen habe ich entgegen deinem Wunsch noch drin. Naja, so lang ist's ja nun auch nicht.
Zuletzt bearbeitet von SeppJ am 18:17:11 10.02.2011, insgesamt 3-mal bearbeitet
Hmm. Mir scheint als hätte ich den Fehler gefunden, den VC da macht.
Die Funktionen selbst sind denke ich korrekt implementiert, aber der Aufruf der Funktionen scheint nicht so ganz zu klappen.
Da sieht man, dass bar(2) korrekt aufgerufen wird. Jedoch bin ich bei (1) stutzig geworden. Warum wird da lediglich ein Wort gepusht und nicht 2, wie es bei einem double ja sein müsste?
Bei (2) dachte ich dann nur WTF? - Warum wird da eine floating Point Operation gemacht, wenn doch nur int's im Spiel sind?
Da scheint irgendwie Code vorschnell erzeugt zu werden.. Ok, also mal schauen was passiert, wenn wir die bösen templates weglassen. :
(ich habe das template mit identischen Funktionen mit expliziten Parametern ausgetauscht)
Fazit: Selbst VC++ 2010 hat gewisse Probleme mit templates.. :P
@SeppJ:
Danke, aber ich hab den Fehler, den VC da macht bereits.
Hat jemand eine Ahnung, ob der Bug bereits gemeldet wurde? Respektive wo es da eine gute DB dazu gibt? Ich werde das bei Gelegenheit mal noch in meinem Blog posten. Wird Zeit, dass da wiedermal was passiert.
Nein. Bin gester nicht dazu gekommen. Wollte eigentlich einen exakten Beschreib (auch für meinen Blog) von dem Fehler machen.
Ich habe mich gestern dort extra noch angemeldet. :P
@djohn:
Da ich ja bereits den Fehler analysiert habe wäre es vielleicht gut das auch noch zu melden. Dann können die sich ein wenig Arbeit sparen.. ^^
Ich werde mal in einem Kommentar den Fehlerbeschreib ergänzen.
Habe gerade noch ein paar Sachen ausprobiert. Mit freien template Funktionen funktioniert es und auch wenn man die Definition inline macht (was denke ich der Hauptgrund ist, dass den Fehler noch niemand bemerkt hat).
Scheint aber wirklich davon abhängig zu sein dass Deklaration und Definition getrennt sind. Und ich kann's auch nicht mit etwas anderem als double reproduzieren. Und das auch nur, wenn vorher oder nachher ein Aufruf mit etwas anderem als double erfolgt.
In einem grösseren Projekt das ich gerade entwickle (mit VC 2005) hab' ich *einige* Templates mit getrennter Deklaration und Definition. Zwecks übersichtlichkeit der Header Files (Definition steht in eigenen .inl Files).
Und auch mit Default-Parametern und die Variablen sind auch oft vom Typ double
EDIT:
Wobei... dort werden eigentlich nur doubles verwendet, und nie was anderes. Sollte dann OK sein. Hab auch noch keinen derartigen Fehler beobachtet. Doof ist es trotzdem. /EDIT
Beim Versuch ein Minimalbeispiel zu erstellen, konnte ich den Fehler bei freien Funktionen auch nicht reproduzieren. Hatte da wahrscheinlich wie drakon noch eine der anderen Bedingungen wegreduziert. Bei Deiner zweiten Variante (Default-Wert ist ein int) reicht es aus, nur eine Template-Instanz mit double zu erzeugen um zumindest bei VS2005 den Fehler zu provozieren. Die zusätzliche Bedingung, dass man mindestens 2 Template-Instanzen mit unterschiedlichen Typen für den Fehler braucht, fällt dann weg.
Ich hatte auch nur wegen der Übersichtlichkeit Deklaration und Definition getrennt, kein großes Problem, dass jetzt zu ändern. Aber wenn so ein Fehler erstmal auftritt, ist man natürlich unsicher, unter welchen Bedingungnen noch dieses undefinierte Verhalten auftreten kann.
Deshalb, nochmal Danke an alle die sich an der Diskussion beteiligt haben, ich denke, wir haben jetzt ganz gut eingegrenzt, wann der Fehler auftritt.
int main()
{
baz(2);
baz(3.14); // compiles OK, but should not
baz("test"); // compiles OK, but should not
baz(c()); // compiles OK, but should not return 0;
}
int main()
{
baz(2);
baz(3.14); // compiles OK, but should not
baz("test"); // compiles OK, but should not
baz(c()); // compiles OK, but should not return 0;
}
int main()
{
baz(2);
baz(3.14); // compiles OK, but should not
baz("test"); // compiles OK, but should not
baz(c()); // compiles OK, but should not return 0;
}
Nächstes Thema anzeigen Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben. Sie können auf Beiträge in diesem Forum antworten. Sie können Ihre Beiträge in diesem Forum nicht bearbeiten. Sie können Ihre Beiträge in diesem Forum nicht löschen. Sie können an Umfragen in diesem Forum nicht mitmachen.
c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums
für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de
Werbekostenerstattung verdient werden kann.
Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de
enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt
(vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in
privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden.
Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere
übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.