Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
c0e72f3
WIP on thread_id proofs
pgiarrusso-sl Aug 20, 2026
4f2111b
[mutex.v]: change token to user; comment out with_RepFor section
dkxb Aug 31, 2026
9c3b48c
replace appearance of mutex.token to user
dkxb Aug 31, 2026
39c9682
check in layout of a custom mutex proof
dkxb Aug 31, 2026
0789521
[custom_mutex_hpp_proof.v] add do_lock lemma statement
dkxb Sep 1, 2026
5b1bdda
Tweak spec and client proof
pgiarrusso-sl Sep 1, 2026
0aa1a82
Drop trailing whitespace
pgiarrusso-sl Sep 1, 2026
4e0677c
cleanups
pgiarrusso-sl Sep 1, 2026
6981a1a
Fix parentheses in Rep
pgiarrusso-sl Sep 1, 2026
f78f655
custom_mutex: atomic<bool> -> atomic<int>
pgiarrusso-sl Sep 1, 2026
bf2b4da
Proof sketch
pgiarrusso-sl Sep 1, 2026
8a893e9
progress on custom mutex proof
dkxb Sep 1, 2026
ecea73e
custom mutex proof mostly done
dkxb Sep 2, 2026
188ed8d
Import linearity, drop unused lemmas
pgiarrusso-sl Sep 2, 2026
8d0dcd1
Proof tweaks
pgiarrusso-sl Sep 2, 2026
28ba7a1
More proof tweaks
pgiarrusso-sl Sep 2, 2026
2cdf9b1
Spec tweaks
pgiarrusso-sl Sep 4, 2026
ef66521
change mutex to use a fractional used_threads and another separate pi…
dkxb Sep 4, 2026
a6271d3
mutex proof WIP
dkxb Sep 4, 2026
1bdd3eb
complete mutex ghost refactor
dkxb Sep 6, 2026
0299a7f
refactor mutex specs, std::mutex and custom mutex are both implemntation
dkxb Sep 7, 2026
0dc1f8d
better model for my_mutex, all properties described in MUTEX_SETS
dkxb Sep 9, 2026
bf5e893
mutex ghost state module instantiation is now associated with impleme…
dkxb Sep 9, 2026
8951a61
rename MUTEX_STATE to MUTEX_PREDS
dkxb Sep 9, 2026
03e10a8
code clean up
dkxb Sep 9, 2026
bb89743
more clean up
dkxb Sep 9, 2026
f3197b5
add instances to MUTEX_PREDS
dkxb Sep 9, 2026
e923867
add comments
dkxb Sep 9, 2026
e19d1cb
make lock_guard and scoped_lock compile
dkxb Sep 10, 2026
83590fa
change my_mutexes to track opened masks
dkxb Sep 12, 2026
ec5a8ce
add mutex client
dkxb Sep 14, 2026
37c20f7
[mutex.v] move mutex predicates to MUTEX_PREDS if they are not specif…
dkxb Sep 16, 2026
a78ff0b
move thread specs to [thread/spec.v], fix [custom_mutex_hpp_proof.v]
dkxb Sep 16, 2026
8da0951
add double_incr example and proof from paper as a mutex client; add s…
dkxb Sep 17, 2026
e8d5c56
Apply suggestion from @simon-skylabs
simon-skylabs Sep 17, 2026
54a00fd
Update dune.inc
pgiarrusso-sl Sep 18, 2026
cf0aa92
[mutex.v] use Axiom for assumptions in Prop.
dkxb Sep 18, 2026
9e6f4c3
[mutex.v] use Axiom for assumptions in Prop.
dkxb Sep 18, 2026
7656a02
Update rocq-brick-libstdcpp/proof/thread/spec.v
dkxb Sep 22, 2026
0e51e79
Update rocq-brick-libstdcpp/proof/lib/lock_ghost2.v
dkxb Sep 22, 2026
9092cb2
Update rocq-brick-libstdcpp/proof/lib/lock_ghost2.v
dkxb Sep 22, 2026
5a63a48
[lock_guard.v] remove qt from R; in the specs, bind qt to mutex.locke…
dkxb Sep 18, 2026
6cf2f0e
fix lock_ghost2.v
dkxb Sep 22, 2026
78578b8
refactor [recursive_mutex.v] to only contain the spec part; the atomi…
dkxb Sep 24, 2026
4ed75f3
add [transfer_with_mutex.cpp] and proof as a client example of the mutex
dkxb Sep 29, 2026
3bc6999
in [rocq-brick-libstdcpp/test/mutex/custom_recursive_mutex_hpp_proof.…
dkxb Sep 29, 2026
da0dd57
[mutex.v] and [recursive_mutex.v]'s register rule is bidirectional, s…
dkxb Sep 29, 2026
2bacd21
make the thread registration in [transfer_with_mutex_cpp_proof.v] bid…
dkxb Sep 29, 2026
cd3521e
update comments in transfer_with_mutex_cpp_proof.v
dkxb Sep 29, 2026
e32b201
remove unused current_thread in recursive_mutex.v ctor spec
dkxb Sep 29, 2026
341a7ac
update comment in recursive_mutex.v
dkxb Sep 29, 2026
b2f2382
add C::transfer() as a simpler alternative to transfer(); make inv na…
dkxb Oct 1, 2026
6fee5a5
add comment
dkxb Oct 1, 2026
ea25270
add a comment
dkxb Oct 1, 2026
8675f18
[custom_recursive_mutex.hpp] use hash for thread id equality checking
dkxb Oct 1, 2026
a08d8ad
[custom_recursive_mutex.hpp] unset owner id before releasing the lock
dkxb Oct 1, 2026
87b9ea1
started on implementation section
mansky1 Aug 31, 2026
42e29c5
start on recursive mutex implementation
mansky1 Aug 31, 2026
8afa3b1
simplify figure 7
dkxb Sep 3, 2026
615b5ef
make invariant fit in column
dkxb Sep 3, 2026
257eaa9
rework mutex implementation invariant explanation; now consistent wit…
dkxb Sep 3, 2026
c7ca3f0
add a comment
dkxb Sep 3, 2026
e3be152
started writing up the new approach to not_locked/locked
mansky1 Sep 30, 2026
2c26ca3
started explaining my_mutexes
mansky1 Sep 30, 2026
8c494e5
case study code
mansky1 Sep 30, 2026
1e04a21
set out questions for case study
mansky1 Sep 30, 2026
643e3fd
updated mutex to new approach
mansky1 Oct 1, 2026
eafd586
small notation tweaks
mansky1 Oct 1, 2026
5fb7540
add some comments to paper
dkxb Oct 5, 2026
3463b74
add comment to paper
dkxb Oct 5, 2026
42fb5c2
refactor recursive_mutex predicate interface, now similar to mutex_pred
dkxb Oct 5, 2026
3789296
fix guard_recursive_cpp_proof.v
dkxb Oct 6, 2026
2aed90c
[transfer_with_mutex_cpp_proof.v] add [my_mutexes \top] to main_spec
dkxb Oct 6, 2026
5ab7bf7
[mutex/demo_cpp_proof.v] acquireable takes a this pointer
dkxb Oct 6, 2026
5b33135
[custom_recursive_mutex.hpp] add explicit constructor
dkxb Oct 6, 2026
48df3b1
add hash functions for thread ID objects
dkxb Oct 6, 2026
56c9d8b
custom_recursive_mutex_hpp_proof.v looks good; fix MUTEX_PREDS module…
dkxb Oct 8, 2026
6770377
lock_ghost2.v: change Props in module type to axioms
dkxb Oct 8, 2026
4151175
lock_ghost2.v: mutex_sets_alloc_thread implementation does not need t…
dkxb Oct 8, 2026
6614f59
add a comment
dkxb Oct 8, 2026
1008fae
in [mutex.v] and [recursive_mutex.v]: remove register_thread, define …
dkxb Oct 8, 2026
f532382
[shared_mutex.v] refactor to use [my_mutex] and follow similar style …
dkxb Oct 12, 2026
659a750
fix shared_mutex/test_cpp_proof.v
dkxb Oct 12, 2026
a0b1d9d
add shared_mutex custom implementation and proof
dkxb Oct 12, 2026
303d82e
update dune.inc to include the rocq ast of custom_shared_mutex.hpp an…
dkxb Oct 12, 2026
956e8f1
[recursive_mutex.v] move current_thread out of acquireable
dkxb Oct 12, 2026
72aa916
remove the MUTEX_SET module type, as it has exactly one implementatio…
dkxb Oct 12, 2026
7c0c5e8
fix custom_mutex_hpp_proof.v
dkxb Oct 12, 2026
6af57fd
gpool, the ghost name for my_mutexes and mutex_set_map, is moved into…
dkxb Oct 13, 2026
0a1b844
generic [lock_guard.v] spec
dkxb Oct 13, 2026
26964a8
fix files that depend on lock_guard
dkxb Oct 13, 2026
0db3eef
fix comments
dkxb Oct 13, 2026
14561bd
plausible generic [scoped_lock.v] specs
dkxb Oct 13, 2026
5c4c5c6
remove the second, extraneous [my_mutexes] from mutex implementation …
dkxb Oct 14, 2026
66a7d9b
[custom_mutex_hpp_proof.v] and [custom_recursive_mutex_hpp_proof.v] n…
dkxb Oct 14, 2026
82c4685
[custom_mutex_hpp_proof.v] lift owner_tid_auth out of the match in state
dkxb Oct 14, 2026
b275f82
[custom_recursive_mutex_hpp_proof.v] inline an unnecessary definition
dkxb Oct 14, 2026
3816527
[lock_ghost2.v] remove the unnecessary MUTEX_TOKENS module type, keep…
dkxb Oct 14, 2026
bb267d2
simplify the token module: do not need given_token, token is just a f…
dkxb Oct 14, 2026
cab2b7c
[mutex/proof/lock_guard.v] now verifies the lock_guard template code
dkxb Oct 14, 2026
a3a1674
add <try_lock> and <try_lock_shared> for all 3 kinds of mutexes
dkxb Oct 14, 2026
5f603a0
add libcpp_tests for custom_mutex implementation
dkxb Oct 14, 2026
ac85203
let dune-gen.sh ignore C++ files under rocq-brick-libstdcpp/test/mute…
dkxb Oct 14, 2026
1a2b17a
make custom_mutex_hpp_proof.v more compact
dkxb Oct 14, 2026
6f962c9
template spec and proof for lock_guard dtor
dkxb Oct 15, 2026
ee7f4de
[Codex] Mark adapted LLVM mutex test sources as modified
pgiarrusso-sl Oct 29, 2026
ac79b86
[Codex] Fix recursive mutex sentinel linkage across translation units
pgiarrusso-sl Oct 29, 2026
be3b47a
[Codex] Track the thread-ID hash injectivity proof obligation
pgiarrusso-sl Oct 29, 2026
57bce7f
[Codex] Add scoped_lock contract test and counterexample
pgiarrusso-sl Oct 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ _RocqProject

# Only at the root, since it comes from enabling `dune.disabled` locally
/dune
*.bbl
344 changes: 247 additions & 97 deletions papers/cpp-mutex/specs.tex

Large diffs are not rendered by default.

79 changes: 73 additions & 6 deletions papers/cpp-mutex/stdcpp.tex
Original file line number Diff line number Diff line change
Expand Up @@ -419,11 +419,11 @@ \subsection{\lstinline{unique_lock}}

%how much of this detail is useful? There are a lot of variations.
\[\begin{array}{c}
\{p \mapsto R(q, m) \ast \dolock{p}{m}{K}\}\\ \texttt{unique\_lock(p)}\\ \{\ulock(\mathsf{Some}\ (\mathsf{false}, p, q, m))\} \vspace{1em}\\%constructor notation?
\{u \mapsto \ulock(m)\ast \neg \mathsf{held}(m) \ast \dolock{\mathsf{ptr}(m)}{\mathsf{m}(m)}{K}\}\\ {u\texttt{.lock()}} \\ \{m \mapsto \ulock(m[\mathsf{held} := \mathsf{true}]) \ast K\} \vspace{1em}\\
\{u \mapsto \ulock(m)\ast \mathsf{held}(m) \ast \dounlock{\mathsf{ptr}(m)}{\mathsf{m}(m)}{K}\}\\ {u\texttt{.unlock}()}\\
\{p \mapsto R(q, m) \ast \dolock{p}{m}{K}\}\\ \texttt{unique\_lock(p)}\\ \{u.\ u \mapsto \ulock(\mathsf{Some}\ (\mathsf{false}, p, q, m))\} \vspace{1em}\\%constructor notation?
\{u \mapsto \ulock(m)\ast \neg \mathsf{held}(m) \ast \dolock{\mathsf{ptr}(m)}{\mathsf{m}(m)}{K}\}\\ {\texttt{u.lock()}} \\ \{m \mapsto \ulock(m[\mathsf{held} := \mathsf{true}]) \ast K\} \vspace{1em}\\
\{u \mapsto \ulock(m)\ast \mathsf{held}(m) \ast \dounlock{\mathsf{ptr}(m)}{\mathsf{m}(m)}{K}\}\\ {\texttt{u.unlock}()}\\
\{m \mapsto \ulock(m[\mathsf{held} := \mathsf{false}]) \ast K\} \vspace{1em} \\
\{u \mapsto \ulock() \ast (\text{if } \mathsf{held}(m) \text{ then } \dounlock{\mathsf{ptr}(m)}{\mathsf{m}(m)}{K}\} \text{ else } K)\}\\ \sim u()\\ \{K \ast \text{if } m \text{ then } \mathsf{ptr}(m) \mapsto R(\mathsf{q}(m), \mathsf{m}(m)) \text { else } \mathsf{emp}\} %destructor notation, Some/None notation
\{u \mapsto \ulock() \ast (\text{if } \mathsf{held}(m) \text{ then } \dounlock{\mathsf{ptr}(m)}{\mathsf{m}(m)}{K}\} \text{ else } K)\}\\ \texttt{u.}\!\!\sim\!\texttt{unique\_lock}()\\ \{K \ast \text{if } m \text{ then } \mathsf{ptr}(m) \mapsto R(\mathsf{q}(m), \mathsf{m}(m)) \text { else } \mathsf{emp}\} %destructor notation, Some/None notation
\end{array}\]
%verify the code from cppreference or a similar example?

