2026-07-07ยท10 min readยทsota.io team

Deploy VerCors to Europe โ€” Marieke Huisman ๐Ÿ‡ณ๐Ÿ‡ฑ + University of Twente (2011), the Viper-Based Concurrent Program Verifier for Java, C, and OpenCL, on EU Infrastructure in 2026

Concurrent software is notoriously hard to verify. Race conditions, deadlocks, and atomicity violations surface at thread interleavings that neither testing nor single-threaded reasoning reaches. Formal verification of concurrent programs requires a permission model that tracks which thread owns which heap location at each program point โ€” and an encoding that discharges concurrent proof obligations automatically.

VerCors โ€” Verification of Concurrent and Distributed Systems โ€” is an open-source deductive program verifier developed at the University of Twente ๐Ÿ‡ณ๐Ÿ‡ฑ by Marieke Huisman and collaborators including Wytse Oortwijn, Pieter Bos, and Petra van den Bos, with a tool paper published at ICFEM 2017 (International Conference on Formal Engineering Methods). VerCors accepts annotated Java, C, and OpenCL programs, together with its own research language PVL (Prototypal Verification Language), and discharges proof obligations using Viper (ETH Zurich ๐Ÿ‡จ๐Ÿ‡ญ) as a backend via Silicon and Z3.

The result is a verifier that handles the full concurrency stack: sequential heap reasoning, multi-threaded Java programs with monitors and locks, parallel arrays with data races excluded by permissions, and OpenCL/CUDA GPU kernels with work-group isolation guarantees. All built on EU-native research infrastructure โ€” University of Twente (NWO-funded), ETH Zurich (SNSF-funded), with no US Cloud Act dependency.

Specification Language โ€” Annotated Java and C

VerCors specifications appear as structured comment annotations in the source language, requiring no separate specification file:

Java Method Contracts

class BankAccount {
  int balance;

  /*@
    requires Perm(balance, 1);
    ensures  Perm(balance, 1);
    ensures  balance == \old(balance) + amount;
    ensures  balance >= 0;
  @*/
  void deposit(int amount) {
    balance += amount;
  }

  /*@
    requires Perm(balance, 1);
    ensures  Perm(balance, 1);
    ensures  balance == \old(balance) - amount;
    context  amount <= \old(balance);
  @*/
  void withdraw(int amount) {
    balance -= amount;
  }
}

Perm(x.f, p) is the VerCors notation for heap ownership: Perm(balance, 1) means full (exclusive) ownership of the balance field. \old(expr) refers to the pre-state value. context is shorthand for requires and ensures combined โ€” a permission that must be held before and after the method.

C Function Contracts

VerCors supports the same annotation style for C:

/*@
  requires \pointer_block(arr, n);
  ensures  \pointer_block(arr, n);
  ensures  (\forall int i; 0 <= i && i < n; arr[i] >= 0);
@*/
void abs_array(int *arr, int n) {
  /*@ loop_invariant \pointer_block(arr, n);
    @ loop_invariant 0 <= i && i <= n;
    @ loop_invariant (\forall int j; 0 <= j && j < i; arr[j] >= 0);
  @*/
  for (int i = 0; i < n; i++) {
    if (arr[i] < 0) arr[i] = -arr[i];
  }
}

\pointer_block(arr, n) asserts ownership of all n elements of the array. The loop_invariant annotation establishes the invariant that VerCors proves is maintained by each loop iteration.

Permission Model โ€” Viper IDF in Java and C

VerCors uses the same Implicit Dynamic Frames permission model as Viper, Prusti, Gobra, and Nagini, but exposes it through Java/C annotation syntax rather than Silver IL directly.

Fractional Permissions โ€” Shared Read Access

class Config {
  int maxConnections;

  /*@
    requires Perm(maxConnections, 1\2);
    ensures  Perm(maxConnections, 1\2);
    ensures  \result == maxConnections;
  @*/
  int getMax() {
    return maxConnections;
  }
}

