[uBasic] "Nested if" Bug

CHDK-Skripte, CHDK-Entwicklung, PC-Zusatzprogramme, Informationen für Tüftler

"Nested if" Bug

Beitragvon BigDaddy » 10.09.2009, 19:14

Hi,

ich bin nun ganz böse über den Bug mit den verschachtelten "if"s gestolpert.

Ich hatte schon davon gelesen, dass es den geben soll. Nur klang das in den Beschreibungen aber immer so, als ob das nur bei recht wüsten Nestern auftritt und/oder ein workaround einfach ist, indem man darauf achtet, notfalls ein überflüssiges "else" einzufügen oder so.

Aber denkste! Selbst bei einer einfachen Verschachtelung wie der folgenden versagt uBasic völlig:

Syntax: [ Download ] [ Verstecken ]
Benutze uBasic Syntax Highlighting
n = 2
if n=1 then
  if 0 then
    print 1
  else
    print 2
  endif
  print 3
else
    print 4  
endif  
end
 
Erstellt in 0.005 Sekunden, mit GeSHi 1.0.8.9

Output:
2
3
4

D.h. es wird sowohl Zeile 8 als auch 10 ausgeführt, obwohl sie in verschiedenen "else"-Zweigen sind!
Wenn ich in obigem Code die Zeilen 3-7 mit "rem" auskommentiere, dann läuft es korrekt und Zeile 8 kommt nicht zur Ausführung.
(Verhält sich übrigens im "UBasic Debugger" identisch wie in der Kamera.)

Ich habe bisher keinen workaround finden können. Arrggh!

Tja, was mach' ich nun? Ich habe mir für ein spezielles Problem so einen hübschen Code ausgedacht und weiss nun aber überhaupt nicht, wie ich dessen Logik (die im Prinzip wie oben ist, nur natürlich ein wenig komplizierter; statt den einzelnen "print"s stehen da halt mehrere Codezeilen usw.) nun realisieren soll.

Gibt es vielleicht noch einen bekannten Kniff, wie man dieses Problem irgendwie vermeiden/umschiffen kann?

Grüße
BigDaddy
Grüße
BigDaddy
__________________
A620 Firmware v100f
CHDK v0.9.8-794
BigDaddy
CHDK-Einsteiger
CHDK-Einsteiger
 
Beiträge: 32
Registriert: 04.09.2009, 15:05
Wohnort: München

Beitragvon rudi » 11.09.2009, 11:45

Hallo BigDaddy,
schau Dir mal das SELECT-CASE - Statement im Handbuch an.

Möglicherweise erwartet der Interpreter beim zweitem IF-Statement zwingend einen vergleichenden Ausdruck um mit TRUE oder FALSE arbeiten zu können.
Also nicht:
Code: Alles auswählen
if 0 then
sondern z.B.
Code: Alles auswählen
if n=0 then


Rudi
Benutzeravatar
rudi
CHDK-Spezialist
CHDK-Spezialist
 
Beiträge: 510
Registriert: 11.09.2009, 11:27
Kamera(s): A590IS_101B, SX260_100B

Beitragvon BigDaddy » 11.09.2009, 13:30

Hi rudi (& gehtnix aus dem anderen Thread),