Expand All @@ -449,15 +449,82 @@ \subsection{\lstinline{unique_lock}}
As discussed in Section~\ref{basic-lockable}, the \lstinline{BasicLockable} requirement does not explicitly require that \lstinline{lock} lead to mutual exclusion, and indeed recursive mutexes can be \lstinline{lock}ed multiple times without being \lstinline{unlock}ed. This interacts in an interesting and useful way with \lstinline{unique_lock}'s acquisition tracking (the $\mathsf{held}$ predicate in our specifications): each \lstinline{unique_lock} can only acquire its mutex at most once, but we can construct multiple \lstinline{unique_lock}s around a single recursive mutex, each of which manages a single acquisition. %Is this equally true of lock_guard? We could call unlock once manually to illustrate the point.
The code in Figure~\ref{unique-recursive} shows how this can be used. When \lstinline{answer} is called, it acquires the recursive mutex \lstinline{m} by constructing a \lstinline{unique_lock} around it; it then calls \lstinline{inc}, which constructs another \lstinline{unique_lock} that acquires \lstinline{m} a second time. When each method returns, its \lstinline{unique_lock} is destroyed and \lstinline{m} is released once, so that \lstinline{m} is no longer locked after \lstinline{answer} returns. Our specifications can be used to verify this program. %proof outline?

