Enkla men fatala buggar

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Micke_s
EF Sponsor
Inlägg: 6741
Blev medlem: 15 december 2005, 21:31:34
Ort: Malmö

Re: Enkla men fatala buggar

Inlägg av Micke_s »

Något är lustigt i alla fall i görningen.
Användarvisningsbild
JimmyAndersson
Inlägg: 26308
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Re: Enkla men fatala buggar

Inlägg av JimmyAndersson »

Ingen bugg, men ett trick för att toggla (invertera) en logisk (boolsk) variabel:

variabel = !variabel (notera utropstecknet)

Alltså t.ex: true = inte true. Dvs false
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

Och ett sätt at konvertera t.ex 5 till 0 eller 0 till 1 .. helst utan att man tänker på det ;)
Användarvisningsbild
Micke_s
EF Sponsor
Inlägg: 6741
Blev medlem: 15 december 2005, 21:31:34
Ort: Malmö

Re: Enkla men fatala buggar

Inlägg av Micke_s »

Hittade felet, stacken krockar med programminnet. kör allt i ram:et.
Användarvisningsbild
JimmyAndersson
Inlägg: 26308
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Re: Enkla men fatala buggar

Inlägg av JimmyAndersson »

bit96 skrev:
blueint skrev:Så här kan man också göra:

Kod: Markera allt

unsigned char ch;
if( ch == 0x81 )
  printf("Seems it's an unsigned day today ;-)\n");
blueint: Ja, men nu glömde du att klamra in det som kommer efter "if()".
Inte nödvändigt, men rekommenderat för att undvika fatala buggar.
:)

Apropå det så finns det ju fall där det faktiskt inte behöver vara något mellan klamrarna.
Ett exempel för att omvandla string till int hyfsat felsäkert:

string aaa;
int bbb;
if (int.TryParse(aaa, out bbb)) {}

Om aaa är siffror i en sträng så hamnar siffrorna i bbb. Inte annars.
Nu har man inte så nytta av själva exemplet i µC-sammanhang,
men det visar att man bör funderar lite extra över sina if-satser.

Vissa miljöer hanterar dessutom => på ett annat sätt än >=. :)
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

Om man anropar en funktion rekursivt för många gånger kan man få slut på stack utan någon vidare förvarning..

Kod: Markera allt

func(int n){
printf("%d\n",n);
return func(n+1);
}

int main(){
func(0);
}
Test på x86 fbsd+gcc gav 2 096 966 rekursioner, dito på SunOS 5 gav 74 852 rekursioner. En viss Borland kan stanna vid cirka 8000..
jappelino_1
Inlägg: 81
Blev medlem: 13 april 2010, 14:40:04
Ort: Stockholm

Re: Enkla men fatala buggar

Inlägg av jappelino_1 »

liknande situation med en ganska lång diskussion som jag "förlorade": http://msp430-discuss.996251.n3.nabble. ... tml#a26857

Det som jag tycker är lite konstigt är att kompilatorn var satt till att inte optimera koden men ändå gjorde det.

Jag tror jag löste det med några fula globala variabler istället.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Enkla men fatala buggar

Inlägg av sodjan »

Blueints kod ger (förrutom en stack-overflow så klart vid runtime) en del andra varningar.
OK, det kanske var förväntat och enbart om man slår på lite extra kontroller... :-)
Jag fick även lägga till en include av stdio.

För övrigt smällde det av vid ca 2.3 M varv, men det är ju enbart en funktion av
storleken på stacken så det är ganska ointressant och det är kanske lite tveksamt
hur mycket det beror på de olika plattformarna/kompilatorerna att göra.

Kod: Markera allt

$ cc rekurs/warn=(enab=level6,verbose)