schau Dir mal das SELECT-CASE - Statement im Handbuch an.
Ja, ist womöglich die einzig sichere Möglichkeit, die Fallen zu umgehen. Aber nicht hübsch, solche Konstrukte machen zu müssen. (Insb. wegen der dann erzwungenen Benutzung von Subroutinen, selbst wenn's sich nur um zweizeilige Codestücke handelt.)

Möglicherweise erwartet der Interpreter beim zweitem IF-Statement zwingend einen vergleichenden Ausdruck
Nein, daran liegt's (leider) nicht. Das "if 0" hatte ich nur hier im Forum zur Verdeutlichung benutzt.

Mal ne andere Frage, an die Insider hier (falls das einer liest): Weiß jemand, ob an einem Fix gearbeitet wird? Ist dies ein Bug in uBasic selber oder nur in der CHDK-Variante davon? Im ersteren Fall sähe es wahrsch. düster aus, oder?
Grüße
BigDaddy
__________________
A620 Firmware v100f
CHDK v0.9.8-794
BigDaddy
CHDK-Einsteiger
CHDK-Einsteiger
 
Beiträge: 32
Registriert: 04.09.2009, 15:05
Wohnort: München

Beitragvon gehtnix » 11.09.2009, 14:10

Hi BidDaddy,

das Problem ist schon alt, existiert immer noch und wird in uBasic wohl auch so bleiben weil es ja noch LUA gibt.

Hier noch zwei alte Beiträge zu dem Thema
viewtopic.php?p=3834#3834
viewtopic.php?p=3180#3180

Erst letztens gab es ja bei Susi2Stackwieder die IF-Falle. Wenn ein "parse err" mit Angabe der letzten Zeile erscheint deutet das sehr wahrscheinlich auf einen IF-Fehler hin.

ifnix then gehtnix :lol:

gruß gehtnix
Benutzeravatar
gehtnix
CHDK-Legende
CHDK-Legende
 
Beiträge: 2406
Bilder: 8
Registriert: 17.04.2008, 12:42
Wohnort: München
Kamera(s): A610 100e+f + IXUS990 IS

Beitragvon msl » 11.09.2009, 14:28

Hallo,

endif war nicht Bestandteil der Original-uBasic-Version. Es wurde irgendwann bis zur Revision 243 eingeführt, was durch eine Verschmelzung von mehreren CHDK-Versionen nicht mehr genau nachvollziebar ist. Damals ist wohl niemand auf die Idee gekommen, kompliziertere if-Verkettungen zu kontrollieren. Ein Fix dazu ist, so glaube ich, nicht in Arbeit. Es gibt auch keinen Eintrag im Bugtracker.

Es bleibt also nur die Möglichkeit der Vermeidung dieser Verschachtelung oder die vorgeschlagene Variante mit case/select. Alternativ könnte man auch Lua benutzen. Da gibt es diese Probleme nicht.

Gruß msl
Benutzeravatar
msl
Super-Mod
Super-Mod
 
Beiträge: 4567
Bilder: 271
Registriert: 22.02.2008, 11:47
Wohnort: Leipzig
Kamera(s): A720 1.00c
SX220 1.01a

Beitragvon gehtnix » 11.09.2009, 16:28

Hi,

versteckt gibt es doch noch was zu dem Thema, fiel mir aber auch jetzt wieder erst ein.

http://chdk.kernreaktor.org/mantis/view.php?id=274

Aber da geht auch nix vorwärts, (bzw. mein Englisch ist zu schlecht um ....) Abgekürzt - den Fehler haben wir ja immer noch, also tut sich da nix.

Wobei, mit einer Einstufung auf "minor", da passiert wohl auch nix mehr.

geschmeidig bleiben

gruss gehtnix Bild
Zuletzt geändert von gehtnix am 11.09.2009, 21:17, insgesamt 1-mal geändert.
Benutzeravatar
gehtnix
CHDK-Legende
CHDK-Legende
 
Beiträge: 2406
Bilder: 8
Registriert: 17.04.2008, 12:42
Wohnort: München
Kamera(s): A610 100e+f + IXUS990 IS

Beitragvon BigDaddy » 11.09.2009, 18:43

Hi an alle,

vielen Dank für die vielen Infos!

Bei der Lektüre der Detektivarbeit von letztem Jahr wurde mir schwindelig. Was für ein Graus! Gut zu wissen...

Ich finde, da sollte aber eine sehr viel deutlichere Warnung im Manual stehen. Der volle Umfang des/der Bug(s) ist wohl viel größer als die Warnung dort vermuten lässt.

Wäre wirklich sehr schade, wenn man das nicht fixen könnte. Ich finde, das gehört auf der Todo-Liste eigentlich ganz nach oben.
Grüße
BigDaddy
__________________
A620 Firmware v100f
CHDK v0.9.8-794
BigDaddy
CHDK-Einsteiger
CHDK-Einsteiger
 
Beiträge: 32
Registriert: 04.09.2009, 15:05
Wohnort: München

Beitragvon rudi » 12.09.2009, 12:46

Hallo,
ich habe mir mal die ubasic.c angesehen und zwei Stellen gefunden (Zeile 746 - if_statement; Zeile 805 - else_statement) die mir nicht ganz klar sind. In beiden Fällen handelt es sich um die gleiche Abfolge von Befehlen
Code: Alles auswählen
          accept(TOKENIZER_CR);
                  .
                  .
                tokenizer_next();
                while ...

Meiner Meinung nach wird an dieser Stelle ein Zeilenende als "Gültig" erklärt (accept...) und bei entspechenden Bedingungen der Abarbeitungszeiger mit "tokenizer_next" auf den nächsten Token gesetzt. Nun beinhaltet der "accept"-Befehl (ab Zeile 144) am Ende doch schon ein "tokenizer_next". Sollte das nicht dazu führen, dass ein Token nicht ausgewertet wurde (eben übersprungen)?

Gruß Rudi
Benutzeravatar
rudi
CHDK-Spezialist
CHDK-Spezialist
 
Beiträge: 510
Registriert: 11.09.2009, 11:27
Kamera(s): A590IS_101B, SX260_100B

Beitragvon rudi » 12.09.2009, 18:20

Hallo Scripter,
ich habe mir jetzt mal mehr Zeit genommen und den Quelltext (ubasic.c) der IF-THEN-ELSE-Statements angesehen.
Als erstes ist zu sagen, es sind zwei Varianten implementiert.
1. Die ursprüngliche Version in einer Zeile mit IF - THEN - ELSE !!!ABER OHNE ENDIF!!!.
2. Die Erweiterung mit ENDIF, dabei müssen IF <Ausdruck> THEN, ELSE und ENDIF jeweils auf einer eigen Zeile stehen.

Folgende Situationen sollten Probleme bereiten.
1. Ein IF-THEN-ELSE-ENDIF auf einer Zeile
Hier ist das Problem beim ENDIF. Dort wird der IF-Stack um eins veringert. Dieser IF-Stack merkt sich die Anzahl der Angefangen IF-Anweisungen und das Ergebnis der jeweiligen Bedingung, aber nur für die Erweiterte Variante! Die ursprüngliche Variante verwendet diesen IF-Stack nicht. Zum Glück gibt es ja noch ein Zähler für diesen IF-Stack, so dass bei einfacher Anwendung nichts passiert. Allerdings kann es zu anderen Fehlfunktionen kommen. Ein Beispiel:
Code: Alles auswählen
1: IF <Ausdruck1> THEN
2:   IF <Ausdruck2> THEN <Anweisung> ENDIF
3: ELSE
4:   <Anweisung>
5: ENDIF

Beim Ausführen von ENDIF in Zeile 2 wird der IF-Stack um einen Eintrag veringert. Da die IF-Anweisung aus Zeile 2 dort keine Werte hinterlegt hat, verfallen die Werte der IF-Anweisung aus Zeile 1. Und wie soll Zeile 3 nun wissen, ob Zeile 4 ausgeführt werden solll?

2. Mischen beider Varianten
Ein Beispiel:
Code: Alles auswählen
1: A=10
2: IF A>10 THEN
3:   REM ursprüngliche Version ohne ENDIF
4:   IF <Ausdruck2> THEN <Anweisung>
5: ELSE
6:   <Anweisung>
7: ENDIF

Hier ist Zeile 4 richtig verwendet, aber auch Ursache. Aufgund der Parameter wird der ELSE-Zweig ausgeführt. Dazu müssen die Zeilen 3, 4 übersprungen werden. Das erfolgt mit einem Lesemechanismus der auch gültige Token angibt, bis eben zum ELSE in Zeile 5. Damit nicht am faschen ELSE weitergearbeitet wird zählt eine Variable die IF's und dazugehörigen ENDIF's der dazwischenliegenden IF-Anweisungen. Nun hat die Zeile 4 ja kein ENDIF. Ich nehme an, dass ein ELSE nach Zeile 7 ausgeführt werden würde.

Diese Infos können evtl. einige Sriptprobleme erklären.

Gruß Rudi
Benutzeravatar
rudi
CHDK-Spezialist
CHDK-Spezialist
 
Beiträge: 510
Registriert: 11.09.2009, 11:27
Kamera(s): A590IS_101B, SX260_100B

Beitragvon BigDaddy » 12.09.2009, 20:57

Wahnsinn, rudi! Erst dein 4. Posting und gleich so ein Ding! 8)
Super, dann gibt's ja jetzt einiges zum ausprobieren. (Nur blöde, dass gerade heute abend meine Frau von ihrer Reise zurückkommt :roll: )