\section{Case Studies?}
\input{ring_buffer.tex}
\section{Case Study: Mutex Encapsulation}
%\input{ring_buffer.tex}
%TODO: find or make some interesting examples

We have seen that enforcing the requirements of C++ mutexes requires the management of thread-specific permission predicates that must be transferred between threads and locks. We have demonstrated that this is possible in simple examples of each mutex type, but we also want to know that our approach scales to programs with multiple mutex-carrying objects. %rephrase
There are at least two possible pitfalls. First, it might be difficult for a thread to acquire two different mutexes, because we need to manually prove that the second mutex is not the same as the first. Second and more subtly, thread-specific predicates might leak through layers of abstraction. Our mutex specifications must include predicates like $\notlocked{\gamma}{t}$ that explicitly mention thread IDs, but a data structure that uses a mutex internally should not need to expose thread IDs in its interface; it should be possible to share the data structure among threads exactly as one would a non-mutex-based implementation, without extra registration steps. In this section, we verify a case study showing that we avoid both these pitfalls, suggesting that our mutex specifications can indeed be used for modular verification.

\begin{figure}[htb]
\begin{lstlisting}
class Account {
private:
unsigned long balance;
std::recursive_mutex mut; // protects balance

public:
explicit Account(unsigned long initial_balance) : balance(initial_balance) {}

void incr_balance(unsigned long i) {
std::lock_guard<std::recursive_mutex> lg(mut);
balance += i;
}

void transfer_to(Account target, unsigned long i) {
std::lock_guard<std::recursive_mutex> lg(mut);
balance -= i;
target.incr_balance(i);
}
}