Perm(maxConnections, 1\2) โ€” a half-permission โ€” allows reading maxConnections but not writing it. Multiple threads can simultaneously hold half-permissions for the same field, enabling safe concurrent reads without requiring synchronisation. This is the same fractional permission arithmetic as VeriFast's [1/2]integer(p, v) and Viper's acc(x.f, 1/2).

Resource Invariants โ€” Predicate Abstractions

/*@
  resource valid() = Perm(x, 1) ** Perm(y, 1) ** x + y == 100;
@*/
class Pair {
  int x;
  int y;

  /*@
    requires valid();
    ensures  valid();
    ensures  x == newX ** y == 100 - newX;
  @*/
  void setX(int newX) {
    //@ unfold valid();
    x = newX;
    y = 100 - newX;
    //@ fold valid();
  }
}

resource defines a named permission predicate โ€” the VerCors equivalent of Viper's predicate. ** is separating conjunction: both Perm(x, 1) and Perm(y, 1) are required simultaneously, and their conjunction also asserts the invariant x + y == 100. unfold/fold make the predicate transparent at the verification point where structural reasoning is needed.

Concurrent Verification โ€” Threads, Locks, and Atomics

VerCors's primary strength is verifying concurrent programs. The permission model precisely tracks heap ownership transfer between threads, making data races statically impossible under the verified execution model.

Thread Fork/Join

class Worker implements Runnable {
  int[] data;
  int result;

  /*@
    context Perm(result, 1);
    context (\forall* int i; 0 <= i && i < data.length; Perm(data[i], 1\2));
    ensures  result == (\sum int i; 0 <= i && i < data.length; data[i]);
  @*/
  public void run() {
    result = 0;
    for (int i = 0; i < data.length; i++) {
      result += data[i];
    }
  }
}

class Main {
  /*@
    requires (\forall* int i; 0 <= i && i < arr.length; Perm(arr[i], 1));
    ensures  (\forall* int i; 0 <= i && i < arr.length; Perm(arr[i], 1));
  @*/
  static int parallelSum(int[] arr) {
    Worker w = new Worker();
    w.data = arr;
    //@ share w.result;    // transfer full permission to new thread
    Thread t = new Thread(w);
    t.start();
    t.join();
    //@ unshare w.result;  // reclaim permission after join
    return w.result;
  }
}

(\forall* int i; ... ; Perm(arr[i], 1\2)) is an iterated separating conjunction over the array โ€” each element has its own independent half-permission. share/unshare are permission-transfer ghost annotations: the forking thread gives away write permission, the joining thread reclaims it. Between start() and join(), the main thread provably cannot access w.result โ€” the permission is held by the worker thread.

Lock Invariants

/*@
  given resource lock_invariant() = Perm(count, 1) ** count >= 0;
@*/
class Counter {
  int count;
  Object lock;

  /*@
    requires held(lock);
    ensures  held(lock);
    ensures  count == \old(count) + 1;
  @*/
  void increment() {
    //@ acquire lock;
    count++;
    //@ release lock;
  }
}

Lock invariants specify what heap state is protected by a given lock object. held(lock) in the contract means the calling thread holds the lock. acquire/release ghost annotations transfer heap ownership between the thread and the lock invariant โ€” acquiring the lock gives the thread access to Perm(count, 1), releasing it hands ownership back to the invariant.

OpenCL Kernel Verification

VerCors extends its permission model to OpenCL GPU kernels โ€” a unique capability among EU formal verification tools:

/*@
  context_everywhere \ltid < 256;
  requires Perm(input[\gtid], 1\2);
  requires Perm(output[\gtid], 1);
  ensures  Perm(input[\gtid], 1\2);
  ensures  Perm(output[\gtid], 1);
  ensures  output[\gtid] == input[\gtid] * 2;
@*/
__kernel void scale(
  __global int* input,
  __global int* output
) {
  int id = get_global_id(0);
  output[id] = input[id] * 2;
}

