Skip to content

Commit 90d304b

Browse files
authored
Add a new challenge to verify CStr (rust-lang#151)
Proposes a new challenge to verify the safety of `CStr` implementation. --------- Co-authored-by: Zyad Hassan <[email protected]>
1 parent 6aa2661 commit 90d304b

File tree

3 files changed

+89
-4
lines changed

3 files changed

+89
-4
lines changed

doc/src/SUMMARY.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@
2525
- [10: Memory safety of String](./challenges/0010-string.md)
2626
- [11: Safety of Methods for Numeric Primitive Types](./challenges/0011-floats-ints.md)
2727
- [12: Safety of `NonZero`](./challenges/0012-nonzero.md)
28-
28+
- [13: Safety of `CStr`](./challenges/0013-cstr.md)
2929

doc/src/challenges/0013-cstr.md

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Challenge 13: Safety of `CStr`
2+
3+
- **Status:** Open
4+
- **Solution:**
5+
- **Tracking Issue:** [#150](https://github.com/model-checking/verify-rust-std/issues/150)
6+
- **Start date:** 2024/11/04
7+
- **End date:** 2025/01/31
8+
9+
-------------------
10+
## Goal
11+
12+
Verify that `CStr` safely represents a borrowed reference to a null-terminated array of bytes sequences similar to
13+
the C string representation.
14+
15+
## Motivation
16+
17+
The `CStr` structure is meant to be used to build safe wrappers of FFI functions that may leverage `CStr::as_ptr`
18+
and the unsafe `CStr::from_ptr` constructor to provide a safe interface to other consumers.
19+
It provides safe methods to convert `CStr` to a Rust `&str` by performing UTF-8 validation, or into an owned `CString`.
20+
21+
Any issue with this structure or misusage of its unsafe methods could trigger an invalid memory access, which poses
22+
a security risk for their users.
23+
24+
## Description
25+
26+
The goal of this challenge is to ensure the safety of the `CStr` struct implementation.
27+
First, we need to specify a safety invariant that captures the essential safety properties that must be maintained.
28+
29+
Next, we should verify that all the safe, public methods respect this invariant.
30+
For example, we can check that creating a `CStr` from a byte slice with method `from_bytes_with_nul` will only yield
31+
safe values of `CStr`.
32+
33+
Finally, for unsafe methods like `from_ptr()` and `from_bytes_with_nul_unchecked`, we need to specify appropriate safety contracts.
34+
These contracts should ensure no undefined behavior occurs within the unsafe methods themselves,
35+
and that they maintain the overall safety invariant of `CStr` when called correctly.
36+
37+
### Assumptions
38+
39+
- Harnesses may be bounded.
40+
41+
### Success Criteria
42+
43+
1. Implement the `Invariant` trait for `CStr`.
44+
45+
2. Verify that the `CStr` safety invariant holds after calling any of the following public safe methods.
46+
47+
| Function | Location |
48+
|------------------------|--------------------|
49+
| `from_bytes_until_nul` | `core::ffi::c_str` |
50+
| `from_bytes_with_nul` | `core::ffi::c_str` |
51+
| `count_bytes` | `core::ffi::c_str` |
52+
| `is_empty` | `core::ffi::c_str` |
53+
| `to_bytes` | `core::ffi::c_str` |
54+
| `to_bytes_with_nul` | `core::ffi::c_str` |
55+
| `bytes` | `core::ffi::c_str` |
56+
| `to_str` | `core::ffi::c_str` |
57+
| `as_ptr` | `core::ffi::c_str` |
58+
59+
3. Annotate and verify the safety contracts for the following unsafe functions:
60+
61+
| Function | Location |
62+
|--------------------------------|---------------------|
63+
| `from_ptr` | `core::ffi::c_str` |
64+
| `from_bytes_with_nul_uncheked` | `core::ffi::c_str` |
65+
| `strlen` | `core::ffi::c_str` |
66+
67+
4. Verify that the following trait implementations for the `CStr` type are safe:
68+
69+
70+
| Trait | Implementation Location |
71+
|-------------------------------------|-------------------------|
72+
| `CloneToUninit` [^unsafe-fn] | `core::clone` |
73+
| `ops::Index<ops::RangeFrom<usize>>` | `core::ffi::c_str` |
74+
75+
[^unsafe-fn]: Unsafe functions will require safety contracts.
76+
77+
All proofs must automatically ensure the absence of the following undefined behaviors [ref](https://github.com/rust-lang/reference/blob/142b2ed77d33f37a9973772bd95e6144ed9dce43/src/behavior-considered-undefined.md):
78+
79+
- Accessing (loading from or storing to) a place that is dangling or based on a misaligned pointer.
80+
- Performing a place projection that violates the requirements of in-bounds pointer arithmetic.
81+
- Mutating immutable bytes.
82+
- Accessing uninitialized memory.
83+
84+
Note: All solutions to verification challenges need to satisfy the criteria established in the
85+
[challenge book](../general-rules.md) in addition to the ones listed above.

doc/src/tool_template.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ _Please list the license(s) that are used by your tool, and if to your knowledge
2020

2121
## Steps to Use the Tool
2222

23-
1. [First Step]
24-
2. [Second Step]
25-
3. [and so on...]
23+
1. \[First Step\]
24+
2. \[Second Step\]
25+
3. \[and so on...\]
2626

2727
## Artifacts
2828
_If there are noteworthy examples of using the tool to perform verificaiton, please include them in this section.Links, papers, etc._

0 commit comments

Comments
 (0)