Second Formal Report
Second Formal Report
TECHNOLOGIES
P00401: Formal Software Engineering
Course Work Two
MOHAMMED AL-SADI
14075351
Friday, November 29, 2014
1) Write a mathematical expression that related a date in the form year, month, day to
days since January 1st, 1980. You might find it convenient to express this in the
syntax of Spec#.
Inputs:
dd: Given date.
mm: Given month.
yy: Given year.
Days =
(dd-1) +
daysInYear(i) +
daysInMonth(i,yy)
2- DaysInMonth(int y, int m) ; It returns the number of days in given year (int y) and Given
month (int m);
sum {int k in (1:month-1) ; DaysInMonth (year,k) } // include all the months except the
current month
4) Following the methods taught in the formal-derivation part of the module, derive
an implementation of the method DaysSince1Jan1980 and annotate it with suitable
loop invariants to show its partial correctness.
Hint: You will find it easiest to implement this in two parts: firstly summing the days
in the whole years since 1980 and then the days since the start of year y.
You may use material from the modules formal-derivation lectures without
acknowledgement.
/* I have my own auxiliary functions */
DaysIn(y,m integer): integer;
DaysInYear(y integer): integer;
/* I have my own auxiliary functions */
(*PRE: year1980 && 1month12 && 1dayDaysIn(year,month)*) //Pre
y=1980 ; m=1 ; totalDays=0 //Initi
(*inv: DaysSince1Jan1980 = (i:1980<=i<=y-1.DaysInYear(i)) *)
while y year do
(*inv& (yyear))*)
if( isLeapYear(y) ) {
totalDays: totalDays +366}
else{
totalDays: totalDays +365}
y:y+1
(*inv *)
end
(*inv&(~ yyear) post*)
(*Inv: DaysSince1Jan1980 = (i:1<=i<=month-1 .DaysIn (year,i )) *)
while m month do
(* inv&(mmonth) *)
totalDays: totalDays + DaysIn(m,year)
m:m+1
(* inv *)
end
(*inv&(~ ymonth) post*)
totalDays = totalDays + day
(*Post: (i:1980<=i<=y-1.DaysInYear(i)) +
(i:1<=i<=month-1 .DaysIn (year,i )) + day-1
*)
5) Identify a suitable bound function for each loop in your method and explain your
choice.
First loop:
bound=(year-y)
The bound function is year-y because with every loop the year
Second loop:
bound=(month-m)
6) Augment the annotation of your implementation to show its total correctness.
DaysSince1Jan1980 (year, month, day)
(*year1980 && 1month12 && 1dayDaysIn(year,month)*) //Pre
y=1980 ; m=1 totalDays=0 //Initi
(*inv: DaysSince1Jan1980 = (i:1980<=i<=y-1.DaysInYear(i)) & (year-y)>0*)
while y year do
(*inv& (yyear) & bound=(year-y)*)
if( isLeapYear(y) ) {
totalDays: totalDays +366}
else{
totalDays: totalDays +365}
y:y+1
(*inv& (year-y)<bound*)
end
(*inv&(~ yyear)=>post*)
(*Inv: DaysSince1Jan1980 = (i:1<=i<=month-1 .DaysIn (year,i )) &(month-m)>0
*)
while m month do
(* inv&(mmonth)&bound=(month-m)*)
totalDays: totalDays + DaysIn(m,year)
m:m+1
(* inv & (month-m) < bound*)
end
(*inv&(~ ymonth)=>post*)
totalDays = totalDays + day
(*Post: (i:1980<=i<=y-1.DaysInYear(i)) +
(i:1<=i<=month-1 .DaysIn (year,i )) + day-1
*)
(*INV *)
}
// end of loop
(*INV & ~( days365 && !(days==365 && isLeapYear(year)) *)
(*POST 1 days<365 *)
(*INV: 1 days=days-daysInMonth(month,year) *)
While (days >= daysInMonth(month,year)) {
// month calculation if current day days in current month
add one month
(*INV & (days>= daysInMonth(month,year)) *)
days=days-daysInMonth(month,year);
month++;
(*INV *)
}
//end of loop
(*INV & ~ (days >= daysInMonth(month,year)* )
(*post: days< daysInMonth(month,year) *)
day = day + days; // add the extra days
9) Study the some of the many posts about the Zune bricking code. Criticise them
where you think they are wrong or poorly expressed or where the corrections offered
are either wrong or messy.
The post from Brian Hayes in his blog (2009) is an interesting material because he has
also criticized other posts. Going through his post allows criticizing more than one view at
the same time. After the introduction of the problem and the quote of the original source
code, Hayes spotted the problem technically, and described it clearly. He supposed the case
when the value of days is 366 and traced the code. After that he said:
This is just what happened on December 31, 2008, which was day 10,593 in Zune time. The
bug would be triggered on the last day of any leap year; it wasnt observed before now
simply because the Zune didnt yet exist the last time February had 29 days.
Brian Hayes(2009)
Then he directly moved to criticize others posts. Hayes didnt describe the problem of the
code from a general view. Assuming the case when the variable days equal 366 is enough for
spotting the bug in 31 Dec 2008. A critical part missing from Hayess description is why the
code doesnt crash while the year is 1980? The code start counting from 1980 (leap year) and
goes till 31 Dec 2008 then crash. The code doesnt crash on 1980 and all the following 6
years (84,88,02,04), which is the missing part that Hays didnt, explored clearly.
The first two solutions that Hayes criticized are wrong. The third one is a good solution but
Hayess notion of using break statement is interesting. Hayes considered using a break
statement is not a good practice. He didnt justify his view of not using break statement but
formally he was right. In formal method, using the break clause means the guard will still
true after the loop. Well, the guard must be not true after the loop execution to get the right
post condition. (*post: Inv & ~(guard) *)
Hayes solution:
Below, the code by Brian to solve the problem.
year=ORIGINYEAR;
while(days>0)
{
if(IsLeapYear(year))
days=366;
else
days=365;
if(days>0)
year+=1;}
Hayes proposed this solution, which works very well in 31 Dec 2008 and any following year.
However, it is not general and cant be used in earlier days. The final result of the variable
days would be a negative number, which is a fatal error. He mentioned that later and
proposed another solution on Lisp. The problem with his Lisp solution that the code starts
counting from 1979, which is the idea that he had already rejected before when he said:
I suppose I consider this an improvement over the alternatives given above, but I dont
really like it. What annoys me most is the trick of initially setting year to ORIGINYEAR - 1.
This violates an implicit assumption that year will always be equal to or greater than 1980.
Brian Hayes has proposed some well-documented solution especially the Lisp solution. Well
he hasnt addressed how he solved the problem clearly. Another issue is his Lisp solution
considers the original year 1979. Which is not the case in Zune code, because the Zune
counts the days given the number of days since 1980. Which means his solution will not
work in Zune.
Another post to consider is by Steven Pigeon (2008) blog. He has provided brief overview of
when the code will crash and why. He has also proposed an interesting ways of testing the
code before releasing it. There is a completed testing code by him. Unfortunately it is not
enough to provide a solution for this problem rather than it is useful to know how to detect
this bug. Compared to Brian Hayes (2009) post, Pigeon did more tests to aid how to detect
the bug than Brian. In the other hand, Brian has provided a wide range of solution although
they arent satisfied.
10) Devise your own explanation of what is wrong with the Zune code, making reference to
the ideas of formal derivation.
The problem with the zone code may happens in any current leap year and to understand
whats go wrong with code lets me down these 2 rules that could be inferred from the Zune
code (The bugged version):
1-In the case of common year and 365 days or more; add new year and subtract 365.
2- In the case of leap year and 367 days or more; subtract 366 days and add new year.
The problem related to the 2nd rule. What would happen if it is leap year and the days equal
366? The code clearly says, DO NOTHING! technically go in loop for about 24 hours.
Below a simple tracing for the code using the figure.
In term of formal program derivation, terminating loop must be done using suitable bound
function.
At 31 Dec 2008 when days =366, the first IF guard will be satisfied because 2008 is a leap
year, but the internal IF will not because days are equal to 366 not greater.
The problem here there is no bound function executed in case we havent satisfied the
internal IF which causes the infinite loop. So the number of days will not go down to exit the
loop and the value of days will remain the same and the loop will never exit.
The last question here is, In 2012, will the code crash in 2008 or only in 2012?
Well, both of 2012 and 2008 are leap years, but when we are in 31 Dec 2012, and while the
code is counting days from 2008, the days will be more than 367 in 31 Dec 2008 (actually,
366+(days of 2009,2010,2011 and 2012)). So it will handle the leap year 2008 correctly. In
31 Dec 2012 the days will be exactly 366 and the code will crash. In formal programming,
the bound must not remain the same. If the bound remains the same while executing the loop,
the loop will not exit, which is the problem with Zune code. Specifying suitable bound (that
changes in any loop repartition) and handling the selection statement correctly could prevent
the errors in Zune code.
Part II:
REFERENCES
Hayes,B. (2009) 'The Zune Bug', bit-player, 3 January. Available at: http://bitplayer.org/2009/the-zune-bug (Accessed: 30 November 2014).
Pigeon,S. (2008) 'The Zune Freezes: A Stupid, Avoidable Bug. ', Harder, Better, Faster,
Stronger, 31 December. Available at: https://hbfs.wordpress.com/2008/12/31/the-zunefreezes-a-stupid-avoidable-bug/ (Accessed: 30 November 2014).
Abrial, J. (2006) 'Formal methods in industry: achievements, problems, future.', Proceedings
of the 28th international conference on Software engineering,2006 pp. 761-768. doi:
10.1145/1134285.1134406
Abrial, J. R. (2010). Modeling in Event-B: system and software engineering. Cambridge
University Press.
'Declarative programming' (2014) Wikipedia. Available at:
http://en.wikipedia.org/wiki/Declarative_programming (Accessed: 30 November 2014).
'Design by contract' (2014) Wikipedia. Available at:
http://en.wikipedia.org/wiki/Design_by_contract (Accessed: 30 November 2014).
Barnett, M., Leino, K. & Schulte, W. (2005) 'The Spec# programming system: An overview.
', Construction and analysis of safe, secure, and interoperable smart devices, 2005. 49-69.
Badeau, F & Amelot, A. (2005) ' Using b as a high level programming language in an
industrial project: roissy VAL ', Proceedings of the 4th international conference on Formal
Specification and Development in Z and B (ZB'05),2006, pp. 334-354. doi: 10.1007/11415787_20