Den kleinen Java-Debugger kennst du schon? http://www.zenoshrdlu.com/kapstuff/zubdb.html
Nach meinen bisherigen Erfahrungen verhält der sich identisch, ist also zum Testen wahrsch. praktisch.
Grüße
BigDaddy
__________________
A620 Firmware v100f
CHDK v0.9.8-794
BigDaddy
CHDK-Einsteiger
CHDK-Einsteiger
 
Beiträge: 32
Registriert: 04.09.2009, 15:05
Wohnort: München

Beitragvon gehtnix » 12.09.2009, 22:52

Hallo Rudi,

da kann ich BigDaddy nur zustimmen, Wahnsinn 8) und =D>

Ich habe mir den letzten "IF-Vorfall" angesehen. Da fehlt ja hier "if Z>10 then goto "restore" " das endif. Würde jetzt statt goto ein gosub hier stehen würde der Fehler wohl nicht mehr auftauchen weil der Stack aufgelöst wird(?).

Ich denke mal dass ich mit meiner Vermutung richtig liege, dass, wenn ein unaufgelöstes IF auftritt, die Fehlermeldung "Pars err" mit Angabe der letzten Zeile erscheint? Der versucht halt den Stack aufzulösen. Und wenn er es nicht kann gibt er halt die letzte Zeile aus.

