summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Chong <52972368+nchong-at-aws@users.noreply.github.com>2020-08-27 14:59:12 -0400
committerGitHub <noreply@github.com>2020-08-27 11:59:12 -0700
commit669084ee8f49566d5ea488b1b1d950faae1977c5 (patch)
tree855bd59220c1d51e6593ae24b1c98ac6f855efc7
parent6d35a38bdd7d24b1ebb177656f3a06037f5554e2 (diff)
downloadfreertos-git-669084ee8f49566d5ea488b1b1d950faae1977c5.tar.gz
List proofs and signoff (#194)
-rw-r--r--FreeRTOS/Test/VeriFast/Makefile56
-rw-r--r--FreeRTOS/Test/VeriFast/README.md44
-rw-r--r--FreeRTOS/Test/VeriFast/docs/signoff.md144
-rw-r--r--FreeRTOS/Test/VeriFast/include/proof/common.gh79
-rw-r--r--FreeRTOS/Test/VeriFast/include/proof/list.h368
-rw-r--r--FreeRTOS/Test/VeriFast/include/proof/queue.h1
-rw-r--r--FreeRTOS/Test/VeriFast/list/README.md69
-rw-r--r--FreeRTOS/Test/VeriFast/list/listLIST_IS_EMPTY.c36
-rw-r--r--FreeRTOS/Test/VeriFast/list/uxListRemove.c306
-rw-r--r--FreeRTOS/Test/VeriFast/list/vListInitialise.c71
-rw-r--r--FreeRTOS/Test/VeriFast/list/vListInitialiseItem.c37
-rw-r--r--FreeRTOS/Test/VeriFast/list/vListInsert.c316
-rw-r--r--FreeRTOS/Test/VeriFast/list/vListInsertEnd.c234
-rwxr-xr-xFreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh2
-rw-r--r--FreeRTOS/Test/VeriFast/scripts/diff_files.md4
-rwxr-xr-xFreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh29
16 files changed, 1737 insertions, 59 deletions
diff --git a/FreeRTOS/Test/VeriFast/Makefile b/FreeRTOS/Test/VeriFast/Makefile
index 9e774f61a..3d9fb4800 100644
--- a/FreeRTOS/Test/VeriFast/Makefile
+++ b/FreeRTOS/Test/VeriFast/Makefile
@@ -14,28 +14,37 @@ check_coverage = perl -pe \
$$status=/$1 statements verified/ ? 0 : 1;'
endif
-all: queue
+all: queue list
.PHONY: queue
queue:
- @$(VERIFAST) $(VERIFAST_ARGS) queue/create.c | $(call check_coverage,317)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/prvCopyDataFromQueue.c | $(call check_coverage,301)
- @$(VERIFAST) $(VERIFAST_ARGS) -disable_overflow_check queue/prvCopyDataToQueue.c | $(call check_coverage,329)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/prvIsQueueEmpty.c | $(call check_coverage,282)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/prvIsQueueFull.c | $(call check_coverage,282)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/prvLockQueue.c | $(call check_coverage,283)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/prvUnlockQueue.c | $(call check_coverage,297)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/uxQueueMessagesWaiting.c | $(call check_coverage,285)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/uxQueueSpacesAvailable.c | $(call check_coverage,283)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/vQueueDelete.c | $(call check_coverage,280)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueueGenericSend.c | $(call check_coverage,328)
- @$(VERIFAST) $(VERIFAST_ARGS) -disable_overflow_check queue/xQueueGenericSendFromISR.c | $(call check_coverage,310)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueueIsQueueEmptyFromISR.c | $(call check_coverage,280)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueueIsQueueFullFromISR.c | $(call check_coverage,280)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueuePeek.c | $(call check_coverage,328)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueuePeekFromISR.c | $(call check_coverage,293)
- @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueueReceive.c | $(call check_coverage,330)
- @$(VERIFAST) $(VERIFAST_ARGS) -disable_overflow_check queue/xQueueReceiveFromISR.c | $(call check_coverage,307)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/create.c | $(call check_coverage,324)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/prvCopyDataFromQueue.c | $(call check_coverage,308)
+ @$(VERIFAST) $(VERIFAST_ARGS) -disable_overflow_check queue/prvCopyDataToQueue.c | $(call check_coverage,336)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/prvIsQueueEmpty.c | $(call check_coverage,289)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/prvIsQueueFull.c | $(call check_coverage,289)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/prvLockQueue.c | $(call check_coverage,290)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/prvUnlockQueue.c | $(call check_coverage,304)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/uxQueueMessagesWaiting.c | $(call check_coverage,292)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/uxQueueSpacesAvailable.c | $(call check_coverage,290)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/vQueueDelete.c | $(call check_coverage,287)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueueGenericSend.c | $(call check_coverage,335)
+ @$(VERIFAST) $(VERIFAST_ARGS) -disable_overflow_check queue/xQueueGenericSendFromISR.c | $(call check_coverage,317)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueueIsQueueEmptyFromISR.c | $(call check_coverage,287)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueueIsQueueFullFromISR.c | $(call check_coverage,287)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueuePeek.c | $(call check_coverage,335)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueuePeekFromISR.c | $(call check_coverage,300)
+ @$(VERIFAST) $(VERIFAST_ARGS) queue/xQueueReceive.c | $(call check_coverage,337)
+ @$(VERIFAST) $(VERIFAST_ARGS) -disable_overflow_check queue/xQueueReceiveFromISR.c | $(call check_coverage,314)
+
+.PHONY: list
+list:
+ @$(VERIFAST) $(VERIFAST_ARGS) list/listLIST_IS_EMPTY.c | $(call check_coverage,314)
+ @$(VERIFAST) $(VERIFAST_ARGS) list/uxListRemove.c | $(call check_coverage,440)
+ @$(VERIFAST) $(VERIFAST_ARGS) list/vListInitialise.c | $(call check_coverage,325)
+ @$(VERIFAST) $(VERIFAST_ARGS) list/vListInitialiseItem.c | $(call check_coverage,316)
+ @$(VERIFAST) $(VERIFAST_ARGS) -disable_overflow_check list/vListInsertEnd.c | $(call check_coverage,410)
+ @$(VERIFAST) $(VERIFAST_ARGS) -disable_overflow_check list/vListInsert.c | $(call check_coverage,456)
.PHONY: proof_changes
proof_changes:
@@ -43,10 +52,13 @@ proof_changes:
GIT?=git
NO_CHANGE_CHECKOUT_DIR=no-change-check-freertos-kernel
-NO_CHANGE_EXPECTED_HASH=587a83d6476
+NO_CHANGE_EXPECTED_HASH_QUEUE=587a83d6476
+NO_CHANGE_EXPECTED_HASH_LIST=bb1c4293787
.PHONY: synced_with_source_check
synced_with_source_check:
@rm -rf $(NO_CHANGE_CHECKOUT_DIR)
@$(GIT) clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git $(NO_CHANGE_CHECKOUT_DIR)
- @cd $(NO_CHANGE_CHECKOUT_DIR) && $(GIT) diff --quiet $(NO_CHANGE_EXPECTED_HASH) queue.c
- @cd $(NO_CHANGE_CHECKOUT_DIR) && $(GIT) diff --quiet $(NO_CHANGE_EXPECTED_HASH) include/queue.h
+ @cd $(NO_CHANGE_CHECKOUT_DIR) && $(GIT) diff --quiet $(NO_CHANGE_EXPECTED_HASH_QUEUE) queue.c
+ @cd $(NO_CHANGE_CHECKOUT_DIR) && $(GIT) diff --quiet $(NO_CHANGE_EXPECTED_HASH_QUEUE) include/queue.h
+ @cd $(NO_CHANGE_CHECKOUT_DIR) && $(GIT) diff --quiet $(NO_CHANGE_EXPECTED_HASH_LIST) list.c
+ @cd $(NO_CHANGE_CHECKOUT_DIR) && $(GIT) diff --quiet $(NO_CHANGE_EXPECTED_HASH_LIST) include/list.h
diff --git a/FreeRTOS/Test/VeriFast/README.md b/FreeRTOS/Test/VeriFast/README.md
index f0deecdfc..5d472692f 100644
--- a/FreeRTOS/Test/VeriFast/README.md
+++ b/FreeRTOS/Test/VeriFast/README.md
@@ -1,8 +1,19 @@
# FreeRTOS VeriFast proofs
-This directory contains automated functional correctness proofs of the FreeRTOS
-kernel queue data structure. These properties are proven with the
-[VeriFast](https://github.com/verifast/verifast) verifier.
+This directory contains unbounded proofs of the FreeRTOS kernel queue and list
+data structures. Unbounded proofs mean that these results hold independent of
+the length of the queue or list.
+
+Informally, the queue proofs demonstrate that the queue implementation is
+memory safe (does not access invalid memory), thread safe (properly
+synchronizes accesses) and functionally correct (behaves like a queue) under
+any arbitrary number of tasks or ISRs. The list proofs demonstrate that the
+list implementation is memory safe and functionally correct.
+
+These properties are proven with the
+[VeriFast](https://github.com/verifast/verifast) verifier. See the proof
+[signoff](docs/signoff.md) document for more on the proof properties,
+assumptions, and simplifications.
## Proof directory structure
@@ -14,6 +25,7 @@ predicates, functions and lemmas used by all proofs is maintained in the
`include/proof` directory.
- `queue`: proofs for the FreeRTOS queue data structure
+ - `list`: proofs for the FreeRTOS list data structure
The following figure gives the callgraph of the queue proofs. Green=Proven
functions, Blue=Functions modeled by lock invariants (underlying implementation
@@ -49,7 +61,7 @@ and uncheck `Check arithmetic overflow`).
- `queue/xQueueReceiveFromISR.c`
A successful proof results in the top banner turning green with a statement
-similar to: `0 errors found (328 statements verified)`.
+similar to: `0 errors found (335 statements verified)`.
## Proof checking a single proof at the command-line
@@ -65,7 +77,7 @@ A successful proof results in output similar to:
```
queue/xQueueGenericSend.c
-0 errors found (328 statements verified)
+0 errors found (335 statements verified)
```
## Running proof regression
@@ -87,7 +99,8 @@ $ VERIFAST=/path/to/verifast NO_COVERAGE=1 make
## Annotation burden
VeriFast can emit statistics about the number of source code lines and
-annotations. These range from .3-2x annotations per line of source code.
+annotations. These range from .3-2x annotations per line of source code for the
+queue proofs and up to 7x for the list proofs.
```
$ VERIFAST=/path/to/verifast ./scripts/annotation_overhead.sh
@@ -96,15 +109,12 @@ $ VERIFAST=/path/to/verifast ./scripts/annotation_overhead.sh
## Reading a VeriFast proof
VeriFast is a modular deductive verifier using separation logic. A quick
-introduction is given by [Jacobs and
-Piessens](https://people.cs.kuleuven.be/~bart.jacobs/verifast/verifast.pdf).
-In particular, Section 1 Introduction, gives a high-level overview of the proof
-technique, which uses forward symbolic execution over a symbolic heap.
+introduction is given by [Jacobs and Piessens][1]. In particular, Section 1
+Introduction, gives a high-level overview of the proof technique, which uses
+forward symbolic execution over a symbolic heap.
-Learning how to use VeriFast will help you read and understand the proofs.
-The VeriFast
-[tutorial](https://people.cs.kuleuven.be/~bart.jacobs/verifast/tutorial.pdf) is
-a good guide. You will need to understand:
+Learning how to use VeriFast will help you read and understand the proofs. The
+VeriFast [tutorial][2] is a good guide. You will need to understand:
- Sec 4. Functions and Contracts
- Sec 5. Patterns
@@ -115,8 +125,12 @@ a good guide. You will need to understand:
- Sec 10. Inductive Datatypes
- Sec 11. Lemmas
+[1]: https://people.cs.kuleuven.be/~bart.jacobs/verifast/verifast.pdf
+[2]: https://people.cs.kuleuven.be/~bart.jacobs/verifast/tutorial.pdf
+
## Contributors
-We acknowledge and thank the following contributors, listed alphabetically:
+We acknowledge and thank the following contributors:
- Bart Jacobs, KU Leuven, https://people.cs.kuleuven.be/~bart.jacobs/
+ - Aalok Thakkar, University of Pennsylvania, https://aalok-thakkar.github.io/
diff --git a/FreeRTOS/Test/VeriFast/docs/signoff.md b/FreeRTOS/Test/VeriFast/docs/signoff.md
new file mode 100644
index 000000000..71af7ddbf
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/docs/signoff.md
@@ -0,0 +1,144 @@
+# FreeRTOS VeriFast Proof Signoff
+
+Verification tool: VeriFast (code-level proof)
+
+Proofs: `queue/` and `list`
+
+Implementation: Kernel queue data structure (`queue.c`) and list data structure (`list.c`)
+
+Specification / Properties:
+ - *Memory safety*: the implementation only accesses valid memory. In the case
+ of the queue, this is true under any arbitrary number of tasks or ISRs.
+ - *Thread safety*: in the case of the queue, tasks and ISRs only update
+ objects that they own via proper synchronization.
+ - *Functional correctness*: the queue and list implementations behave like an
+ abstract queue and list. In the case of the queue, this is true under any
+ arbitrary number of tasks or ISRs.
+
+## Queue proof assumptions
+
+Generally, we assume well-behaved clients; the correctness of underlying
+primitives (memory allocation, task scheduling, scheduler suspension); and
+assumptions about the system.
+
+ - Well-behaved client: all client tasks and ISRs use the queue API in a
+ manner that adheres to the specification. A badly-behaved client can
+ invalidate the proven properties. For example, a client that reads or
+ writes to the queue storage directly, without masking interrupts, is racy
+ and no longer thread safe. The specification forbids this behavior by
+ the definition of `queuehandle`, which is a handle to acquire ownership of
+ the queue through interrupt masking, but we cannot, in general, enforce
+ this behavior since we do not verify client code.
+
+ - Memory safety, thread safety and function contracts for the following
+ primitives. For the list and task functions we give a contract that is
+ maximal in terms of the queue objects that can be updated, but we do not
+ model their function effect (e.g., task blocking and the moving of task
+ control blocks between scheduler lists).
+
+ pvPortMalloc
+ vPortFree
+ memcpy
+ vListInitialise
+ xTaskRemoveFromEventList
+ vTaskMissedYield
+ xTaskCheckForTimeOut
+ vTaskInternalSetTimeOutState
+ vTaskPlaceOnEventList
+
+ - We assume interrupt masking gives strong isolation between tasks and ISRs.
+ See Appendix. We further assume the system is configured as required by
+ `configASSERT`. For example, interrupts with a priority greater than the
+ maximum system call priority must not call queue API functions, otherwise
+ the strong isolation guarantee is not maintained.
+
+## List proof assumptions
+
+The list proofs are sequential. We assume the caller of the list API functions
+has taken appropriate synchronization steps to avoid races.
+
+## Simplifications
+
+A list of changes to the source code required for the proofs can be generated:
+
+```
+make proof_changes
+```
+
+A side-by-side diff with respect to the source code can be generated. See
+![`scripts/diff_files.md`](../scripts/diff_files.md).
+
+The main queue changes are:
+
+ - merge cTxLock and cRxLock critical regions: under approximate queue
+ unlock behavior to atomically set `cTxLock` and `cRxLock` to unlocked in a
+ single critical region instead of two separate critical regions. In
+ practice, this is not an issue since no ISR function reads-from both
+ cTxLock and cRxLock.
+ - model single malloc of struct and buffer: split the single malloc of the
+ queue struct and storage into two separate mallocs.
+ - xQueueGenericReset happens-before concurrent behavior: assume that queue
+ initialisation is not concurrent.
+ - do not model pxIndex and xListEnd of xLIST struct: ignore these fields in
+ the list structs of the queue implementation
+
+The main list changes are:
+
+ - change `MiniList_t` to `ListItem_t`: simplifying assumption on the list
+ structure.
+ - over-approximate list insert loop: replace a loop in the insert function
+ that finds the insertion point with an over-approximating function call.
+
+The following minor changes due to the stricter typing and parser of VeriFast:
+
+ - replacing a union declaration with a struct
+ - const pointer declaration
+ - stricter casting
+ - void cast of unused return value
+ - void cast of unused var
+
+The following minor changes due to the modeling of interrupts and scheduler
+suspension in the proofs as ghost state.
+
+ - ghost action
+ - leak ghost state on deletion
+
+## Configuration
+
+We do not verify across the full configuration space of FreeRTOS. In
+particular, the queue proofs do not apply when the following options are
+enabled:
+
+ - `configUSE_QUEUE_SETS`
+ - `configSUPPORT_STATIC_ALLOCATION`
+
+For both the queue and list proofs we assume that coverage and tracing
+macros are no-ops.
+
+## Trusted computing base
+
+ - Soundness of verification tools: VeriFast, Redux prover
+ - C Compiler, because the verification is at the C code-level and the
+ properties proved may not be preserved by compilation.
+
+## References
+
+[N1570] ISO/IEC. Programming languages – C. International standard 9899:201x,
+2011
+
+## Appendix
+
+Assumption on strong isolation induced by interrupt masking and scheduler
+suspension for queue proofs. Informally, we need the following:
+
+```
+// Initially *data == 0
+// Task 1
+taskENTER_CRITICAL()
+*data = 1;
+*data = 2;
+taskEXIT_CRITICAL()
+
+// ISR or Task 2
+r0 = *data; //< guaranteed to read 0 or 2, never 1
+```
diff --git a/FreeRTOS/Test/VeriFast/include/proof/common.gh b/FreeRTOS/Test/VeriFast/include/proof/common.gh
index c3b064939..f8acfdddc 100644
--- a/FreeRTOS/Test/VeriFast/include/proof/common.gh
+++ b/FreeRTOS/Test/VeriFast/include/proof/common.gh
@@ -191,6 +191,45 @@ lemma_auto void mod_range(int x, int n)
div_rem_nonneg(x, n);
}
+lemma void head_append<t>(list<t> xs, list<t> ys)
+ requires 0 < length(xs);
+ ensures head(append(xs, ys)) == head(xs);
+{
+ switch(xs)
+ {
+ case cons(c, cs):
+ case nil:
+ }
+}
+
+lemma void drop_take_singleton<t>(int i, list<t> xs)
+ requires 0 < i && i < length(xs);
+ ensures drop(i-1, take(i, xs)) == singleton(nth(i-1, xs));
+{
+ switch (xs) {
+ case nil:
+ case cons(x0, xs0):
+ if (i == 1) {
+ } else {
+ drop_take_singleton(i-1, xs0);
+ }
+ }
+}
+
+lemma void take_singleton<t>(int i, list<t> xs)
+ requires 0 <= i && i < length(xs);
+ ensures append(take(i, xs), singleton(nth(i, xs))) == take(i+1, xs);
+{
+ switch (xs) {
+ case nil:
+ case cons(x0, xs0):
+ if (i == 0) {
+ } else {
+ take_singleton(i-1, xs0);
+ }
+ }
+}
+
lemma void drop_update_le<t>(int i, int j, t x, list<t> xs)
requires 0 <= i && i <= j && j < length(xs);
ensures drop(i, update(j, x, xs)) == update(j - i, x, drop(i, xs));
@@ -298,21 +337,17 @@ lemma void take_take<t>(int m, int n, list<t> xs)
}
}
-lemma void index_of_distinct<t>(list<t> xs, t x1, t x2)
- requires mem(x1, xs) == true &*& mem(x2, xs) == true &*& x1 != x2;
- ensures index_of(x1, xs) != index_of(x2, xs);
+lemma_auto void take_head<t>(list<t> xs)
+ requires 0 < length(xs);
+ ensures take(1, xs) == singleton(head(xs));
{
- switch (xs) {
+ switch(xs) {
case nil:
- case cons(h, tl):
- if (h == x1 || h == x2) {
- /* trivial */
- } else {
- index_of_distinct(tl, x1, x2);
- }
+ case cons(x0, xs0):
}
}
+/* Following lemma from `verifast/bin/rt/_list.java` */
lemma void remove_remove_nth<t>(list<t> xs, t x)
requires mem(x, xs) == true;
ensures remove(x, xs) == remove_nth(index_of(x, xs), xs);
@@ -328,6 +363,18 @@ lemma void remove_remove_nth<t>(list<t> xs, t x)
}
}
+lemma void mem_take_false<t>(t x, int n, list<t> xs)
+ requires mem(x, xs) == false;
+ ensures mem(x, take(n, xs)) == false;
+{
+ switch (xs) {
+ case nil:
+ case cons(x0, xs0):
+ if (x0 != x && n != 0)
+ mem_take_false(x, n - 1, xs0);
+ }
+}
+
/* Following lemma from `verifast/bin/rt/_list.java`. Renamed to
avoid clash with listex.c's nth_drop lemma. */
lemma void nth_drop2<t>(list<t> vs, int i)
@@ -536,12 +583,12 @@ lemma void update_rewrite<t>(list<t> vs, t v, int pos)
ensures update(pos, v, vs) == append(take(pos, vs), cons(v, (drop(pos+1, vs))));
{
switch(vs) {
- case nil:
- case cons(h, t):
- if(pos == 0) {
- } else {
- update_rewrite(t, v, pos - 1);
- }
+ case nil:
+ case cons(h, t):
+ if (pos == 0) {
+ } else {
+ update_rewrite(t, v, pos - 1);
+ }
}
}
diff --git a/FreeRTOS/Test/VeriFast/include/proof/list.h b/FreeRTOS/Test/VeriFast/include/proof/list.h
new file mode 100644
index 000000000..21f9b42b0
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/include/proof/list.h
@@ -0,0 +1,368 @@
+/*
+ * FreeRTOS VeriFast Proofs
+ * Copyright (C) Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+#define VERIFAST
+#include <stdlib.h>
+#include <stdint.h>
+//@#include "common.gh"
+
+typedef size_t TickType_t;
+typedef size_t UBaseType_t;
+typedef ssize_t BaseType_t;
+
+#define pdTRUE 1
+#define pdFALSE 0
+
+/* Empty/no-op macros */
+#define mtCOVERAGE_TEST_MARKER()
+#define mtCOVERAGE_TEST_DELAY()
+#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
+#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
+#define listTEST_LIST_INTEGRITY( pxList )
+#define listTEST_LIST_ITEM_INTEGRITY( pxListItem )
+#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxListItem )
+#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxListItem )
+
+/* Max value stored in sentinel xListEnd element */
+#define portMAX_DELAY UINT_MAX
+
+struct xLIST;
+
+struct xLIST_ITEM {
+ TickType_t xItemValue;
+ struct xLIST_ITEM * pxNext;
+ struct xLIST_ITEM * pxPrevious;
+ void * pvOwner;
+ struct xLIST *pxContainer;
+};
+typedef struct xLIST_ITEM ListItem_t;
+
+typedef struct xLIST {
+ UBaseType_t uxNumberOfItems;
+ struct xLIST_ITEM *pxIndex;
+#ifdef VERIFAST /*< ***change MiniList_t to ListItem_t*** */
+ struct xLIST_ITEM xListEnd;
+#else
+ MiniListItem_t xListEnd;
+#endif
+} List_t;
+
+/*@
+predicate xLIST_ITEM(
+ struct xLIST_ITEM *n,
+ TickType_t xItemValue,
+ struct xLIST_ITEM *pxNext,
+ struct xLIST_ITEM *pxPrevious,
+ struct xLIST *pxContainer;) =
+ n->xItemValue |-> xItemValue &*&
+ n->pxNext |-> pxNext &*&
+ n->pxPrevious |-> pxPrevious &*&
+ n->pvOwner |-> _ &*&
+ n->pxContainer |-> pxContainer;
+@*/
+
+/* Ferreira et al. (STTT'14) doubly-linked list segment (DLS). */
+/*@
+predicate DLS(
+ struct xLIST_ITEM *n,
+ struct xLIST_ITEM *nprev,
+ struct xLIST_ITEM *mnext,
+ struct xLIST_ITEM *m,
+ list<struct xLIST_ITEM * > cells,
+ list<TickType_t > vals,
+ struct xLIST *pxContainer) =
+ n == m
+ ? cells == cons(n, nil) &*&
+ vals == cons(?v, nil) &*&
+ xLIST_ITEM(n, v, mnext, nprev, pxContainer)
+ : cells == cons(n, ?cells0) &*&
+ vals == cons(?v, ?vals0) &*&
+ xLIST_ITEM(n, v, ?o, nprev, pxContainer) &*& DLS(o, n, mnext, m, cells0, vals0, pxContainer);
+
+lemma void dls_star_item(
+ struct xLIST_ITEM *n,
+ struct xLIST_ITEM *m,
+ struct xLIST_ITEM *o)
+requires DLS(n, ?nprev, ?mnext, m, ?cells, ?vals, ?l) &*& xLIST_ITEM(o, ?v, ?onext, ?oprev, ?l2);
+ensures DLS(n, nprev, mnext, m, cells, vals, l) &*& xLIST_ITEM(o, v, onext, oprev, l2) &*& mem(o, cells) == false;
+{
+ open DLS(n, nprev, mnext, m, cells, vals, l);
+ if (n == m) {
+ assert xLIST_ITEM(n, _, _, _, _);
+ open xLIST_ITEM(n, _, _, _, _);
+ open xLIST_ITEM(o, _, _, _, _);
+ assert n != o;
+ close xLIST_ITEM(o, _, _, _, _);
+ close xLIST_ITEM(n, _, _, _, _);
+ close DLS(n, nprev, mnext, m, cells, vals, l);
+ }
+ else {
+ assert DLS(?nnext, n, mnext, m, tail(cells), tail(vals), l);
+ dls_star_item(nnext, m, o);
+ open xLIST_ITEM(n, _, _, _, _);
+ open xLIST_ITEM(o, _, _, _, _);
+ assert n != o;
+ close xLIST_ITEM(o, _, _, _, _);
+ close xLIST_ITEM(n, _, _, _, _);
+ close DLS(n, nprev, mnext, m, cells, vals, l);
+ }
+}
+
+lemma void dls_distinct(
+ struct xLIST_ITEM *n,
+ struct xLIST_ITEM *nprev,
+ struct xLIST_ITEM *mnext,
+ struct xLIST_ITEM *m,
+ list<struct xLIST_ITEM * > cells)
+requires DLS(n, nprev, mnext, m, cells, ?vals, ?l);
+ensures DLS(n, nprev, mnext, m, cells, vals, l) &*& distinct(cells) == true;
+{
+ if (n == m) {
+ open DLS(n, nprev, mnext, m, cells, vals, l);
+ close DLS(n, nprev, mnext, m, cells, vals, l);
+ } else {
+ open DLS(n, nprev, mnext, m, cells, vals, l);
+ assert DLS(?nnext, n, mnext, m, tail(cells), tail(vals), l);
+ dls_distinct(nnext, n, mnext, m, tail(cells));
+ dls_star_item(nnext, m, n);
+ close DLS(n, nprev, mnext, m, cells, vals, l);
+ }
+}
+
+predicate xLIST(
+ struct xLIST *l,
+ int uxNumberOfItems,
+ struct xLIST_ITEM *pxIndex,
+ struct xLIST_ITEM *xListEnd,
+ list<struct xLIST_ITEM *>cells,
+ list<TickType_t >vals) =
+ l->uxNumberOfItems |-> uxNumberOfItems &*&
+ l->pxIndex |-> pxIndex &*&
+ mem(pxIndex, cells) == true &*&
+ xListEnd == &(l->xListEnd) &*&
+ xListEnd == head(cells) &*&
+ portMAX_DELAY == head(vals) &*&
+ struct_xLIST_ITEM_padding(&l->xListEnd) &*&
+ length(cells) == length(vals) &*&
+ uxNumberOfItems + 1 == length(cells) &*&
+ DLS(xListEnd, ?endprev, xListEnd, endprev, cells, vals, l);
+
+lemma void xLIST_distinct_cells(struct xLIST *l)
+requires xLIST(l, ?n, ?idx, ?end, ?cells, ?vals);
+ensures xLIST(l, n, idx, end, cells, vals) &*& distinct(cells) == true;
+{
+ open xLIST(l, n, idx, end, cells, vals);
+ assert DLS(end, ?endprev, end, _, cells, vals, l);
+ dls_distinct(end, endprev, end, endprev, cells);
+ close xLIST(l, n, idx, end, cells, vals);
+}
+
+lemma void xLIST_star_item(struct xLIST *l, struct xLIST_ITEM *x)
+requires xLIST(l, ?n, ?idx, ?end, ?cells, ?vals) &*& xLIST_ITEM(x, ?v, ?xnext, ?xprev, ?l2);
+ensures xLIST(l, n, idx, end, cells, vals) &*& xLIST_ITEM(x, v, xnext, xprev, l2) &*& mem(x, cells) == false;
+{
+ open xLIST(l, n, idx, end, cells, vals);
+ assert DLS(end, ?endprev, end, _, cells, vals, l);
+ dls_distinct(end, endprev, end, endprev, cells);
+ dls_star_item(end, endprev, x);
+ close xLIST(l, n, idx, end, cells, vals);
+}
+
+lemma void dls_first_mem(
+ struct xLIST_ITEM *n,
+ struct xLIST_ITEM *nprev,
+ struct xLIST_ITEM *mnext,
+ struct xLIST_ITEM *m,
+ list<struct xLIST_ITEM * > cells)
+requires DLS(n, nprev, mnext, m, cells, ?vals, ?l);
+ensures DLS(n, nprev, mnext, m, cells, vals, l) &*& mem(n, cells) == true &*& index_of(n, cells) == 0;
+{
+ open DLS(n, nprev, mnext, m, cells, vals, l);
+ if (n == m) {
+ assert cells == cons(n, nil);
+ close DLS(n, nprev, mnext, m, cells, vals, l);
+ } else {
+ assert cells == cons(n, ?tail);
+ close DLS(n, nprev, mnext, m, cells, vals, l);
+ }
+}
+
+lemma void dls_not_empty(
+ struct xLIST_ITEM *n,
+ struct xLIST_ITEM *m,
+ list<struct xLIST_ITEM * > cells,
+ struct xLIST_ITEM *x)
+requires DLS(n, m, n, m, cells, ?vals, ?l) &*& mem(x, cells) == true &*& x != n;
+ensures DLS(n, m, n, m, cells, vals, l) &*& n != m;
+{
+ open DLS(n, m, n, m, cells, vals, l);
+ close DLS(n, m, n, m, cells, vals, l);
+}
+
+lemma void dls_last_mem(
+ struct xLIST_ITEM *n,
+ struct xLIST_ITEM *nprev,
+ struct xLIST_ITEM *mnext,
+ struct xLIST_ITEM *m,
+ list<struct xLIST_ITEM * > cells)
+requires DLS(n, nprev, mnext, m, cells, ?vals, ?l);
+ensures DLS(n, nprev, mnext, m, cells, vals, l) &*& mem(m, cells) == true &*& index_of(m, cells) == length(cells) - 1;
+{
+ open DLS(n, nprev, mnext, m, cells, vals, l);
+ if (n == m) {
+ // trivial
+ } else {
+ open xLIST_ITEM(n, _, ?nnext, _, l);
+ assert DLS(?o, n, mnext, m, tail(cells), tail(vals), l);
+ dls_last_mem(o, n, mnext, m, tail(cells));
+ close xLIST_ITEM(n, _, nnext, _, l);
+ }
+ close DLS(n, nprev, mnext, m, cells, vals, l);
+}
+
+lemma void split(
+ struct xLIST_ITEM *n,
+ struct xLIST_ITEM *nprev,
+ struct xLIST_ITEM *mnext,
+ struct xLIST_ITEM *m,
+ list<struct xLIST_ITEM * > cells,
+ list<TickType_t > vals,
+ struct xLIST_ITEM *x,
+ int i)
+requires DLS(n, nprev, mnext, m, cells, vals, ?l) &*& x != n &*& mem(x, cells) == true &*& index_of(x,cells) == i;
+ensures DLS(n, nprev, x, ?xprev, take(i, cells), take(i, vals), l) &*& DLS(x, xprev, mnext, m, drop(i, cells), drop(i, vals), l) &*& xprev == nth(i-1, cells);
+{
+ open DLS(n, nprev, mnext, m, cells, vals, l);
+ assert n != m;
+ assert xLIST_ITEM(n, ?v, ?nnext, _, _);
+ assert DLS(nnext, n, mnext, m, tail(cells), tail(vals), l);
+ if (nnext == x) {
+ close DLS(n, nprev, x, n, singleton(n), singleton(v), l);
+ open DLS(x, n, mnext, m, tail(cells), tail(vals), l);
+ open xLIST_ITEM(x, _, ?xnext, ?xprev, l);
+ close xLIST_ITEM(x, _, xnext, xprev, l);
+ close DLS(x, n, mnext, m, tail(cells), tail(vals), l);
+ } else {
+ assert nnext != x;
+ split(nnext, n, mnext, m, tail(cells), tail(vals), x, i - 1);
+ assert DLS(nnext, n, x, ?xprev, take(i-1, tail(cells)), take(i-1, tail(vals)), l);
+ dls_distinct(nnext, n, x, xprev, take(i-1, tail(cells)));
+ dls_star_item(nnext, xprev, n);
+ dls_last_mem(nnext, n, x, xprev, take(i-1, tail(cells)));
+ assert n != xprev;
+ close DLS(n, nprev, x, xprev, take(i, cells), take(i, vals), l);
+ }
+}
+
+lemma void join(
+ struct xLIST_ITEM *n1,
+ struct xLIST_ITEM *nprev1,
+ struct xLIST_ITEM *mnext1,
+ struct xLIST_ITEM *m1,
+ list<struct xLIST_ITEM * > cells1,
+ list<TickType_t > vals1,
+ struct xLIST_ITEM *n2,
+ struct xLIST_ITEM *nprev2,
+ struct xLIST_ITEM *mnext2,
+ struct xLIST_ITEM *m2,
+ list<struct xLIST_ITEM * > cells2,
+ list<TickType_t > vals2)
+requires
+ DLS(n1, nprev1, mnext1, m1, cells1, vals1, ?l) &*&
+ DLS(n2, nprev2, mnext2, m2, cells2, vals2, l) &*&
+ mnext1 == n2 &*& m1 == nprev2;
+ensures DLS(n1, nprev1, mnext2, m2, append(cells1, cells2), append(vals1, vals2), l);
+{
+ if (n1 == m1) {
+ dls_first_mem(n1, nprev1, mnext1, m1, cells1);
+ dls_last_mem(n2, nprev2, mnext2, m2, cells2);
+ open DLS(n1, nprev1, mnext1, m1, cells1, vals1, l);
+ dls_star_item(n2, m2, n1);
+ close DLS(n1, nprev1, mnext2, m2, append(singleton(n1), cells2), append(vals1, vals2), l);
+ } else {
+ open DLS(n1, nprev1, mnext1, m1, cells1, vals1, l);
+ assert DLS(?o, n1, mnext1, m1, ?cells1_tail, ?vals1_tail, l);
+ join(o, n1, mnext1, m1, cells1_tail, vals1_tail,
+ n2, nprev2, mnext2, m2, cells2, vals2);
+ assert DLS(o, n1, mnext2, m2, append(cells1_tail, cells2), append(vals1_tail, vals2), l);
+ dls_last_mem(o, n1, mnext2, m2, append(cells1_tail, cells2));
+ dls_star_item(o, m2, n1);
+ close DLS(n1, nprev1, mnext2, m2, append(cells1, cells2), append(vals1, vals2), l);
+ }
+}
+
+lemma void idx_remains_in_list<t>(
+ list<t> cells,
+ t idx,
+ t x,
+ int ix)
+requires
+ idx != x &*&
+ mem(idx, cells) == true &*&
+ mem(x, cells) == true &*&
+ index_of(x, cells) == ix;
+ensures mem(idx, remove_nth(ix, cells)) == true;
+{
+ neq_mem_remove(idx, x, cells);
+ remove_remove_nth(cells, x);
+}
+@*/
+
+/* Following lemma from `verifast/examples/shared_boxes/concurrentqueue.c`.
+Used in the uxListRemove proof to show that the item to remove `x` must
+have value `nth(i, vals)` where `i == index_of(x, cells)`. */
+/*@
+lemma void drop_nth_index_of<t>(list<t> vs, int i)
+requires
+ 0 <= i && i < length(vs);
+ensures
+ head(drop(i , vs)) == nth(i, vs);
+{
+ switch(vs) {
+ case nil:
+ case cons(h, t):
+ if (i == 0) {
+ // trivial
+ } else {
+ drop_nth_index_of(t, i - 1);
+ }
+ }
+}
+@*/
+
+/*@
+lemma void remove_append<t>(t x, list<t> l1, list<t> l2)
+ requires mem(x, l1) == false;
+ ensures remove(x, append(l1, l2)) == append(l1, remove(x, l2));
+{
+ switch(l1) {
+ case nil:
+ case cons(h1, t1):
+ remove_append(x, t1, l2);
+ }
+}
+@*/
+
+#endif /* LIST_H */
diff --git a/FreeRTOS/Test/VeriFast/include/proof/queue.h b/FreeRTOS/Test/VeriFast/include/proof/queue.h
index 610bc03d9..a05b327f7 100644
--- a/FreeRTOS/Test/VeriFast/include/proof/queue.h
+++ b/FreeRTOS/Test/VeriFast/include/proof/queue.h
@@ -305,7 +305,6 @@ ensures
}
drop_drop(1, j, elements);
nth_drop2(elements, i);
- open buffer(buffer + (i+1) * M, (N-1-i), M, _);
}
}
diff --git a/FreeRTOS/Test/VeriFast/list/README.md b/FreeRTOS/Test/VeriFast/list/README.md
new file mode 100644
index 000000000..b9385b920
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/list/README.md
@@ -0,0 +1,69 @@
+# FreeRTOS list proofs
+
+The list predicates and proofs are inspired by and based on the work from
+Ferreira et al. (STTT'14).
+
+The main shape predicate is a doubly-linked list segment (DLS), as defined
+by Ferreira et al. in Fig 15. A DLS is defined by two `xLIST_ITEM` struct
+pointers `n` and `m` (possibly pointing to the same item) which are the start
+and end of the segment. We track the item pointers and values within the DLS in
+the lists `cells` and `vals`, respectively. Therefore `n` and `m` are the first
+and last items of `cells`.
+
+```
+ +--+ +--+
+ -----n-> |*n| ... |*m| -mnext->
+ <-nprev- | | | | <-m-----
+ +--+ +--+
+ ^-----------^
+ DLS(n, nprev, mnext, m)
+```
+
+With base case: `n == m` (single item case)
+
+```
+ +--+
+ -----n-> |*n| -mnext->
+ <-nprev- | | <-n-----
+ +--+
+ ^--^
+ xLIST_ITEM
+ DLS(n, nprev, mnext, n)
+```
+
+Cons case:
+
+```
+ +--+ +--+ +--+
+ -----n-> |*n| -o-> |*o| ... |*m| -mnext->
+ <-nprev- | | <-n- | | | | <-m-----
+ +--+ +--+ +--+
+ ^--^ ^-----------^
+ xLIST_ITEM DLS(o, n, mnext, m)
+
+ ^---------------------^
+ DLS(n, nprev, mnext, m)
+```
+
+A DLS can be made into a well-formed list by joining `n` and `m` into a cycle.
+Note that unlike Ferreira et al.'s list shape predicate, we always start with
+the sentinel end item to avoid a top-level case-split. So in the following
+diagram the start and end of the DLS are `end` and the item-before-end
+`endprev`.
+
+```
+ .-----------------------------------.
+ | +--------+ +--------+ |
+ `--> |*end | ... |*endprev| ----'
+ .---- | | | | <---.
+ | +--------+ +--------+ |
+ `----------------------------------'
+ ^-----------------------^
+ DLS(end, endprev, end, endprev)
+```
+
+## References
+
+- Automated Verification of the FreeRTOS Scheduler in HIP/SLEEK\
+ João F. Ferreira, Cristian Gherghina, Guanhua He, Shengchao Qin, Wei-Ngan Chin\
+ https://joaoff.com/publication/2014/sttt/
diff --git a/FreeRTOS/Test/VeriFast/list/listLIST_IS_EMPTY.c b/FreeRTOS/Test/VeriFast/list/listLIST_IS_EMPTY.c
new file mode 100644
index 000000000..ab6e12b4a
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/list/listLIST_IS_EMPTY.c
@@ -0,0 +1,36 @@
+/*
+ * FreeRTOS VeriFast Proofs
+ * Copyright (C) Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "proof/list.h"
+
+/* Wrap the macro in a function call so we can give a function contract */
+#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
+
+BaseType_t wrapper_listLIST_IS_EMPTY( List_t * pxList )
+/*@requires xLIST(pxList, ?len, ?idx, ?end, ?cells, ?vals);@*/
+/*@ensures xLIST(pxList, len, idx, end, cells, vals) &*&
+ result == ((len == 0) ? pdTRUE : pdFALSE); @*/
+{
+ /*@open xLIST(pxList, len, _, _, _, _);@*/
+ return listLIST_IS_EMPTY( pxList );
+ /*@close xLIST(pxList, len, _, _, cells, vals);@*/
+}
diff --git a/FreeRTOS/Test/VeriFast/list/uxListRemove.c b/FreeRTOS/Test/VeriFast/list/uxListRemove.c
new file mode 100644
index 000000000..1d244bc06
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/list/uxListRemove.c
@@ -0,0 +1,306 @@
+/*
+ * FreeRTOS VeriFast Proofs
+ * Copyright (C) Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "proof/list.h"
+
+UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
+/*@requires
+ exists<struct xLIST * >(?l) &*&
+ xLIST(l, ?len, ?idx, ?end, ?cells, ?vals) &*&
+ end != pxItemToRemove &*&
+ mem(pxItemToRemove, cells) == true;@*/
+/*@ensures
+ result == len-1 &*&
+ xLIST_ITEM(pxItemToRemove, nth(index_of(pxItemToRemove, cells), vals), _, ?pxItemToRemovePrevious, NULL) &*&
+ pxItemToRemovePrevious == nth(index_of(pxItemToRemove, cells)-1, cells) &*&
+ xLIST(l, result, idx == pxItemToRemove ? pxItemToRemovePrevious : idx, end, remove(pxItemToRemove, cells), remove_nth(index_of(pxItemToRemove, cells), vals));@*/
+{
+ /* For brevity we alias x to pxItemToRemove */
+ /*@struct xLIST_ITEM *x = pxItemToRemove;@*/
+
+ /* Start by establishing that the list must be non-empty since x != end */
+ /*@open xLIST(l, len, idx, end, cells, vals);@*/
+ /*@assert DLS(end, ?endprev, end, _, cells, vals, l);@*/
+ /*@assert vals == cons(portMAX_DELAY, _);@*/
+ /*@dls_not_empty(end, endprev, cells, x);@*/
+
+ /* We know the xLIST is a DLS: end...endprev
+ Split this into DLS1:end...xprev and DLS2:x...endprev */
+ /*@int i = index_of(x, cells);@*/
+ /*@split(end, endprev, end, endprev, cells, vals, x, i);@*/
+ /*@list<struct xLIST_ITEM *> ys = take(i, cells);@*/
+ /*@list<struct xLIST_ITEM *> zs = drop(i, cells);@*/
+ /*@list<TickType_t> vs = take(i, vals);@*/
+ /*@list<TickType_t> ws = drop(i, vals);@*/
+ /*@assert length(ys) == length(vs);@*/
+ /*@assert length(zs) == length(ws);@*/
+ /*@assert DLS(end, endprev, x, ?xprev, ys, vs, l);@*/ /*< DLS1 (ys, vs) */
+ /*@assert DLS(x, xprev, end, endprev, zs, ws, l);@*/ /*< DLS2 (zs, ws) */
+
+ /* Now case split to open DLS1 and DLS2 appropriately */
+ /*@
+ if (end == xprev)
+ {
+ if (x == endprev)
+ {
+ //Case A
+ //DLS1: extract end=prev=next
+ open DLS(end, endprev, x, xprev, ys, vs, l);
+ open xLIST_ITEM(end, portMAX_DELAY, x, endprev, l);
+ //DLS2: extract x
+ open DLS(x, xprev, end, endprev, zs, ws, l);
+ //Lengths
+ assert length(ys) == 1;
+ assert length(zs) == 1;
+ }
+ else
+ {
+ //Case B
+ //DLS1: extract end=prev
+ open DLS(end, endprev, x, xprev, ys, vs, l);
+ open xLIST_ITEM(end, portMAX_DELAY, x, endprev, l);
+ //DLS2: extract next and x
+ open DLS(x, end, end, endprev, zs, ws, l);
+ assert DLS(?xnext, x, end, endprev, tail(zs), tail(ws), l);
+ open DLS(xnext, x, end, endprev, tail(zs), tail(ws), l);
+ open xLIST_ITEM(xnext, _, _, x, l);
+ //Lengths
+ assert length(ys) == 1;
+ }
+ }
+ else
+ {
+ if (x == endprev)
+ {
+ //Case C
+ //DLS1: extract end=next and prev
+ dls_last_mem(end, endprev, x, xprev, ys);
+ assert mem(xprev, ys) == true;
+ open DLS(end, endprev, x, xprev, ys, vs, l);
+ open xLIST_ITEM(end, portMAX_DELAY, ?endnext, endprev, l);
+ if (endnext == xprev)
+ {
+ open DLS(endnext, end, x, xprev, tail(ys), tail(vs), l);
+ open xLIST_ITEM(xprev, _, x, _, l);
+ }
+ else
+ {
+ assert DLS(endnext, end, x, xprev, tail(ys), tail(vs), l);
+ int k = index_of(xprev, tail(ys));
+ dls_last_mem(endnext, end, x, xprev, tail(ys));
+ split(endnext, end, x, xprev, tail(ys), tail(vs), xprev, k);
+ open DLS(xprev, _, x, xprev, _, _, l);
+ open xLIST_ITEM(xprev, _, x, _, l);
+ }
+ //DLS2: extract x
+ open DLS(x, xprev, end, endprev, zs, ws, l);
+ //Lengths
+ assert length(zs) == 1;
+ }
+ else
+ {
+ //Case D
+ //DLS1: extract prev
+ dls_last_mem(end, endprev, x, xprev, ys);
+ int j = index_of(xprev, ys);
+ open DLS(end, endprev, x, xprev, ys, vs, l);
+ open xLIST_ITEM(end, portMAX_DELAY, ?endnext, endprev, l);
+ if (endnext == xprev)
+ {
+ open DLS(endnext, end, x, xprev, tail(ys), tail(vs), l);
+ assert tail(ys) == singleton(xprev);
+ open xLIST_ITEM(xprev, _, x, _, l);
+ }
+ else
+ {
+ assert DLS(endnext, end, x, xprev, tail(ys), tail(vs), l);
+ int k = index_of(xprev, tail(ys));
+ dls_last_mem(endnext, end, x, xprev, tail(ys));
+ split(endnext, end, x, xprev, tail(ys), tail(vs), xprev, k);
+ open DLS(xprev, _, x, xprev, _, _, l);
+ open xLIST_ITEM(xprev, _, x, _, l);
+ }
+ //DLS2: extract next and x
+ open DLS(x, xprev, end, endprev, zs, ws, l);
+ assert xLIST_ITEM(x, _, ?xnext, _, l);
+ open DLS(xnext, x, end, endprev, tail(zs), tail(ws), l);
+ open xLIST_ITEM(xnext, _, _, x, l);
+ }
+ }
+ @*/
+ /*@drop_nth_index_of(vals, i);@*/
+ /*@open xLIST_ITEM(x, nth(i, vals), ?xnext, xprev, l);@*/
+
+/* The list item knows which list it is in. Obtain the list from the list
+ * item. */
+#ifdef VERIFAST /*< const pointer declaration */
+ List_t * pxList = pxItemToRemove->pxContainer;
+#else
+ List_t * const pxList = pxItemToRemove->pxContainer;
+#endif
+
+ pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
+ pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
+
+ /* Only used during decision coverage testing. */
+ mtCOVERAGE_TEST_DELAY();
+
+ /* Make sure the index is left pointing to a valid item. */
+ if( pxList->pxIndex == pxItemToRemove )
+ {
+ pxList->pxIndex = pxItemToRemove->pxPrevious;
+ }
+ else
+ {
+ mtCOVERAGE_TEST_MARKER();
+ }
+
+ pxItemToRemove->pxContainer = NULL;
+ ( pxList->uxNumberOfItems )--;
+
+ return pxList->uxNumberOfItems;
+
+ /*@
+ // Reassemble DLS1 and a modified DLS2, which no longer includes x
+ if (end == xprev)
+ {
+ if (x == endprev)
+ {
+ //Case A
+ close xLIST_ITEM(end, portMAX_DELAY, _, _, _);
+ close DLS(end, end, end, end, singleton(end), singleton(portMAX_DELAY), l);
+ }
+ else
+ {
+ //Case B
+ close xLIST_ITEM(xprev, _, xnext, endprev, l);
+ close DLS(end, endprev, xnext, xprev, singleton(end), singleton(portMAX_DELAY), l);
+ close xLIST_ITEM(xnext, _, _, xprev, l);
+ close DLS(xnext, xprev, end, endprev, tail(zs), tail(ws), l);
+ join(end, endprev, xnext, xprev, singleton(end), singleton(portMAX_DELAY),
+ xnext, xprev, end, endprev, tail(zs), tail(ws));
+ }
+ }
+ else
+ {
+ if (x == endprev)
+ {
+ //Case C
+ close xLIST_ITEM(end, _, ?endnext, xprev, l);
+ close xLIST_ITEM(xprev, ?xprev_val, end, _, l);
+ if (endnext == xprev)
+ {
+ close DLS(xprev, end, end, xprev, singleton(xprev), singleton(xprev_val), l);
+ close DLS(end, xprev, end, xprev, cons(end, singleton(xprev)), cons(portMAX_DELAY, singleton(xprev_val)), l);
+ }
+ else
+ {
+ close DLS(xprev, ?xprevprev, xnext, xprev, singleton(xprev), singleton(xprev_val), l);
+ assert DLS(endnext, end, xprev, xprevprev, ?cells_endnext_to_xprevprev, ?vals_endnext_to_xprevprev, l);
+ join(endnext, end, xprev, xprevprev, cells_endnext_to_xprevprev, vals_endnext_to_xprevprev,
+ xprev, xprevprev, xnext, xprev, singleton(xprev), singleton(xprev_val));
+ close DLS(end, xprev, end, xprev, ys, vs, l);
+ }
+ }
+ else
+ {
+ //Case D
+ close xLIST_ITEM(xnext, _, ?xnextnext, xprev, l);
+ close DLS(xnext, xprev, end, endprev, tail(zs), tail(ws), l);
+ close xLIST_ITEM(end, _, ?endnext, endprev, l);
+ close xLIST_ITEM(xprev, ?xprev_val, xnext, _, l);
+ if (endnext == xprev)
+ {
+ close DLS(xprev, _, xnext, xprev, singleton(xprev), singleton(xprev_val), l);
+ close DLS(end, endprev, xnext, xprev, ys, vs, l);
+ join(end, endprev, xnext, xprev, ys, vs,
+ xnext, xprev, end, endprev, tail(zs), tail(ws));
+ }
+ else
+ {
+ close DLS(xprev, ?xprevprev, xnext, xprev, singleton(xprev), singleton(xprev_val), l);
+ assert DLS(endnext, end, xprev, xprevprev, ?cells_endnext_to_xprevprev, ?vals_endnext_to_xprevprev, l);
+ join(endnext, end, xprev, xprevprev, cells_endnext_to_xprevprev, vals_endnext_to_xprevprev,
+ xprev, xprevprev, xnext, xprev, singleton(xprev), singleton(xprev_val));
+ close DLS(end, endprev, xnext, xprev, ys, vs, l);
+ join(end, endprev, xnext, xprev, ys, vs,
+ xnext, xprev, end, endprev, tail(zs), tail(ws));
+ }
+ }
+ }
+ @*/
+ /*@remove_remove_nth(cells, x);@*/
+ /*@
+ if (idx == x)
+ {
+ close xLIST(l, len-1, xprev, end, append(ys, tail(zs)), append(vs, tail(ws)));
+ }
+ else
+ {
+ idx_remains_in_list(cells, idx, x, i);
+ close xLIST(l, len-1, idx, end, append(ys, tail(zs)), append(vs, tail(ws)));
+ }
+ @*/
+ /*@close xLIST_ITEM(x, nth(i, vals), xnext, xprev, NULL);@*/
+}
+
+ListItem_t * client_example( List_t * l )
+/*@requires
+ xLIST(l, ?len, ?idx, ?end, ?cells, ?vals) &*&
+ idx != end &*&
+ cells == cons(end, cons(idx, ?cells_tl)) &*&
+ vals == cons(portMAX_DELAY, cons(42, ?vals_tl));@*/
+/*@ensures
+ xLIST(l, len - 1, _, end, cons(end, cells_tl), cons(portMAX_DELAY, vals_tl)) &*&
+ xLIST_ITEM(result, 42, _, _, NULL);@*/
+{
+ /*@open xLIST(l, len, idx, end, cells, vals);@*/
+ ListItem_t *index = l->pxIndex;
+ /*@close xLIST(l, len, idx, end, cells, vals);@*/
+ /*@close exists(l);@*/
+ uxListRemove( index );
+ return index;
+}
+
+void client_example2( List_t * l )
+/*@requires
+ xLIST(l, ?len, ?idx, ?end, ?cells, ?vals) &*&
+ cells == cons(end, cons(?x1, cons(?x2, ?cells_tl))) &*&
+ idx == x2 &*&
+ vals == cons(portMAX_DELAY, cons(1, cons(2, ?vals_tl)));@*/
+/*@ensures
+ xLIST(l, len-2, end, end, cons(end, cells_tl), cons(portMAX_DELAY, vals_tl)) &*&
+ xLIST_ITEM(_, 1, _, _, NULL) &*&
+ xLIST_ITEM(_, 2, _, _, NULL);@*/
+{
+ /*@xLIST_distinct_cells(l);@*/
+ /*@open xLIST(l, len, idx, end, cells, vals);@*/
+ ListItem_t *index = l->pxIndex;
+ /*@close xLIST(l, len, idx, end, cells, vals);@*/
+ /*@close exists(l);@*/
+ uxListRemove( index );
+ /*@open xLIST(l, len-1, x1, end, cons(end, cons(x1, cells_tl)), cons(portMAX_DELAY, cons(1, vals_tl)));@*/
+ index = l->pxIndex;
+ /*@close xLIST(l, len-1, x1, end, cons(end, cons(x1, cells_tl)), cons(portMAX_DELAY, cons(1, vals_tl)));@*/
+ /*@close exists(l);@*/
+ uxListRemove( index );
+}
diff --git a/FreeRTOS/Test/VeriFast/list/vListInitialise.c b/FreeRTOS/Test/VeriFast/list/vListInitialise.c
new file mode 100644
index 000000000..6ea02e6af
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/list/vListInitialise.c
@@ -0,0 +1,71 @@
+/*
+ * FreeRTOS VeriFast Proofs
+ * Copyright (C) Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "proof/list.h"
+
+/*@
+predicate xLIST_uninitialised(struct xLIST *l) =
+ l->uxNumberOfItems |-> _ &*&
+ l->pxIndex |-> _ &*&
+ l->xListEnd.xItemValue |-> _ &*&
+ l->xListEnd.pxNext |-> _ &*&
+ l->xListEnd.pxPrevious |-> _ &*&
+ l->xListEnd.pvOwner |-> _ &*&
+ l->xListEnd.pxContainer |-> _ &*&
+ struct_xLIST_ITEM_padding(&l->xListEnd);
+@*/
+
+void vListInitialise( List_t * const pxList )
+/*@requires xLIST_uninitialised(pxList);@*/
+/*@ensures xLIST(pxList, 0, ?end, end, singleton(end), singleton(portMAX_DELAY));@*/
+{
+ /*@open xLIST_uninitialised(pxList);@*/
+
+ /* The list structure contains a list item which is used to mark the
+ * end of the list. To initialise the list the list end is inserted
+ * as the only list entry. */
+ pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
+
+ /* The list end value is the highest possible value in the list to
+ * ensure it remains at the end of the list. */
+ pxList->xListEnd.xItemValue = portMAX_DELAY;
+
+ /* The list end next and previous pointers point to itself so we know
+ * when the list is empty. */
+ pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
+ pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
+
+ pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
+
+ /* Write known values into the list if
+ * configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
+ listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
+ listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
+
+#ifdef VERIFAST /*< ***change MiniList_t to ListItem_t*** */
+ pxList->xListEnd.pxContainer = pxList;
+#endif
+ /*@ListItem_t *end = &(pxList->xListEnd);@*/
+ /*@close xLIST_ITEM(end, portMAX_DELAY, _, _, pxList);@*/
+ /*@close DLS(end, end, end, end, singleton(end), singleton(portMAX_DELAY), pxList);@*/
+ /*@close xLIST(pxList, 0, end, end, singleton(end), singleton(portMAX_DELAY));@*/
+}
diff --git a/FreeRTOS/Test/VeriFast/list/vListInitialiseItem.c b/FreeRTOS/Test/VeriFast/list/vListInitialiseItem.c
new file mode 100644
index 000000000..d744f5f28
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/list/vListInitialiseItem.c
@@ -0,0 +1,37 @@
+/*
+ * FreeRTOS VeriFast Proofs
+ * Copyright (C) Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "proof/list.h"
+
+void vListInitialiseItem( ListItem_t * const pxItem )
+/*@requires xLIST_ITEM(pxItem, _, _, _, _);@*/
+/*@ensures xLIST_ITEM(pxItem, _, _, _, NULL);@*/
+{
+ /* Make sure the list item is not recorded as being on a list. */
+ pxItem->pxContainer = NULL;
+
+ /* Write known values into the list item if
+ * configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
+ listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
+ listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
+ /*@close xLIST_ITEM(pxItem, _, _, _, NULL);@*/
+}
diff --git a/FreeRTOS/Test/VeriFast/list/vListInsert.c b/FreeRTOS/Test/VeriFast/list/vListInsert.c
new file mode 100644
index 000000000..96e333832
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/list/vListInsert.c
@@ -0,0 +1,316 @@
+/*
+ * FreeRTOS VeriFast Proofs
+ * Copyright (C) Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "proof/list.h"
+
+
+ListItem_t * choose(List_t * list);
+/*@ requires DLS(&(list->xListEnd), ?endprev, &(list->xListEnd), endprev, ?cells, ?vals, ?container);@*/
+/*@ ensures DLS(&(list->xListEnd), endprev, &(list->xListEnd), endprev, cells, vals, container) &*&
+ mem(result, cells) == true;@*/
+
+void vListInsert( List_t * const pxList,
+ ListItem_t * const pxNewListItem )
+/*@requires xLIST(pxList, ?len, ?idx, ?end, ?cells, ?vals) &*&
+ xLIST_ITEM(pxNewListItem, ?val, _, _, _);@*/
+/*@ensures xLIST(pxList, len+1, idx, end, ?new_cells, ?new_vals) &*&
+ remove(pxNewListItem, new_cells) == cells
+;@*/
+{
+ /*@xLIST_star_item(pxList, pxNewListItem);@*/
+ /*@open xLIST_ITEM(pxNewListItem, _, _, _, _);@*/
+ /*@open xLIST(pxList, len, idx, end, cells, vals);@*/
+ /*@assert DLS(end, ?endprev, end, endprev, cells, vals, pxList);@*/
+ ListItem_t * pxIterator;
+ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
+
+ /* Only effective when configASSERT() is also defined, these tests may catch
+ * the list data structures being overwritten in memory. They will not catch
+ * data errors caused by incorrect configuration or use of FreeRTOS. */
+ listTEST_LIST_INTEGRITY( pxList );
+ listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
+
+ /* Insert the new list item into the list, sorted in xItemValue order.
+ *
+ * If the list already contains a list item with the same item value then the
+ * new list item should be placed after it. This ensures that TCBs which are
+ * stored in ready lists (all of which have the same xItemValue value) get a
+ * share of the CPU. However, if the xItemValue is the same as the back marker
+ * the iteration loop below will not end. Therefore the value is checked
+ * first, and the algorithm slightly modified if necessary. */
+ if( xValueOfInsertion == portMAX_DELAY )
+ {
+ /*@open DLS(end, endprev, end, endprev, cells, vals, pxList);@*/
+ /*@open xLIST_ITEM(end, portMAX_DELAY, ?endnext, endprev, pxList);@*/
+ /*@
+ if (end != endprev)
+ {
+ assert DLS(endnext, end, end, endprev, tail(cells), tail(vals), pxList);
+ if (endnext == endprev)
+ {
+ // done
+ }
+ else
+ {
+ dls_last_mem(endnext, end, end, endprev, tail(cells));
+ split(endnext, end, end, endprev, tail(cells), tail(vals), endprev, index_of(endprev, tail(cells)));
+ }
+ open DLS(endprev, _, _, _, _, _, _);
+ open xLIST_ITEM(endprev, _, _, _, _);
+ }
+ @*/
+ pxIterator = pxList->xListEnd.pxPrevious;
+ }
+ else
+ {
+ /* *** NOTE ***********************************************************
+ * If you find your application is crashing here then likely causes are
+ * listed below. In addition see https://www.freertos.org/FAQHelp.html for
+ * more tips, and ensure configASSERT() is defined!
+ * https://www.freertos.org/a00110.html#configASSERT
+ *
+ * 1) Stack overflow -
+ * see https://www.freertos.org/Stacks-and-stack-overflow-checking.html
+ * 2) Incorrect interrupt priority assignment, especially on Cortex-M
+ * parts where numerically high priority values denote low actual
+ * interrupt priorities, which can seem counter intuitive. See
+ * https://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
+ * of configMAX_SYSCALL_INTERRUPT_PRIORITY on
+ * https://www.freertos.org/a00110.html
+ * 3) Calling an API function from within a critical section or when
+ * the scheduler is suspended, or calling an API function that does
+ * not end in "FromISR" from an interrupt.
+ * 4) Using a queue or semaphore before it has been initialised or
+ * before the scheduler has been started (are interrupts firing
+ * before vTaskStartScheduler() has been called?).
+ **********************************************************************/
+
+#ifdef VERIFAST /*< ***over-approximate list insert loop*** */
+ pxIterator = choose(pxList);
+#else
+ for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */
+ {
+ /* There is nothing to do here, just iterating to the wanted
+ * insertion position. */
+ }
+#endif
+ /*@int i = index_of(pxIterator, cells);@*/
+ /*@
+ if (pxIterator == end)
+ {
+ open DLS(end, endprev, end, endprev, cells, vals, pxList);
+ open xLIST_ITEM(end, portMAX_DELAY, ?endnext, endprev, pxList);
+ if (end != endprev)
+ {
+ assert DLS(endnext, end, end, endprev, tail(cells), tail(vals), pxList);
+ open DLS(endnext, _, _, _, _, _, _);
+ open xLIST_ITEM(endnext, _, _, _, _);
+ }
+ }
+ else
+ {
+ assert DLS(end, endprev, end, endprev, cells, vals, pxList);
+ dls_first_mem(end, endprev, end, endprev, cells);
+ assert pxIterator != end;
+ assert index_of(end, cells) == 0;
+ split(end, endprev, end, endprev, cells, vals, pxIterator, i);
+ assert DLS(end, endprev, pxIterator, ?iterprev, take(i, cells), take(i, vals), pxList);
+ assert DLS(pxIterator, iterprev, end, endprev, drop(i, cells), drop(i, vals), pxList);
+ open DLS(pxIterator, iterprev, end, endprev, drop(i, cells), drop(i, vals), pxList);
+ open xLIST_ITEM(pxIterator, _, ?iternext, iterprev, pxList);
+ if (pxIterator == endprev)
+ {
+ open DLS(end, endprev, pxIterator, iterprev, take(i, cells), take(i, vals), pxList);
+ take_take(1, i, vals);
+ assert xLIST_ITEM(end, portMAX_DELAY, _, _, _);
+ open xLIST_ITEM(iternext, _, _, pxIterator, _);
+ }
+ else
+ {
+ open DLS(iternext, pxIterator, end, endprev, _, _, _);
+ open xLIST_ITEM(iternext, _, _, pxIterator, _);
+ }
+ }@*/
+ }
+
+ pxNewListItem->pxNext = pxIterator->pxNext;
+ pxNewListItem->pxNext->pxPrevious = pxNewListItem;
+ pxNewListItem->pxPrevious = pxIterator;
+ pxIterator->pxNext = pxNewListItem;
+
+ /* Remember which list the item is in. This allows fast removal of the
+ * item later. */
+ pxNewListItem->pxContainer = pxList;
+
+ ( pxList->uxNumberOfItems )++;
+
+ /*@close xLIST_ITEM(pxNewListItem, val, ?iternext, pxIterator, pxList);@*/
+ /*@close xLIST_ITEM(pxIterator, ?iterval, pxNewListItem, ?iterprev, pxList);@*/
+ /*@
+ if( xValueOfInsertion == portMAX_DELAY )
+ {
+ assert iternext == end;
+ assert pxIterator == endprev;
+ if (end == endprev)
+ {
+ close DLS(end, pxNewListItem, pxNewListItem, end, cells, vals, pxList);
+ close DLS(pxNewListItem, end, end, pxNewListItem, singleton(pxNewListItem), singleton(val), pxList);
+ join(end, pxNewListItem, pxNewListItem, end, cells, vals,
+ pxNewListItem, end, end, pxNewListItem, singleton(pxNewListItem), singleton(val));
+ close xLIST(pxList, len+1, idx, end, append(cells, singleton(pxNewListItem)), append(vals, singleton(val)));
+ }
+ else
+ {
+ close xLIST_ITEM(end, portMAX_DELAY, ?endnext, pxNewListItem, pxList);
+ close DLS(pxNewListItem, endprev, end, pxNewListItem, singleton(pxNewListItem), singleton(val), pxList);
+ if (endnext == endprev)
+ {
+ assert xLIST_ITEM(endnext, ?endnextval, pxNewListItem, end, pxList);
+ close DLS(end, pxNewListItem, endnext, end, singleton(end), singleton(portMAX_DELAY), pxList);
+ close DLS(endnext, end, pxNewListItem, endnext, singleton(endnext), singleton(endnextval), pxList);
+ join(end, pxNewListItem, endnext, end, singleton(end), singleton(portMAX_DELAY),
+ endnext, end, pxNewListItem, endnext, singleton(endnext), singleton(endnextval));
+ assert DLS(end, pxNewListItem, pxNewListItem, endnext, cells, vals, pxList);
+ }
+ else
+ {
+ assert DLS(endnext, end, endprev, ?endprevprev, ?cells_endnext_to_endprevprev, ?vals_endnext_to_endprevprev, pxList);
+ assert cells_endnext_to_endprevprev == take(index_of(endprev, tail(cells)), tail(cells));
+ assert index_of(endprev, tail(cells)) == length(tail(cells)) - 1;
+ assert cells_endnext_to_endprevprev == take(length(tail(cells)) - 1, tail(cells));
+ assert xLIST_ITEM(endprev, ?endprevval, pxNewListItem, endprevprev, pxList);
+ close DLS(endprev, endprevprev, pxNewListItem, endprev, singleton(endprev), singleton(endprevval), pxList);
+ dls_last_mem(endnext, end, endprev, endprevprev, cells_endnext_to_endprevprev);
+ dls_star_item(endnext, endprevprev, end);
+ close DLS(end, pxNewListItem, endprev, endprevprev, cons(end, cells_endnext_to_endprevprev), cons(portMAX_DELAY, vals_endnext_to_endprevprev), pxList);
+ join(end, pxNewListItem, endprev, endprevprev, cons(end, cells_endnext_to_endprevprev), cons(portMAX_DELAY, vals_endnext_to_endprevprev),
+ endprev, endprevprev, pxNewListItem, endprev, singleton(endprev), singleton(endprevval));
+ assert DLS(end, pxNewListItem, pxNewListItem, endprev, cells, vals, pxList);
+
+ }
+ join(end, pxNewListItem, pxNewListItem, endprev, cells, vals,
+ pxNewListItem, endprev, end, pxNewListItem, singleton(pxNewListItem), singleton(val));
+ remove_append(pxNewListItem, cells, singleton(pxNewListItem));
+ close xLIST(pxList, len+1, idx, end, append(cells, singleton(pxNewListItem)), append(vals, singleton(val)));
+ }
+ }
+ else
+ {
+ if (pxIterator == end)
+ {
+ if (iternext == end)
+ {
+ close DLS(end, pxNewListItem, pxNewListItem, end, cells, vals, pxList);
+ close DLS(pxNewListItem, pxIterator, end, pxNewListItem, singleton(pxNewListItem), singleton(val), pxList);
+ join(end, pxNewListItem, pxNewListItem, end, cells, vals,
+ pxNewListItem, pxIterator, end, pxNewListItem, singleton(pxNewListItem), singleton(val));
+ close xLIST(pxList, len+1, idx, end, append(cells, singleton(pxNewListItem)), append(vals, singleton(val)));
+ }
+ else
+ {
+ close xLIST_ITEM(iternext, ?iternextval, _, pxNewListItem, pxList);
+ if (iternext == endprev)
+ {
+ close DLS(iternext, pxNewListItem, end, endprev, singleton(iternext), singleton(iternextval), pxList);
+ dls_last_mem(iternext, pxNewListItem, end, endprev, singleton(iternext));
+ }
+ else
+ {
+ assert DLS(?iternextnext, iternext, end, endprev, ?cells_iternextnext_to_endprev, ?vals_iternextnext_to_endprev, pxList);
+ close DLS(iternext, pxNewListItem, end, endprev, cons(iternext, cells_iternextnext_to_endprev), cons(iternextval, vals_iternextnext_to_endprev), pxList);
+ dls_last_mem(iternext, pxNewListItem, end, endprev, cons(iternext, cells_iternextnext_to_endprev));
+ }
+ close DLS(end, endprev, pxNewListItem, end, singleton(end), singleton(portMAX_DELAY), pxList);
+ assert DLS(iternext, pxNewListItem, end, endprev, ?cells_iternext_to_endprev, ?vals_iternext_to_endprev, pxList);
+ dls_star_item(iternext, endprev, pxNewListItem);
+ close DLS(pxNewListItem, pxIterator, end, endprev, cons(pxNewListItem, cells_iternext_to_endprev), cons(val, vals_iternext_to_endprev), pxList);
+ join(end, endprev, pxNewListItem, end, singleton(end), singleton(portMAX_DELAY),
+ pxNewListItem, pxIterator, end, endprev, cons(pxNewListItem, cells_iternext_to_endprev), cons(val, vals_iternext_to_endprev));
+ close xLIST(pxList, len+1, idx, end, cons(end, cons(pxNewListItem, cells_iternext_to_endprev)), cons(portMAX_DELAY, cons(val, vals_iternext_to_endprev)));
+ }
+ }
+ else
+ {
+ close xLIST_ITEM(iternext, ?iternextval, _, pxNewListItem, pxList);
+ if (pxIterator == endprev)
+ {
+ if (iterprev == end)
+ {
+ close DLS(end, pxNewListItem, pxIterator, end, singleton(end), singleton(portMAX_DELAY), pxList);
+ }
+ else
+ {
+ assert DLS(_, iternext, pxIterator, iterprev, ?cells1, ?vals1, _);
+ close DLS(end, pxNewListItem, pxIterator, iterprev, cons(end, cells1), cons(portMAX_DELAY, vals1), pxList);
+ }
+ int i = index_of(pxIterator, cells);
+ assert DLS(end, pxNewListItem, pxIterator, iterprev, take(i, cells), take(i, vals), pxList);
+ close DLS(pxIterator, iterprev, pxNewListItem, pxIterator, drop(i, cells), drop(i, vals), pxList);
+ close DLS(pxNewListItem, pxIterator, end, pxNewListItem, singleton(pxNewListItem), singleton(val), pxList);
+ join(end, pxNewListItem, pxIterator, iterprev, take(i, cells), take(i, vals),
+ pxIterator, iterprev, pxNewListItem, pxIterator, drop(i, cells), drop(i, vals));
+ join(end, pxNewListItem, pxNewListItem, pxIterator, cells, vals,
+ pxNewListItem, pxIterator, end, pxNewListItem, singleton(pxNewListItem), singleton(val));
+ close xLIST(pxList, len+1, idx, end, append(cells, singleton(pxNewListItem)), append(vals, singleton(val)));
+ remove_append(pxNewListItem, cells, singleton(pxNewListItem));
+ }
+ else
+ {
+ int i = index_of(pxIterator, cells);
+ if (iternext == endprev)
+ {
+ close DLS(iternext, pxNewListItem, end, endprev, singleton(iternext), singleton(iternextval), pxList);
+ }
+ else
+ {
+ assert DLS(_, iternext, end, endprev, ?cells0, ?vals0, pxList);
+ dls_star_item(end, iterprev, iternext);
+ close DLS(iternext, pxNewListItem, end, endprev, tail(drop(i, cells)), tail(drop(i, vals)), pxList);
+ }
+ drop_drop(1, i, cells);
+ drop_drop(1, i, vals);
+ assert DLS(iternext, pxNewListItem, end, endprev, drop(i+1, cells), drop(i+1, vals), pxList);
+ assert DLS(end, endprev, pxIterator, iterprev, take(i, cells), take(i, vals), pxList);
+ dls_star_item(iternext, endprev, pxNewListItem);
+ dls_last_mem(iternext, pxNewListItem, end, endprev, drop(i+1, cells));
+ close DLS(pxNewListItem, pxIterator, end, endprev, cons(pxNewListItem, drop(i+1, cells)), cons(val, drop(i+1, vals)), pxList);
+ close DLS(pxIterator, iterprev, end, endprev, cons(pxIterator, cons(pxNewListItem, drop(i+1, cells))), cons(iterval, cons(val, drop(i+1, vals))), pxList);
+ join(end, endprev, pxIterator, iterprev, take(i, cells), take(i, vals),
+ pxIterator, iterprev, end, endprev, cons(pxIterator, cons(pxNewListItem, drop(i+1, cells))), cons(iterval, cons(val, drop(i+1, vals))));
+ list<struct xLIST_ITEM * >new_cells = append(take(i, cells), cons(pxIterator, cons(pxNewListItem, drop(i+1, cells))));
+ list<TickType_t >new_vals = append(take(i, vals), cons(iterval, cons(val, drop(i+1, vals))));
+ head_append(take(i, cells), cons(pxIterator, cons(pxNewListItem, drop(i+1, cells))));
+ take_head(take(i, cells));
+ take_take(1, i, cells);
+ assert( end == head(new_cells) );
+ head_append(take(i, vals), cons(iterval, cons(val, drop(i+1, vals))));
+ take_head(take(i, vals));
+ take_take(1, i, vals);
+ assert( portMAX_DELAY == head(new_vals) );
+ append_take_drop_n(cells, index_of(pxIterator, cells));
+ close xLIST(pxList, len+1, idx, end, append(take(i, cells), cons(pxIterator, cons(pxNewListItem, drop(i+1, cells)))), append(take(i, vals), cons(iterval, cons(val, drop(i+1, vals)))));
+ mem_take_false(pxNewListItem, i, cells);
+ remove_append(pxNewListItem, take(i, cells), cons(pxIterator, cons(pxNewListItem, drop(i+1, cells))));
+ }
+ }
+ }@*/
+}
diff --git a/FreeRTOS/Test/VeriFast/list/vListInsertEnd.c b/FreeRTOS/Test/VeriFast/list/vListInsertEnd.c
new file mode 100644
index 000000000..063eeb7a6
--- /dev/null
+++ b/FreeRTOS/Test/VeriFast/list/vListInsertEnd.c
@@ -0,0 +1,234 @@
+/*
+ * FreeRTOS VeriFast Proofs
+ * Copyright (C) Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "proof/list.h"
+
+void vListInsertEnd( List_t * const pxList,
+ ListItem_t * const pxNewListItem )
+/*@requires xLIST(pxList, ?len, ?idx, ?end, ?cells, ?vals) &*&
+ xLIST_ITEM(pxNewListItem, ?val, _, _, _);@*/
+/*@ensures xLIST(pxList, len+1, idx, end, ?new_cells, ?new_vals) &*&
+ idx == end
+ ? (new_cells == append(cells, singleton(pxNewListItem)) &*&
+ new_vals == append(vals, singleton(val)))
+ : (new_cells == append(take(index_of(idx, cells), cells), append(singleton(pxNewListItem), drop(index_of(idx, cells), cells))) &*&
+ new_vals == append(take(index_of(idx, cells), vals), append(singleton(val), drop(index_of(idx, cells), vals))));@*/
+{
+ /*@xLIST_star_item(pxList, pxNewListItem);@*/
+ /*@assert mem(pxNewListItem, cells) == false;@*/
+ /*@open xLIST(pxList, len, idx, end, cells, vals);@*/
+#ifdef VERIFAST /*< const pointer declaration */
+ ListItem_t * pxIndex = pxList->pxIndex;
+#else
+ ListItem_t * const pxIndex = pxList->pxIndex;
+
+ /* Only effective when configASSERT() is also defined, these tests may catch
+ * the list data structures being overwritten in memory. They will not catch
+ * data errors caused by incorrect configuration or use of FreeRTOS. */
+ listTEST_LIST_INTEGRITY( pxList );
+ listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
+#endif
+
+ /*@open xLIST_ITEM(pxNewListItem, _, _, _, _);@*/
+ /*@assert DLS(end, ?endprev, end, _, cells, vals, pxList);@*/
+ /*@dls_first_mem(end, endprev, end, endprev, cells);@*/
+ /*@dls_last_mem(end, endprev, end, endprev, cells);@*/
+ /*@
+ if (end == idx)
+ {
+ open DLS(end, endprev, end, endprev, cells, vals, pxList);
+ open xLIST_ITEM(end, portMAX_DELAY, ?endnext, endprev, pxList);
+ if (end == endprev)
+ {
+ // Case A (singleton): idx==end==endprev
+ }
+ else
+ {
+ assert DLS(endnext, end, end, endprev, tail(cells), tail(vals), pxList);
+ if (endnext == endprev)
+ {
+ // Case B (two): idx==end and endnext==endprev
+ open DLS(endnext, end, end, endnext, _, _, _);
+ open xLIST_ITEM(endnext, _, _, _, _);
+ }
+ else
+ {
+ // Case C: idx==end and DLS:endnext...endprev
+ split(endnext, end, end, endprev, tail(cells), tail(vals), endprev, index_of(endprev, tail(cells)));
+ open DLS(endprev, _, _, _, _, _, _);
+ open xLIST_ITEM(endprev, _, _, _, _);
+ }
+ }
+ }
+ else
+ {
+ int i = index_of(idx, cells);
+ split(end, endprev, end, endprev, cells, vals, idx, i);
+ assert DLS(end, endprev, idx, ?idxprev, take(i, cells), take(i, vals), pxList);
+ assert DLS(idx, idxprev, end, endprev, drop(i, cells), drop(i, vals), pxList);
+ open DLS(idx, idxprev, end, endprev, _, _, _);
+ open xLIST_ITEM(idx, _, _, _, _);
+ if (end == idxprev)
+ {
+ // Case D: end==idxprev and DLS:idx...endprev
+ take_take(1, i, vals);
+ take_head(vals);
+ open DLS(end, endprev, idx, idxprev, take(i, cells), take(i, vals), pxList);
+ open xLIST_ITEM(end, portMAX_DELAY, _, _, _);
+ assert length(take(i, cells)) == 1;
+ }
+ else
+ {
+ // Case E: DLS:end...idxprev and DLS:idx...endprev
+ dls_last_mem(end, endprev, idx, idxprev, take(i, cells));
+ split(end, endprev, idx, idxprev, take(i, cells), take(i, vals), idxprev, index_of(idxprev, take(i, cells)));
+ open DLS(idxprev, _, _, idxprev, _, _, _);
+ length_take(i, cells);
+ drop_take_singleton(i, vals);
+ open xLIST_ITEM(idxprev, nth(i-1, vals), _, _, _);
+ }
+ }
+ @*/
+
+ /* Insert a new list item into pxList, but rather than sort the list,
+ * makes the new list item the last item to be removed by a call to
+ * listGET_OWNER_OF_NEXT_ENTRY(). */
+ pxNewListItem->pxNext = pxIndex;
+ pxNewListItem->pxPrevious = pxIndex->pxPrevious;
+
+ /* Only used during decision coverage testing. */
+ mtCOVERAGE_TEST_DELAY();
+
+ pxIndex->pxPrevious->pxNext = pxNewListItem;
+ pxIndex->pxPrevious = pxNewListItem;
+
+ /* Remember which list the item is in. */
+ pxNewListItem->pxContainer = pxList;
+
+ ( pxList->uxNumberOfItems )++;
+
+ /*@
+ if (end == idx)
+ {
+ close xLIST_ITEM(pxNewListItem, val, end, endprev, pxList);
+ close DLS(pxNewListItem, endprev, end, pxNewListItem, singleton(pxNewListItem), singleton(val), pxList);
+ close xLIST_ITEM(end, portMAX_DELAY, ?endnext, pxNewListItem, pxList);
+ if (end == endprev)
+ {
+ // Case A (singleton): idx==end==endprev
+ close DLS(end, pxNewListItem, endnext, end, cells, vals, pxList);
+ join(end, pxNewListItem, endnext, end, cells, vals,
+ pxNewListItem, endprev, end, pxNewListItem, singleton(pxNewListItem), singleton(val));
+ close xLIST(pxList, len+1, idx, end, append(cells, singleton(pxNewListItem)), append(vals, singleton(val)));
+ }
+ else
+ {
+ close xLIST_ITEM(endprev, ?endprevval, pxNewListItem, ?endprevprev, _);
+ if (endnext == endprev)
+ {
+ // Case B (two): idx==end and endnext==endprev
+ close DLS(endprev, end, pxNewListItem, endprev, singleton(endprev), singleton(endprevval), pxList);
+ close DLS(end, pxNewListItem, pxNewListItem, endprev, cells, vals, pxList);
+ join(end, pxNewListItem, pxNewListItem, endprev, cells, vals,
+ pxNewListItem, endprev, end, pxNewListItem, singleton(pxNewListItem), singleton(val));
+ close xLIST(pxList, len+1, idx, end, append(cells, singleton(pxNewListItem)), append(vals, singleton(val)));
+ }
+ else
+ {
+ // Case C: idx==end and DLS:endnext...endprev
+ close DLS(endprev, endprevprev, pxNewListItem, endprev, singleton(endprev), singleton(endprevval), pxList);
+ assert DLS(endnext, end, endprev, endprevprev, ?cells_endnext_to_endprevprev, ?vals_endnext_to_endprevprev, pxList);
+ join(endnext, end, endprev, endprevprev, cells_endnext_to_endprevprev, vals_endnext_to_endprevprev,
+ endprev, endprevprev, pxNewListItem, endprev, singleton(endprev), singleton(endprevval));
+ close DLS(end, pxNewListItem, pxNewListItem, endprev, cells, vals, pxList);
+ join(end, pxNewListItem, pxNewListItem, endprev, cells, vals,
+ pxNewListItem, endprev, end, pxNewListItem, singleton(pxNewListItem), singleton(val));
+ close xLIST(pxList, len+1, idx, end, append(cells, singleton(pxNewListItem)), append(vals, singleton(val)));
+ }
+ }
+ }
+ else
+ {
+ // Case D: end==idxprev and DLS:idx...endprev
+ // Case E: DLS:end...idxprev and DLS:idx...endprev
+ int i = index_of(idx, cells);
+ close xLIST_ITEM(pxNewListItem, val, idx, ?idxprev, pxList);
+ close xLIST_ITEM(idx, ?idxval, ?idxnext, pxNewListItem, pxList);
+ nth_drop2(vals, i);
+ assert idxval == nth(i, vals);
+ close xLIST_ITEM(idxprev, ?idxprevval, pxNewListItem, ?idxprevprev, pxList);
+
+ if (end == idxprev)
+ {
+ close DLS(end, endprev, pxNewListItem, end, singleton(end), singleton(portMAX_DELAY), pxList);
+ }
+ else
+ {
+ length_take(i, cells);
+ take_take(i-1, i, vals);
+ take_singleton(i-1, vals);
+ take_singleton(i, vals);
+ assert DLS(end, endprev, idxprev, idxprevprev, ?cells_end_to_idxprevprev, take(i-1, vals), pxList);
+ close DLS(idxprev, idxprevprev, pxNewListItem, idxprev, singleton(idxprev), singleton(idxprevval), pxList);
+ join(end, endprev, idxprev, idxprevprev, cells_end_to_idxprevprev, take(i-1, vals),
+ idxprev, idxprevprev, pxNewListItem, idxprev, singleton(idxprev), singleton(idxprevval));
+ }
+
+ if (idx == endprev)
+ {
+ close DLS(idx, pxNewListItem, end, idx, singleton(idx), singleton(idxval), pxList);
+ }
+ else
+ {
+ assert DLS(end, endprev, pxNewListItem, idxprev, ?cells_end_to_idxprev, ?vals_end_to_idxprev, pxList);
+ close DLS(idx, pxNewListItem, end, endprev, drop(i, cells), drop(i, vals), pxList);
+ }
+
+ assert DLS(end, endprev, pxNewListItem, idxprev, take(i, cells), take(i, vals), pxList);
+ assert DLS(idx, pxNewListItem, end, endprev, drop(i, cells), drop(i, vals), pxList);
+ assert xLIST_ITEM(pxNewListItem, val, idx, idxprev, pxList);
+ dls_star_item(idx, endprev, pxNewListItem);
+ close DLS(pxNewListItem, idxprev, end, endprev, cons(pxNewListItem, drop(i, cells)), cons(val, drop(i, vals)), pxList);
+ join(end, endprev, pxNewListItem, idxprev, take(i, cells), take(i, vals),
+ pxNewListItem, idxprev, end, endprev, cons(pxNewListItem, drop(i, cells)), cons(val, drop(i, vals)));
+ assert DLS(end, endprev, end, endprev, ?cells_new, ?vals_new, pxList);
+ assert cells_new == append(take(i, cells), append(singleton(pxNewListItem), drop(i, cells)));
+ assert vals_new == append(take(i, vals) , append(singleton(val), drop(i, vals)));
+ head_append(take(i, cells), append(singleton(pxNewListItem), drop(i, cells)));
+ take_take(1, i, cells);
+ head_append(take(i, vals), append(singleton(val), drop(i, vals)));
+ take_take(1, i, vals);
+ close xLIST(pxList, len+1, idx, end, cells_new, vals_new);
+ }
+ @*/
+}
+
+void client_example1( List_t * const l, ListItem_t * const pxNewListItem )
+/*@requires
+ xLIST(l, ?len, ?idx, ?end, ?cells, ?vals) &*&
+ xLIST_ITEM(pxNewListItem, ?val, _, _, _) &*&
+ idx == end;@*/
+/*@ensures
+ xLIST(l, len + 1, idx, end, _, append(vals, singleton(val)));@*/
+{
+ vListInsertEnd(l, pxNewListItem);
+}
diff --git a/FreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh b/FreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh
index 3384ea1aa..b49fc84bc 100755
--- a/FreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh
+++ b/FreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh
@@ -1,3 +1,3 @@
#!/bin/bash -eu
-NO_COVERAGE=1 EXTRA_VERIFAST_ARGS=-stats make queue | grep overhead: | sort | uniq
+NO_COVERAGE=1 EXTRA_VERIFAST_ARGS=-stats make queue list | grep overhead: | sort | uniq
diff --git a/FreeRTOS/Test/VeriFast/scripts/diff_files.md b/FreeRTOS/Test/VeriFast/scripts/diff_files.md
index 59f62d364..cfc2fb7de 100644
--- a/FreeRTOS/Test/VeriFast/scripts/diff_files.md
+++ b/FreeRTOS/Test/VeriFast/scripts/diff_files.md
@@ -16,7 +16,7 @@ implementation and the proof directory.
```
cd scripts
./generate_diff_files.sh
-# will extract to ./FreeRTOS-Kernel/generated and ./queue/generated
+# will extract to ./FreeRTOS-Kernel/generated and ./queue/generated and ./list/generated
```
Then use `diff` for a side-by-side comparison. Note that the `--color=always`
@@ -24,12 +24,14 @@ flag needs v3.4+:
```
diff --color=always --width=$COLUMNS --suppress-common-lines --side-by-side FreeRTOS-Kernel/generated queue/generated | less -r
+diff --color=always --width=$COLUMNS --suppress-common-lines --side-by-side FreeRTOS-Kernel/generated list/generated | less -r
```
Or generate a html report using `diff2html`:
```
diff -u FreeRTOS-Kernel/generated queue/generated | diff2html -i stdin
+diff -u FreeRTOS-Kernel/generated list/generated | diff2html -i stdin
```
The expectation is that the proofs make minimal changes to the original source
diff --git a/FreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh b/FreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh
index 55f9cfbd2..db4d9469a 100755
--- a/FreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh
+++ b/FreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh
@@ -1,6 +1,6 @@
#!/bin/bash -eu
-FUNCS=(
+QUEUE_FUNCS=(
prvCopyDataFromQueue
prvCopyDataToQueue
prvInitialiseNewQueue
@@ -22,6 +22,14 @@ FUNCS=(
xQueueReceiveFromISR
)
+LIST_FUNCS=(
+ uxListRemove
+ vListInitialise
+ vListInitialiseItem
+ vListInsertEnd
+ vListInsert
+)
+
if [ ! -d "FreeRTOS-Kernel" ]; then
git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git
fi
@@ -29,7 +37,11 @@ pushd FreeRTOS-Kernel > /dev/null
rm -rf tags generated
ctags --excmd=number queue.c
mkdir generated
-for f in ${FUNCS[@]}; do
+for f in ${QUEUE_FUNCS[@]}; do
+ ../extract.py tags $f > generated/$f.c
+done
+ctags --excmd=number list.c
+for f in ${LIST_FUNCS[@]}; do
../extract.py tags $f > generated/$f.c
done
popd > /dev/null
@@ -40,8 +52,19 @@ pushd queue > /dev/null
rm -rf tags generated
ctags --excmd=number *.c
mkdir generated
-for f in ${FUNCS[@]}; do
+for f in ${QUEUE_FUNCS[@]}; do
../scripts/extract.py tags $f > generated/$f.c
done
popd > /dev/null
echo "created: queue/generated"
+
+ln -fs ../list .
+pushd list > /dev/null
+rm -rf tags generated
+ctags --excmd=number *.c
+mkdir generated
+for f in ${LIST_FUNCS[@]}; do
+ ../scripts/extract.py tags $f > generated/$f.c
+done
+popd > /dev/null
+echo "created: list/generated"