Ich laufe f
:
contract Test {
function f() {
f();
}
}
was VM Exception: invalid opcode
in Browser-Festigkeit erzeugt. Ist das ein Fehler oder erwartetes Verhalten?
Scheint ein Fehler in der ethereumjs-vm zu sein, die browser-solidity über universal-dapp.js verwendet .
runCode.js hat seltsamen Code ...
function iterateVm (done) {
if (runState.stack.length > 1024) {
return done(ERROR.INVALID_OPCODE)
}
...weil sich die Stapellänge von der Tiefe unterscheidet, die gegen die 1024 (Wert von fee.stackLimit.v) in opFns.js geprüft wird:
// increment the runState.depth
callOptions.depth = runState.depth + 1
if (runState.depth >= fees.stackLimit.v ...
Wenn die Stapellängenprüfung korrekt ist, könnte sie zumindest einen anderen zurückgeben, der eine Verwechslung des Tiefenbegrenzungsfehlers mit einem ungültigen Opcode vermeiden würde.
Hinweis: Der folgende Code ist ein interner Funktionsaufruf , der „in einfache Sprünge innerhalb der EVM übersetzt“ wird. Das bedeutet, dass die Stapeltiefe nicht zunimmt .
contract Test {
function f() {
f();
}
}
Um die Stapeltiefe zu erhöhen, ist ein externer Funktionsaufruf erforderlich , verwenden Sie this.f()
. Auch die explizite Bezeichnung der Funktion als external
(oder public
) verbessert die Übersichtlichkeit.
contract Test {
function f() external {
this.f();
}
}
Darüber hinaus hat die EIP150 -Hardfork das Durchbrechen der Stack-Tiefe praktisch unmöglich gemacht (da das gesamte Gas zuerst erschöpft wäre):
Ersetzen Sie die maximale Call-Stack-Tiefe des „harten Limits“ durch ein weicheres Limit, bei dem das Erstellen eines tiefen Call-Towers eine exponentiell wachsende Menge an Gas erfordern würde. Dadurch werden Call-Stack-Tiefenbegrenzungsangriffe als eine Kategorie von Problemen, um die sich Vertragsentwickler kümmern sollten, vollständig entfernt ...
contract Test {
function f() {
f();
}
}
es wird einen unendlichen rekursiven Aufruf provozieren. Es handelt sich also nicht um einen Solidity-Browser-Bug.
versuchen Sie etwas wie:
contract C {
function g(uint a) returns (uint ret) { return f(); }
function f() returns (uint ret) { return g(7) + f(); }
}
Diese Funktionsaufrufe werden innerhalb der EVM in einfache Sprünge übersetzt.
Bearbeiten : Der Fehler wird durch eine Stapellänge von 1024 generiert, sodass der Compiler nicht mehr zum Ziel springen konnte (jeder Aufruf von f () führt einen Jump to Jumpdest durch).
74 JUMPDEST
75 PUSH 50
77 PUSH 4a
79 JUMP
Bei jedem rekursiven Aufruf (..=>97=>74=>97...) wird 0X50 zum Stack hinzugefügt, bis wir die Stake-Limit-Länge erreichen, dann springt der Fehler heraus. Dieser Fehler wird ausgelöst, solange der Vertrag über genügend Restgas verfügt (also keine outOfGas-Ausnahme).
SCBürgel
outOfGas
oder -stackDepth
Ausnahme erwartet. Waruminvalid opcode
? Ein einfacher Sprung sollte kein ungültiger Opcode sein.Badr Bellaj