func(int n){
^
%CC-I-DEFRETURNTYPE, The type of the function func defaults to "int".
at line number 2 in file USER:[JANNE]REKURS.C;2
Description: A function definition did not include a type specifier for the function's return value. 
It will default to int. This might not be what you intend. This is also a violation of the C99 Standard. 
User Action: It is a good programming practice to give all function definitions explicit return types. 

printf("%d\n",n);
^
%CC-I-IGNORECALLVAL, In this statement, the value returned from the function "printf(...)" is not used
- if this is intended, it should be cast to "void".
at line number 3 in file USER:[JANNE]REKURS.C;2
Description: A function that returns a value has been invoked, yet the value was not used.
This might not have been what you intended. 
User Action: Cast the function to void to suppress the message. 

int main(){
....^
%CC-I-NOPARMLIST, The declaration of the function main has an empty parameter list.
If the function has parameters, they should be declared here; if it has no parameters,
"void" should be specified in the parameter list.
at line number 7 in file USER:[JANNE]REKURS.C;2
Description: The recommended way to declare a function that takes no parameters is to use "void" in the parameter list. 
User Action: Make the recommended change. 

func(0);
^
%CC-I-IGNORECALLVAL, In this statement, the value returned from the function "func(...)" is not used
- if this is intended, it should be cast to "void".
at line number 8 in file USER:[JANNE]REKURS.C;2
Description: A function that returns a value has been invoked, yet the value was not used.
This might not have been what you intended. 
User Action: Cast the function to void to suppress the message. 
$ 
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: Enkla men fatala buggar

Inlägg av johano »

Vill bara tipsa om en bok som jag tyckte var rätt bra när jag läste den för ca. 20 år sen: "Writing Solid Code - Microsoft's Techniques for Developing Bug-Free C Programs" av Steve Maguire.

Det verkar finnas en online pdf-version här, vet inte lagligheten i den länken dock:
vmg.pp.ua/books/../Microsoft/Microsoft Press - Writing Solid Code.pdf

/johan
Senast redigerad av blueint 5 juni 2013, 15:51:38, redigerad totalt 1 gång.
Anledning: urltrim
jappelino_1
Inlägg: 81
Blev medlem: 13 april 2010, 14:40:04
Ort: Stockholm

Re: Enkla men fatala buggar

Inlägg av jappelino_1 »

Ett till boktips:

Han har fått mycket bra recensioner, själv har jag bara kommit in en bit i boken, men så långt verkar det lovande.
Användarvisningsbild
bit96
Inlägg: 2492
Blev medlem: 3 september 2007, 10:04:29
Ort: Säffle

Re: Enkla men fatala buggar

Inlägg av bit96 »

JimmyAndersson skrev: Apropå det så finns det ju fall där det faktiskt inte behöver vara något mellan klamrarna.
Ett exempel för att omvandla string till int hyfsat felsäkert:

string aaa;
int bbb;
if (int.TryParse(aaa, out bbb)) {}
Och här kan/bör man t.ex. skriva nåt i stil med:

Kod: Markera allt

string aaa;
int bbb;
if (int.TryParse(aaa, out bbb)) { /* Tomt här! Beräkning sker i själva if()-villkoret */}
Annars har man efter några månader helt glömt varför man har ett par tomma klamrar här. :humm:
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: Enkla men fatala buggar

Inlägg av johano »

Eller bara strunta i IF-satsen helt och hållet:

Kod: Markera allt

string aaa;
int bbb;
int.TryParse(aaa, out bbb);
Men, då tråden handlar om buggar så kommer ju frågan om man kan vara säker på att konverteringen
verkligen lyckas varje gång?

/johan
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

Denna kodsnutt borde överlasta stacken utan alltför mycket varningar ;)

Kod: Markera allt

int func(int n){
(void)printf("%d\n",n);
return func(n+1);
}

int main(void){
(void)func(0);
return 0;
}
Att missa deklerationen av funktionens returvärde kan nog också ses som fatalt om man inte ser upp. Det övriga är av ringa betydelse.

@johano, Alltså vet man inte.. ;) antingen får man köra if() och göra något åt det. Eller senare kontrollera indatat. Alternativt shit-happens ;)
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Enkla men fatala buggar

Inlägg av sodjan »

> Denna kodsnutt borde överlasta stacken utan alltför mycket varningar

Det kompilerade och länkade utan diagnostiska meddelanden... :-)
Däremot vet i fanken varför det aldrig stannar. Räknaren slår runt
och det bara fortsätter... :humm:

Aha! :-)
Det visade sig att funktionen optimerades till inline kod utan några CALL's
(förrutom till printf) och stacken kraschade så klar aldrig:

> 1. Inlining func into main

Det blev bara *8* maskininstruktioner kvar (plus lite init och exit kod som aldrig körs) av det hela.
Ja, printf koden körs ju också så klart...

Kod: Markera allt

             0030       L$2:
A7420020     0030               LDQ     R26, 32(R2)
47E30411     0034               MOV     n, R17                                  ; R3, R17
47E05419     0038               MOV     2, R25
22020030     003C               LDA     R16, 48(R2)
A7620028     0040               LDQ     R27, 40(R2)
40603003     0044               ADDL    n, 1, n                                 ; R3, 1, R3
6B5A4000     0048               JSR     R26, DECC$GXPRINTF                      ; R26, R26
C3FFFFF8     004C               BR      L$2
Med /NOOPTIMIZE så kraschade det med en ACCVIO (Access Violation, d.v.s
normalt en skrivning till read-only minnesområde) efter ca 1.5 M varv... :-)
Efter att ha ökat virtuella minnet för usern så gick det ca 15.5 M varv.
Processen växer dynamiskt när det behövs mera (t.ex) stack tills det slår i taket...
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

Kan man få till den icke optimerade varianten utan att mixtra kompilator optioner?
Skriv svar