CS 395T: Systems Verification and Synthesis Spring 2022

Homework 4: Dafny

Due date: April 12, 11pm
Grading: 5% of your course grade: 2% for Part 1 (basic scheduler), 2% for Part 2 (smarter scheduler), 1% for Part 3 (scheduler correctness)

Dafny is a verification-ready programming language. It's an imperative language, vaguely influenced by C#, but with built-in automatic verification to check the correctness of your code as you write it. Once your code is confirmed to be correct by the Dafny verifier, it can be automatically compiled to languages like C#, Go, or JavaScript.

In this homework we'll use Dafny to explore some variations on a verified operating system scheduler, similar to one in the seL4 verified OS kernel that we read about in lecture recently. We'll implement two schedulers, prove them correct against some higher-level specifications, and then think a little about what types of bugs our verification does and does not preclude.

Table of contents

Prerequisites

We'll be working with Dafny in this homework, so the first step is to it set up on your system.

I strongly suggest using Visual Studio Code to complete this homework, as it has a full-featured Dafny integration with many nice features. Regardless of operating system, install Visual Studio Code before going any further.

Now install the Dafny VSCode extension by clicking the Install button on its homepage or by searching for dafny-lang.ide-vscode in VSCode's extension pane. Make sure you get the right extension, as there are some deprecated ones still available—the one you're looking for is authored by "dafny-lang" rather than "Correctness Lab".

Next, follow the appropriate instructions below for your system to get the extension fully set up. If any of the instructions are unclear, see the official Dafny installation instructions for more detailed help.

macOS

First, install the .NET 6.0 SDK using Homebrew:

brew install dotnet-sdk

If you have an Intel Mac, you're done. The first time you open a .dfy file in VSCode, the Dafny extension will automatically download and install the latest Dafny release.

If you have an Apple Silicon Mac, unfortunately, there's a little more work to do as the Dafny VSCode extension doesn't yet recognize these Macs correctly. I've prepared a Dafny release for Apple Silicon Macs that you need to download and extract somewhere on your system (here I'm going to assume you extracted it to the folder /Users/bornholt/dafny, so for example you have a file /Users/bornholt/dafny/Dafny.dll). Now open the Settings UI in VSCode (press Cmd + Shift + P, search for "settings ui", press enter). Search for "dafny" in the settings UI. Set the "Dafny: Compiler Runtime Path" to /Users/bornholt/dafny/Dafny.dll, and set the "Dafny: Language Server Runtime Path" to /Users/bornholt/dafny/DafnyLanguageServer.dll.

Now once you open a .dfy file, the Dafny extension should be able to find your new Dafny installation and use it. If you instead see an error like "The Dafny Language Server server crashed 5 times", something went wrong—make sure you got all the paths right.

Linux

Install the .NET 6.0 SDK by following the instructions for your distribution.

That should be all you need to do. The first time you open a .dfy file in VSCode, the Dafny extension will automatically download and install the latest Dafny release.

Windows

Nothing more to do! The first time you open a .dfy file in VSCode, the Dafny extension will automatically download and install the latest Dafny release.

Set up the code

We'll be using GitHub Classroom to check out and submit this homework. Follow the GitHub Classroom URL on Canvas to create your private copy of the homework repository, and then clone that repository to your machine. For example, the repository it created for me is called hw4-dafny-jamesbornholt, so I would do:

git clone git@github.com:cs395t-svs/hw4-dafny-jamesbornholt.git
cd hw4-dafny-jamesbornholt

To make sure everything's working, open the Scheduler.dfy file from this directory in VSCode. You should see "Verification Failed" in the bottom left of the window (in the status bar), and some red squiggly underlines scattered around the file. You'll know you've finished the homework when you see "Verification Succeeded"!

Part 1: A basic scheduler

We're going to write specifications and implementations for an operating system scheduler, vaguely inspired by Figures 3 and 4 in the seL4 paper we read recently.

Open Scheduler.dfy. It comes with a bunch of code already written for you. You shouldn't modify any code other than that annotated with TODO comments.

First, there's a class called Task that we'll use as the unit of actions being scheduled by the scheduler. Tasks have an ID and can be in one of two states—runnable or not runnable.

Second, there's a trait called Scheduler. Think of traits like you would think of interface in Java—they're abstract definitions of what a class should do. Here, the Scheduler trait defines the interface to a scheduler implementation. A scheduler maintains a list (a seq, in Dafny terms) of tasks it is managing, as well as a field next pointing to the currently scheduled task (or null if no task is currently scheduled). A scheduler has two methods:

Third, we have a class called BasicScheduler that implements the Scheduler interface.

For part 1, your task is to finish the implementation of BasicScheduler, and in particular, to fill in its Next implementation. The BasicScheduler is a not a very good scheduler: it should always schedule the first task in tasks, even if that task is not runnable.

Fill in the missing postcondition for Next as well as its body, such that Next returns true only if there are no tasks to run. Do not modify any of the other annotations or the Valid predicate. You'll know you're done when Dafny can prove all the postconditions of Next, and can also verify the three test methods whose names start with TestBasicScheduler.

A couple of hints to get you started:

Part 2: A slightly smarter scheduler

Now let's take a look at the RunnableScheduler. This is a scheduler that goes just one step further than BasicScheduler: it should always schedule the first runnable task (a task such that task.runnable == true); if there are no runnable tasks under the control of the scheduler, it will idle.

In the RunnableScheduler, fill in the missing postcondition for Next as well as its body, such that Next returns true if and only if there are no runnable tasks. Do not modify any of the other annotations or the Valid predicate. You'll know you're done when Dafny can prove all the postconditions of Next, and can also verify the three test methods whose names start with TestRunnableScheduler.

A couple of hints on this one:

Part 3: Scheduler correctness

Although we've now proven the correctness of two schedulers, there's a very significant issue with both of them, such that no real (or even toy) operating system would consider them "correct".

  1. What is the issue, and why does our proof say they are correct despite suffering this issue?
  2. Does seL4's scheduler proof (the example in Figures 3 and 4 of the paper) have the same problem?
  3. What could we do about it?

Answer these three questions by writing a comment in the Part3 method in Scheduler.dfy. No need to write too much—a sentence per question should be enough.

What to submit

Submit your solutions by committing your changes in Git and pushing them to the private repository GitHub Classroom created for you in the Set up the code step. If you haven't used Git before, Chapters 1 and 2 of the Git book are a good tutorial.

The only file you should need to modify is Scheduler.dfy. GitHub will automatically select your most recent pushed commit before the deadline as your submission; there's no need to manually submit anything else via Canvas or GitHub.

GitHub Classroom will autograde your submission every time you push, by just running the Dafny verifier on Scheduler.dfy. If you can't complete the entire homework and so the autograder fails, don't worry—I will still be grading manually for partial credit.