int main() {
Account from{4};
Account to{2};
from.transfer_to(to, 3);
}
\end{lstlisting}
\caption{The code of our case study}
\label{transfer}
\end{figure}


The code of our case study is shown in Figure~\ref{transfer}. Each object of class \lstinline{Account} has a \lstinline{balance} protected by a mutex (in this code we use a \lstinline{recursive_mutex}, but any form of mutex would work). %make generic?
The \lstinline{transfer_to} method decrements the receiver's %terminology?
balance and increments the target object's balance, acquiring both mutexes in the process. Our questions are then:
\begin{enumerate}
\item How do we prove that we can acquire \lstinline{target}'s mutex, given that we already hold the receiver's mutex?
\item Can we use a representation predicate for \lstinline{Account} that is freely transferable between threads and does not take a thread ID as a parameter?
\end{enumerate}

%how much do we need to explain namespaces?

For question 2, recall that our specifications for \lstinline{recursive_mutex} are:
\[\begin{array}{c}
\{\currentthread{t} \ast m \mapsto_q \rmutex{\gamma}{P}\ast\acquirable{\gamma}{t}{n}{P}{a}\}\\ {\texttt{m.lock()}} \\ \{m \mapsto_q \rmutex{\gamma}{P}\ast \exists a'.\ \mathsf{acquire}(n, a, a') \ast \acquirable{\gamma}{t}{n+1}{P}{a'}\} \vspace{1em}\\
\{\currentthread{t} \ast m \mapsto_q \rmutex{\gamma}{P}\ast\acquirable{\gamma}{t}{n+1}{P}{a}\}\\ {\texttt{m.unlock}()}\\
\{m \mapsto_q \rmutex{\gamma}{P}\ast\acquirable{\gamma}{t}{n}{P}{a}\}
\end{array}\]
The $\mathsf{holds}$ predicate takes a thread $t$ that must match the current thread, and we must have it at line 15 %confirm
in order to acquire \lstinline{mut}. On the other hand, \lstinline{transfer_to} is a function that can be called by any thread that has access to the two accounts involved, and should have a specification like
\[ \{ a \mapsto_q \mathsf{account}{\gamma_a} \ast b \mapsto_q \mathsf{account}{\gamma_b} \}\ \texttt{a.transfer\_to(b, n)}\ \{ a \mapsto_q \mathsf{account}{\gamma_a} \ast b \mapsto_q \mathsf{account}{\gamma_b} \}\]
In particular, if $\mathsf{account}$ takes a thread $t$ as an argument, then we will not be able to freely transfer ownership of it between threads (since it would only be usable by that thread $t$). The mutex permission library allows us to isolate this thread-local information.

If the precondition of \lstinline{transfer_to} includes $\mathsf{holds}$, then it will also need to mention the thread $t$, and so will not be freely

The representation predicate for \lstinline{Account} is defined as
\[p \mapsto_q \mathsf{account}(\gamma) \triangleq p.\texttt{mut} \mapsto \rmutex{\gamma}{\lambda n.\ p.\texttt{balance} \mapsto n} \ast \mathsf{token}_\gamma(q)
\]
Ownership of an \lstinline{Account} is simply ownership of the mutex protecting the \lstinline{balance} field, plus ownership of the $\mathsf{token}$ that tracks whether the lock is held. In particular, it makes no mention of the $\mathsf{holds}$ predicate that appears in the precondition of the \lstinline{recursive_mutex} specifications (and explicitly takes a thread $t$ as an argument). Then, how does

\section{BRiCk Formalization}
note that BRiCk itself is an axiomatic semantics

\section{Conclusion and Future Work}
...

%the client problem: all preconditions need not_locked, can't be transferred between threads, so if we include it in an abstract predicate that predicate can't be transferred either (even if it uses locks in a way that would never allow double acquire)

condition variables, futures, shared pointers, ...

verified Pthread?
Expand Down
3 changes: 3 additions & 0 deletions rocq-brick-libstdcpp/proof/atomic/pred.v
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-License-Identifier: LGPL-2.1 WITH BlueRock Exception for use over network, see repository root for details.
*)
Require Import skylabs.auto.cpp.spec.
Require Import skylabs.bi.weakly_objective.
Require Import skylabs.cpp.spec.concepts.
Require skylabs.brick.libstdcpp.atomic.inc_int_cpp.

