The K2 Language
Kratos2 works on an intermediate verifiation language called K2, with a semantic based on first-order logic and Satisfiability Modulo Theories.
K2 uses S-expressions for its concrete syntax.
Types
- Booleans:
bool; - Integers:
int; - Reals:
real; - Signed bit-vectors:
(sbv SIZE), whereSIZEis an integer representing the bit-width; - Unsigned bit-vectors:
(ubv SIZE); - IEEE Floating-point numbers:
(fp EXPONENT MANTISSA), whereEXPONENTis the bit-width of the exponent, andMANTISSAis the bit-width of the mantissa (without the extra implicit 1); - Maps:
(map INDEX ELEM), whereINDEXis the type of the index andELEMis the type of the element. (Maps correspond to arrays in the standard SMT-LIB theory); - Enumeratives:
(enum VALUE_1 VALUE_2 ... VALUE_N), whereVALUE_i's are the enum values. (There is no ordering relation among the values); - Functions:
(fun (ARG_1 ... ARG_N) (RET_1 ... RET_N)), whereARG_iandRET_iare the types of the input parameters and return values.
Expressions
- Variables:
(var NAME TYPE), whereNAMEis a symbol; - Constants:
(const VALUE TYPE), whereVALUEis a symbol ofTYPEis a basic type, or an association list ofTYPEis a map type; - Type conversions:
(cast NEWTYPE EXPR)and(bitcast NEWTYPE EXPR), whereNEWTYPEis a type andEXPRan expression. The actual semantics depends on both the source and destination types (not all combinations are supported); - Logical operations:
(and EXPR_1 EXPR_2),(or EXPR_1, EXPR_2),(not EXPR); - Bit-level operations (with bit-vector arguments):
(lshift EXPR_1 EXPR_2),(rshift EXPR_1 EXPR_2),(bitand EXPR_1 EXPR_2),(bitor EXPR_1, EXPR_2),(bitxor EXPR_1, EXPR_2),(bitnot EXPR); - Arithmetic operations (overloaded according to the operand types):
(add EXPR_1 EXPR_2),(sub EXPR_1 EXPR_2),(mul EXPR_1 EXPR_2),(neg EXPR),(div EXPR_1 EXPR_2),(rem EXPR_1 EXPR_2),(floor EXPR); - Comparison operators:
(eq EXPR_1 EXPR_2),(le EXPR_1 EXPR_2),(lt EXPR_1 EXPR_2),(ge EXPR_1 EXPR_2),(gt EXPR_1 EXPR_2); - IEEE floating-point predicates:
(isfinite EXPR),(isinf EXPR),(isnan EXPR),(isnormal EXPR),(issubnormal EXPR),(iszero EXPR); - Map operations:
(mapget MAP INDEX), returning the value ofMAPat the givenINDEX(corresponding to an array read in SMT-LIB), and(mapset MAP INDEX VALUE), returning a new updated map with the element atINDEXset to the givenVALUE(corresponding to an array write in SMT-LIB).
Statements
- Assignments:
(assign VAR RHS), whereVARis a variable andRHSan expression; - Assumptions:
(assume COND), whereCONDis an expression; - Havoc:
(havoc VAR), whereVARis a variable; - Label:
(label NAME), whereNAMEis a symbol; - Non-deterministic jumps:
(jump TARGET_1 ... TARGET_N), whereTARGET_iare labels; - Sequential composition:
(seq STMT_1 ... STMT_N), whereSTMT_iare statements; - Function calls:
(call FUNC ARG_1 ... ARG_N RET_1 ... RET_N), whereFUNCis an expression of function type,ARG_iare expressions, andRET_iare variables; - Conditional jumps:
(condjump COND TARGET), whereCONDis an expression andTARGETis a label. This is equivalent to the following:
(seq
(jump (label then) (label else))
(label then)
(assume COND)
(jump TARGET)
(label else)
(assume (not COND)))
where (label then) and (label else) are fresh.
Functions
(function NAME (PARAM_1 ... PARAM_N) (return RET_1 ... RET_N)
(locals VAR_1 ... VAR_N)
BODY)
where:
NAMEis the function name (a symbol);PARAM_iare the formal parameter variables. The list can be empty;RET_iare the return variables. The list can be empty;VAR_iare the local variables. The list can be empty;BODYis a statement.
Programs
A program is a list of function definitions, plus an optional list of global variables, an entry point defining the main function, an optional initial constraint, and an optional list of type definitions. The syntax is the following:
(type TYPENAME_1 TYPE_1)
...
(type TYPENAME_N TYPE_N)
(entry NAME)
(init CONSTR)
(globals VAR_1 ... VAR_N)
FUNCTION_1
...
FUNCTION_N
where:
TYPENAME_iare symbls, andTYPE_iare types. This is similar to typedefs in C, and is used to avoid having to repeat often long types;NAMEis the name of the main function (entry point);CONSTRis an expression over global variables;VAR_iare variable expressions for global variables.
Annotations and Properties
Expressions, statements and function definitions can be annotated with metadata. The syntax is the following:
(! SEXP :KEY VALUE)
where:
SEXPis an expression, statement or function declaration;KEYandVALUEare symbols.
Properties can be defined by annotating label statements as follows:
(! LABEL :error NAME)states thatLABELis unreachable;(! LABEL :notlive NAME)states thatLABELis eventually unreachable;(! LABEL :live NAME)states thatLABELcan be reached infinitely often in all infinite executions.
Example
Here is a simple C program and its equivalent formulation in K2:
C version
var glbl;
int f(int x)
{
if (glbl > 0) {
return x - 1;
} else {
glbl = 0;
return x;
}
}
void main(void)
{
int y;
y = f(23);
}
K2 version
(type cint (sbv 32))
(entry main)
(globals (var glbl cint))
(function f ((var x cint)) (return (var ret cint))
(locals)
(seq
(jump (label then) (label else))
(label then)
(assume (op gt glbl (const 0 cint)))
(assign ret (op sub x (const 1 cint)))
(jump (label end))
(label else)
(assume (op not (op gt glbl (const 0 cint))))
(assign glbl (const 0 cint))
(assign ret x)
(label end)))
(function main () (return)
(locals (var y cint))
(call f (const 23 cint) y))