\gtid is the global thread ID, \ltid the local thread ID within a work-group. The permission Perm(input[\gtid], 1\2) โ€” a half-permission on the thread's own input element โ€” statically prevents any kernel from writing another thread's input slot. VerCors verifies the absence of data races across the entire work-group without requiring dynamic race detection.

This makes VerCors the only EU-native verifier targeting GPU/accelerator code โ€” directly relevant to HPC and AI workloads under the EU AI Act's high-risk system requirements.

Prototypal Verification Language (PVL)

For research and teaching, VerCors includes PVL โ€” a minimal imperative language with first-class verification constructs:

class Stack {
  seq<int> elements;

  resource inv() = Perm(elements, 1);

  requires inv();
  ensures  inv();
  ensures  |elements| == \old(|elements|) + 1;
  ensures  elements[|elements|-1] == v;
  void push(int v) {
    unfold inv();
    elements = elements + [v];
    fold inv();
  }

  requires inv();
  requires |elements| > 0;
  ensures  inv();
  ensures  |elements| == \old(|elements|) - 1;
  int pop() {
    unfold inv();
    int result = elements[|elements|-1];
    elements = elements[..|elements|-1];
    fold inv();
    return result;
  }
}

PVL uses seq<T> (mathematical sequences), |elements| (length), and slice notation elements[..n] โ€” pure functional data structures that make postconditions straightforward to state and verify. PVL programs are not compiled to machine code; they exist solely for verification research and course exercises.

Industrial Applications โ€” Dutch High-Tech

The University of Twente is located in Enschede, embedded in the eastern Netherlands high-tech corridor. VerCors targets the verification needs of Dutch and European industrial partners:

ASML ๐Ÿ‡ณ๐Ÿ‡ฑ (Veldhoven) โ€” the world's only supplier of EUV lithography machines, used in every advanced semiconductor fab globally. ASML's embedded software controls nanometre-precision optical systems under hard real-time constraints. VerCors has been used in ASML-adjacent research for verifying concurrent Java middleware in lithography control systems โ€” where a race condition in exposure sequencing cannot be discovered by testing and must be excluded formally.

NXP Semiconductors ๐Ÿ‡ณ๐Ÿ‡ฑ (Eindhoven) โ€” NXP develops automotive microcontrollers (S32K series, i.MX RT) where AUTOSAR Classic C software runs concurrent tasks on multicore hardware under ISO 26262 ASIL D. VerCors C contract verification directly targets this domain.

Philips Healthcare ๐Ÿ‡ณ๐Ÿ‡ฑ (Best) โ€” medical imaging systems (MRI, CT, ultrasound) run concurrent Java pipelines for signal reconstruction. IEC 62304 Class C demands software lifecycle evidence; VerCors thread-safety proofs for Java imaging pipelines provide formal evidence complementing unit tests.

EU Funding and Institutional Context

University of Twente (Enschede, founded 1961) โ€” the Netherlands' only campus university, located 20 km from the German border in the Twente technology region. The Software Engineering group (led by Marieke Huisman) holds a chair in Formal Methods for Parallel Programming. VerCors development has been funded by:

TU Twente formal methods lineage: Ed Brinksma (E-LOTOS, ISO 15437) โ†’ Jan Tretmans (ioco conformance testing, TorX/JTorX) โ†’ Marieke Huisman (VerCors concurrent verification). The same institution contributed E-LOTOS to the ISO process algebra standardisation and now leads concurrent program verification for industrial-scale Java.

EU Ecosystem Position โ€” Viper Front-End Cluster

VerCors is the fifth major Viper front-end in the EU formal methods cluster, alongside Prusti (Rust), Gobra (Go), Nagini (Python), and VeriFast (C/Java). But VerCors adds a dimension the others do not cover: multi-language concurrent verification and GPU kernel contracts.