Expand Down Expand Up @@ -48,6 +49,8 @@ Module Type ATOMIC_PREDS.
#[global] Declare Instance R_frac_valid : CFracValid1 R.
#[global] Declare Instance R_agree : Cbn (Learn (any ==> learn_eq ==> learn_hints.fin) R).
#[global] Declare Instance R_type : Typed2 (class_name ty) R.
#[global] Declare Instance R_weakly_objective q x p :
WeaklyObjective (R q x p).
End R_props.

End ATOMIC_PREDS.
Expand Down
12 changes: 12 additions & 0 deletions rocq-brick-libstdcpp/proof/dune.inc
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,18 @@
(with-stderr-to inc_string_cpp.v.stderr (run cpp2v -v %{input} -o inc_string_cpp.v --no-elaborate --templates=inc_string_cpp_templates.v -- -std=c++20 -stdlib=libstdc++ ))))
(alias (name srcs) (deps inc_string.cpp))
)
(subdir thread
(rule
(targets thread_hpp.v.stderr thread_hpp.v thread_hpp_templates.v)
(alias test_ast)
(deps
(:input thread.hpp)
(env_var CPP2V_DOCKER_ENABLED)
(glob_files_rec ../*.hpp))
(action
(with-stderr-to thread_hpp.v.stderr (run cpp2v -v %{input} -o thread_hpp.v --no-elaborate --templates=thread_hpp_templates.v -- -std=c++20 -stdlib=libstdc++ ))))
(alias (name srcs) (deps thread.hpp))
)
(subdir vector
(rule
(targets inc_vector_cpp.v.stderr inc_vector_cpp.v inc_vector_cpp_templates.v)
Expand Down
Loading
Loading