Es bleibt spannend...


BigDaddy hat geschrieben:(Nur blöde, dass gerade heute abend meine Frau von ihrer Reise zurückkommt :roll: )
Irgendwas is allweil :roll:

gruß gehtnix
Benutzeravatar
gehtnix
CHDK-Legende
CHDK-Legende
 
Beiträge: 2406
Bilder: 8
Registriert: 17.04.2008, 12:42
Wohnort: München
Kamera(s): A610 100e+f + IXUS990 IS

Beitragvon BigDaddy » 13.09.2009, 10:10

Hi alle,

[EDIT: sorry, Untenstehendes war Fehlalarm. Ist anscheinend nur ein Bug im Debugger. Autsch...]

hatte/habe heute kaum Zeit, aber es wird immer schlimmer! :shock: Es gibt anscheinend zusätzlich auch einen "gosub-Bug", der mit dem if-Bug gar nix zu tun hat.

Um die if-Sache etwas systematisch untersuchen zu können, habe ich mir Testcode wie diesen hier geschrieben:

Code: Alles auswählen
rem Testing IF constructs
@title TestIF01

a=0
b=0
gosub "tryif"
a=0
b=1
gosub "tryif"
a=1
b=0
gosub "tryif"
a=1
b=1
gosub "tryif"

end

:tryif
print ""
print ""
print "case", a, b
if a then
   print "a is true"
   if b then print "b is true"
else
   print "a is false"
endif
return


Nun ist mir beim Singlesteppen aufgefallen, dass bereits nach dem ersten Durchlauf nach dem return nicht an die richtige Zeile zurückgekehrt wird. Statt zu Zeile 7 wird zu Zeile 8 gesprungen!

Und das hat mit der Verwendung des IF in der Subroutine gar nix zu tun. Das passiert immer!
Das bedeutet wohl, dass man nach einem "gobub" immer eine rem-Zeile einfügen muss! (Leerzeile genügt nicht, die ignoriert der Parser.)

War denn das bisher schon bekannt?

P.S.: bisher nur im Debugger ausprobiert ...
Grüße
BigDaddy
__________________
A620 Firmware v100f
CHDK v0.9.8-794
BigDaddy
CHDK-Einsteiger
CHDK-Einsteiger
 
Beiträge: 32
Registriert: 04.09.2009, 15:05
Wohnort: München

Beitragvon BigDaddy » 13.09.2009, 11:28

Hi,

