Skip to content

Commit

Permalink
Fix valid-cleanup not being violated at abort statements
Browse files Browse the repository at this point in the history
  • Loading branch information
zafer-esen committed Feb 1, 2024
1 parent 07948bd commit 97c1a48
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 5 deletions.
3 changes: 3 additions & 0 deletions regression-tests/properties/Answers
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,6 @@ SAFE

valid-free-12-false.c
UNKNOWN (4:7 Casts between pointer and arithmetic types are not supported.)

valid-memcleanup-4-false.c
UNSAFE
2 changes: 1 addition & 1 deletion regression-tests/properties/runtests
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ TESTS="valid-free-10-true.c valid-free-3-true.c valid-free-7-false.c \
valid-memcleanup-1-true.c valid-memcleanup-array-true.c \
valid-memtrack-array-true.c valid-memcleanup-2-false.c \
valid-memcleanup-3-false.c valid-memcleanup-3-true.c \
valid-free-12-false.c"
valid-free-12-false.c valid-memcleanup-4-false.c"

for name in $TESTS; do
echo
Expand Down
10 changes: 10 additions & 0 deletions regression-tests/properties/valid-memcleanup-4-false.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <stdlib.h>

extern int nondet();
int main() {
int *p = malloc(sizeof(int));
// p is not freed before program end - violates memcleanup.
// int main with multiple exit paths
abort();
free(p);
}
15 changes: 11 additions & 4 deletions src/tricera/concurrency/CCReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ class CCReader private (prog : Program,
}

private var globalPreconditions : IFormula = true
private val globalExitPred = newPred("exit", Nil, None)

private def lookupVarNoException(name : String, enclosingFunction : String)
: Int = {
Expand Down Expand Up @@ -714,6 +713,14 @@ class CCReader private (prog : Program,
variableHints += List()
}

/**
* It is important that globalExitPred has arguments for the ghost variables
* and the heap - for instance we want to check that memory is cleaned before
* exit, and it cannot be done if the prophecy variable does not exist at
* that point. This is reachable, for instance, with the `abort` statement.
*/
private val globalExitPred = newPred("exit", allFormalVars, None)

private val structCtorsOffset = predefSignatures.size
val defObj = heap.userADTCtors.last
val structCount = structInfos.size
Expand Down Expand Up @@ -1137,12 +1144,12 @@ class CCReader private (prog : Program,
* return type, the function can still end without reaching a
* return statement - which is why there can be multiple `finalPreds`.
*/
val finalPreds =
val finalPreds = Seq(globalExitPred) ++ (
if (returnType != CCVoid) {
val exitWithoutReturnPred = translator.translateWithReturn(stm)
Seq(exitWithoutReturnPred, exitPred)
}
else Seq(translator.translateNoReturn(stm))
else Seq(translator.translateNoReturn(stm)))

/**
* Add an assertion that all pointers that are in scope at the
Expand Down Expand Up @@ -4842,7 +4849,7 @@ private def collectVarDecls(dec : Dec,
}
case _ : SjumpAbort | _ : SjumpExit => // abort() or exit(int status)
output(addRichClause(
Clause(atom(globalExitPred, Nil),
Clause(atom(globalExitPred, allFormalVarTerms take globalExitPred.arity),
List(atom(entry, allFormalVarTerms take entry.arity)),
true), srcInfo))
}
Expand Down

0 comments on commit 97c1a48

Please sign in to comment.