ToolOriginLanguageConcurrency
VerCorsUniversity of Twente ๐Ÿ‡ณ๐Ÿ‡ฑJava, C, OpenCLThreads, locks, atomics, GPU
PrustiETH Zurich ๐Ÿ‡จ๐Ÿ‡ญRustOwnership (sequential)
GobraETH Zurich ๐Ÿ‡จ๐Ÿ‡ญGoGoroutines, channels
NaginiETH Zurich ๐Ÿ‡จ๐Ÿ‡ญPythonLock/Thread annotations
VeriFastKU Leuven ๐Ÿ‡ง๐Ÿ‡ชC, JavaFractional permissions
ViperETH Zurich ๐Ÿ‡จ๐Ÿ‡ญSilver ILBackend IVL

The geographic spread: Netherlands ๐Ÿ‡ณ๐Ÿ‡ฑ + Switzerland ๐Ÿ‡จ๐Ÿ‡ญ + Belgium ๐Ÿ‡ง๐Ÿ‡ช โ€” three EU/EFTA countries, all with NWO/SNSF/FWO public science funding, none subject to US Cloud Act. The entire Viper front-end ecosystem is EU-native.

EU Regulatory Alignment

EU AI Act Art. 9 (High-Risk System Technical Documentation): VerCors thread-safety proofs for Java AI inference pipelines (concurrent prediction servers, shared model state) demonstrate that concurrent data access to model weights and patient records is governed by verified lock invariants โ€” not just by tests that cannot exhaustively cover thread interleavings.

EU AI Act Art. 10 (Data Governance for High-Risk Systems): VerCors permission proofs for concurrent ETL pipelines show that personal data flowing through parallel Java processing stages is not aliased between threads โ€” each thread owns its exclusive slice of the data, preventing unauthorised sharing across processing boundaries.

GDPR Art. 25 (Data Protection by Design): Iterated separating conjunctions over patient record arrays โ€” (\forall* int i; 0 <= i && i < records.length; Perm(records[i], 1)) โ€” formally encode that no two concurrent threads can simultaneously access the same patient record. This is data protection by design expressed as a machine-checked formal proof.

IEC 61508 SIL 3/4 (Functional Safety of E/E/PE Systems): Concurrent safety-critical software (reactor control, railway interlocking, industrial robot coordination) runs on multicore hardware where RTOS scheduling creates thread-interleaving non-determinism. VerCors lock invariant verification eliminates the class of concurrent faults that sequential analysis misses.

NIS2 Directive (Network and Information Security): Network-facing concurrent Java services (REST APIs, WebSocket handlers, concurrent message processors) are primary NIS2 targets. VerCors permission-based thread isolation proofs demonstrate that concurrent request handlers cannot corrupt shared session state โ€” addressing the class of concurrency vulnerabilities (TOCTOU, broken access control under race conditions) that NIS2 Article 21 mandates be systematically addressed.

Deploy VerCors on EU Infrastructure with sota.io

VerCors runs as a self-contained JVM tool with no external cloud dependencies โ€” verification happens locally against the Z3 SMT solver. Deploy a VerCors-integrated Java CI pipeline on sota.io โ€” the EU-native PaaS on German infrastructure, GDPR-compliant by default:

# Install VerCors (requires JDK 17+)
wget https://github.com/utwente-fmt/vercors/releases/latest/download/vercors.zip
unzip vercors.zip
export PATH=$PATH:$(pwd)/vercors/bin

# Verify a Java file
vct --silicon BankAccount.java

# Verify a C file with Silicon backend
vct --silicon abs_array.c

# Verify an OpenCL kernel
vct --silicon scale_kernel.cl

--silicon selects the Viper Silicon backend (symbolic execution + Z3). --carbon selects the Carbon backend (VCGen + Boogie + Z3) โ€” the same two backends as all other Viper front-ends.

sota.io provides:

# sota.io deploy
sota deploy --region eu-central

Free tier available. No credit card required to start.

See Also