bin mit der Analyse deutlich weitergekommen. Folgendes ist der Testcode (ist derselbe wie vorher, nur mit zuätzlichen "rem"s wg. des Debugger-Bugs):

Code: Alles auswählen
rem Testing IF constructs
@title TestIF01

a=0
b=0
gosub "tryif"
rem
a=0
b=1
gosub "tryif"
rem
a=1
b=0
gosub "tryif"
rem
a=1
b=1
gosub "tryif"
rem

end

:tryif
print ""
print ""
print "case", a, b
if a then
   print "a is true"
   if b then print "b is true"
else
   print "a is false"
endif
return


Test A: Bereits der erste Durchlauf (mit (a,b) = (0,0)) liefert in Zeile 27 einen "parse error in line 34" (also einer Zeile, die es gar nicht gibt!)

Test B: Auskommentieren von Zeile 29 (der inneren IF-Abfrage): alles läuft korrekt (nicht anders erwartet).

Test C: In Zeile 29 ein "endif" angehängt: Problem wie in Test A tritt nicht mehr auf. Dafür aber im Fall (1,1) ein parse error bei Zeile 29/30.

Test D: In Zeile 29 zusätzlich noch ein überflüssiges "else" (also "if b then print ... else endif"): Gibt nie einen parse error, aber im Fall (1,0) wird zum falschen else-Zweig gesprungen (Zeile 31 wird ausgeführt).

Test E: Die innere if-Abfrage als Mehrzeiler ausgelegt (mit endif natürlich): ALLES OK. Auch dann noch, wenn ich dort einen else-Zweig hinzufüge:

Vorläufige (mich hoffnungsvoll stimmende, weil ganz einfache) Hypothese also:

Innere if-Abfragen sind immer fehlerhaft wenn Einzeiler, aber immer korrekt wenn Mehrzeiler!

Wäre schön, wenn jemand versuchen könnte, das zu veri-/falsifizieren.

(so, jetzt erstmal Pause, muss mit Frauchen gassigehen...)
Grüße
BigDaddy
__________________
A620 Firmware v100f
CHDK v0.9.8-794
BigDaddy
CHDK-Einsteiger
CHDK-Einsteiger
 
Beiträge: 32
Registriert: 04.09.2009, 15:05
Wohnort: München

Beitragvon BigDaddy » 13.09.2009, 11:34

Hi,

noch ganz kurz, nur zur Info:

Habe dem Entwickler von UBDebug den o.g. Bug gemeldet, und er hat schon geantwortet:
thanks for the bug report and kind words. You're right, though the SDM version doesn't have this bug. I think I know where the problem is and will fix asap.

Allerdings keine Ahnung, was die "SDM-Version" ist. Weiß das jemand?
Grüße
BigDaddy
__________________
A620 Firmware v100f
CHDK v0.9.8-794
BigDaddy
CHDK-Einsteiger
CHDK-Einsteiger
 
Beiträge: 32
Registriert: 04.09.2009, 15:05
Wohnort: München

Beitragvon rudi » 13.09.2009, 11:57

Hallo,
inspiriert durch BigDaddy und aus meinen Erkenntnissen stelle ich mal folgende These auf:

"Die IF-Anweisung arbeitet in der jetzigen Implementierung fehlerfrei wenn ..."
1. Es wird ausschließlich die erweiterte Version verwendet, also hinter THEN und ELSE keine weiteren Anweisungen.
2. Die Folgezeile nach THEN und ELSE muss eine REM-Zeile sein.
3. Das abschließende ENDIF steht immer alleine auf einer Zeile.
4. Der ELSE-Zweig bleibt natürlich optional.

Ach so und denkt daran, die Anzahl der offenen IF-Anweisungen darf nicht größer 4 sein.

@BigDaddy
An einen GOSUB-Bug glaube ich nicht, dazu ist die IF-Anweisung zu anfällig.
SDM (StereoData Maker) ist eine CHDK-Version für Stereo-Fotografie.

Gruß Rudi
Benutzeravatar
rudi
CHDK-Spezialist
CHDK-Spezialist
 
Beiträge: 510
Registriert: 11.09.2009, 11:27
Kamera(s): A590IS_101B, SX260_100B

Nächste

Zurück zu Code-Ecke

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 6 Gäste