diff --git a/libsafecxx/CMakeLists.txt b/libsafecxx/CMakeLists.txt index 54faf43..36ce6d1 100644 --- a/libsafecxx/CMakeLists.txt +++ b/libsafecxx/CMakeLists.txt @@ -16,7 +16,8 @@ include(GNUInstallDirs) file( GLOB_RECURSE safe_cxx_headers CONFIGURE_DEPENDS - "include/*.h" + "single-header/*.h" + # "include/*.h" ) add_library(safe_cxx INTERFACE) @@ -24,13 +25,13 @@ add_library(safe_cxx INTERFACE) target_include_directories( safe_cxx INTERFACE - $ + $ $) target_sources( safe_cxx INTERFACE FILE_SET HEADERS - BASE_DIRS include + BASE_DIRS single-header FILES ${safe_cxx_headers} ) diff --git a/libsafecxx/test/box_test.cxx b/libsafecxx/test/box_test.cxx index 70d4105..7c315d4 100644 --- a/libsafecxx/test/box_test.cxx +++ b/libsafecxx/test/box_test.cxx @@ -4,9 +4,7 @@ #feature on safety -#include -#include - +#include #include "helpers.h" void box_constructor() safe diff --git a/libsafecxx/test/compile-fail/arc1.cxx b/libsafecxx/test/compile-fail/arc1.cxx index 76ea37d..ff52d96 100644 --- a/libsafecxx/test/compile-fail/arc1.cxx +++ b/libsafecxx/test/compile-fail/arc1.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include int main() { diff --git a/libsafecxx/test/compile-fail/box1.cxx b/libsafecxx/test/compile-fail/box1.cxx index a6c53d6..3bcd47c 100644 --- a/libsafecxx/test/compile-fail/box1.cxx +++ b/libsafecxx/test/compile-fail/box1.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include struct incomplete; diff --git a/libsafecxx/test/compile-fail/box_incomplete.cxx b/libsafecxx/test/compile-fail/box_incomplete.cxx index d34593a..3497c3a 100644 --- a/libsafecxx/test/compile-fail/box_incomplete.cxx +++ b/libsafecxx/test/compile-fail/box_incomplete.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include struct incomplete; diff --git a/libsafecxx/test/compile-fail/cell1.cxx b/libsafecxx/test/compile-fail/cell1.cxx index 1dca8d9..7757271 100644 --- a/libsafecxx/test/compile-fail/cell1.cxx +++ b/libsafecxx/test/compile-fail/cell1.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include int main() { diff --git a/libsafecxx/test/compile-fail/cell2.cxx b/libsafecxx/test/compile-fail/cell2.cxx index 67092e1..2a73ba6 100644 --- a/libsafecxx/test/compile-fail/cell2.cxx +++ b/libsafecxx/test/compile-fail/cell2.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include struct not_copy { diff --git a/libsafecxx/test/compile-fail/cell3.cxx b/libsafecxx/test/compile-fail/cell3.cxx index 4fdfafd..61ad479 100644 --- a/libsafecxx/test/compile-fail/cell3.cxx +++ b/libsafecxx/test/compile-fail/cell3.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include struct not_copy { diff --git a/libsafecxx/test/compile-fail/manually_drop1.cxx b/libsafecxx/test/compile-fail/manually_drop1.cxx index ac191fe..ff89959 100644 --- a/libsafecxx/test/compile-fail/manually_drop1.cxx +++ b/libsafecxx/test/compile-fail/manually_drop1.cxx @@ -4,8 +4,7 @@ #feature on safety -#include -#include +#include int main() { diff --git a/libsafecxx/test/compile-fail/mutex1.cxx b/libsafecxx/test/compile-fail/mutex1.cxx index b64421f..98db31a 100644 --- a/libsafecxx/test/compile-fail/mutex1.cxx +++ b/libsafecxx/test/compile-fail/mutex1.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include int main() safe { diff --git a/libsafecxx/test/compile-fail/mutex2.cxx b/libsafecxx/test/compile-fail/mutex2.cxx index 228bb8e..dc55985 100644 --- a/libsafecxx/test/compile-fail/mutex2.cxx +++ b/libsafecxx/test/compile-fail/mutex2.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include int main() safe { diff --git a/libsafecxx/test/compile-fail/mutex3.cxx b/libsafecxx/test/compile-fail/mutex3.cxx index 9ae9299..1d34e75 100644 --- a/libsafecxx/test/compile-fail/mutex3.cxx +++ b/libsafecxx/test/compile-fail/mutex3.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include int main() safe { diff --git a/libsafecxx/test/compile-fail/rc1.cxx b/libsafecxx/test/compile-fail/rc1.cxx index 7352d9d..9470a2e 100644 --- a/libsafecxx/test/compile-fail/rc1.cxx +++ b/libsafecxx/test/compile-fail/rc1.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include int main() { diff --git a/libsafecxx/test/compile-fail/ref_cell1.cxx b/libsafecxx/test/compile-fail/ref_cell1.cxx index b9222b9..2cc2a7a 100644 --- a/libsafecxx/test/compile-fail/ref_cell1.cxx +++ b/libsafecxx/test/compile-fail/ref_cell1.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include int main() { diff --git a/libsafecxx/test/compile-fail/string_view1.cxx b/libsafecxx/test/compile-fail/string_view1.cxx index 40f20b5..ee75996 100644 --- a/libsafecxx/test/compile-fail/string_view1.cxx +++ b/libsafecxx/test/compile-fail/string_view1.cxx @@ -1,6 +1,6 @@ #feature on safety -#include +#include int main() { diff --git a/libsafecxx/test/compile-fail/thread1.cxx b/libsafecxx/test/compile-fail/thread1.cxx index 84cf2f6..150a819 100644 --- a/libsafecxx/test/compile-fail/thread1.cxx +++ b/libsafecxx/test/compile-fail/thread1.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include struct [[unsafe::send(false)]] not_send { int x_; diff --git a/libsafecxx/test/compile-fail/thread2.cxx b/libsafecxx/test/compile-fail/thread2.cxx index d358a94..6d474a9 100644 --- a/libsafecxx/test/compile-fail/thread2.cxx +++ b/libsafecxx/test/compile-fail/thread2.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include struct not_send { int x_; diff --git a/libsafecxx/test/compile-fail/thread3.cxx b/libsafecxx/test/compile-fail/thread3.cxx index bb718af..9762eeb 100644 --- a/libsafecxx/test/compile-fail/thread3.cxx +++ b/libsafecxx/test/compile-fail/thread3.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include struct [[unsafe::send(false)]] not_send { int x_; diff --git a/libsafecxx/test/compile-fail/thread4.cxx b/libsafecxx/test/compile-fail/thread4.cxx index 5f9b199..4a47215 100644 --- a/libsafecxx/test/compile-fail/thread4.cxx +++ b/libsafecxx/test/compile-fail/thread4.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include void foo/(a)(int^/a x) safe {} diff --git a/libsafecxx/test/compile-fail/unsafe_cell1.cxx b/libsafecxx/test/compile-fail/unsafe_cell1.cxx index e01f6a4..cb23575 100644 --- a/libsafecxx/test/compile-fail/unsafe_cell1.cxx +++ b/libsafecxx/test/compile-fail/unsafe_cell1.cxx @@ -4,8 +4,7 @@ #feature on safety -#include -#include +#include int main() { diff --git a/libsafecxx/test/compile-fail/vector1.cxx b/libsafecxx/test/compile-fail/vector1.cxx index aee93d7..96d4846 100644 --- a/libsafecxx/test/compile-fail/vector1.cxx +++ b/libsafecxx/test/compile-fail/vector1.cxx @@ -1,7 +1,6 @@ #feature on safety -#include -#include +#include int main() safe { std2::vector strs = {}; diff --git a/libsafecxx/test/compile-fail/vector2.cxx b/libsafecxx/test/compile-fail/vector2.cxx index 2baf94c..0788b34 100644 --- a/libsafecxx/test/compile-fail/vector2.cxx +++ b/libsafecxx/test/compile-fail/vector2.cxx @@ -1,6 +1,6 @@ #feature on safety -#include +#include int main() { std2::slice_iterator it; diff --git a/libsafecxx/test/source_location_test.cxx b/libsafecxx/test/source_location_test.cxx index 087c918..89fce64 100644 --- a/libsafecxx/test/source_location_test.cxx +++ b/libsafecxx/test/source_location_test.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include #include template diff --git a/libsafecxx/test/string_view_test.cxx b/libsafecxx/test/string_view_test.cxx index 39d30bf..dd5db1e 100644 --- a/libsafecxx/test/string_view_test.cxx +++ b/libsafecxx/test/string_view_test.cxx @@ -4,10 +4,8 @@ #feature on safety -#include - +#include #include "helpers.h" -#include void string_view_constructor() safe { diff --git a/libsafecxx/test/tuple_test.cxx b/libsafecxx/test/tuple_test.cxx index 9843739..e89a8bf 100644 --- a/libsafecxx/test/tuple_test.cxx +++ b/libsafecxx/test/tuple_test.cxx @@ -4,7 +4,7 @@ #feature on safety -#include +#include struct empty {}; diff --git a/libsafecxx/test/vector_test.cxx b/libsafecxx/test/vector_test.cxx index 5d45aa7..c98e04d 100644 --- a/libsafecxx/test/vector_test.cxx +++ b/libsafecxx/test/vector_test.cxx @@ -4,10 +4,7 @@ #feature on safety -#include -#include -#include - +#include #include #include "helpers.h" diff --git a/proposal/draft.md b/proposal/draft.md index 6c9f6a5..4bb50be 100644 --- a/proposal/draft.md +++ b/proposal/draft.md @@ -89,7 +89,7 @@ Line 2: `#include ` - Include the new safe containers and algorithms. Sa Line 4: `int main() safe` - The new _safe-specifier_ is part of a function's type, just like _noexcept-specifier_. To callers, the function is marked as safe, so that it can be called from a safe context. `main`'s definition starts in a safe context, so unsafe operations such as pointer dereferences, which may raise undefined behavior, is disallowed. Rust's functions are safe by default. C++'s are unsafe by default. But that's now just a syntax difference. Once you enter a safe context in C++ by using the _safe-specifier_, you're backed by the same rigorous safety guarantees that Rust provides. -Line 5: `std2::vector vec { 11, 15, 20 };` - List initialization of a memory-safe vector. This vector is aware of lifetime parameters, so borrow checking would extend to element types that have lifetimes. The vector's constructor doesn't use `std::initializer_list`. That type is problematic for two reasons: first, users are given pointers into the argument data, and reading from pointers is unsafe; second, the `std::initializer_list` _doesn't own_ its data, making relocation impossible. For these reasons, Safe C++ introduces a `std2::initializer_list`, which can be used in a safe context and supports our ownership object model. +Line 5: `std2::vector vec { 11, 15, 20 };` - List initialization of a memory-safe vector. This vector is aware of lifetime parameters, so borrow checking would extend to element types that have lifetimes. The vector's constructor doesn't use `std::initializer_list`. That type is problematic for two reasons: first, users are given pointers into the argument data, and reading from pointers is unsafe; second, the `std::initializer_list` _doesn't own_ its data, making relocation impossible. For these reasons, Safe C++ introduces a [`std2::initializer_list`](#initializer-lists), which can be used in a safe context and supports our ownership object model. Line 7: `for(int x : vec)` - Ranged-for on the vector. The standard mechanism returns a pair of iterators, which are pointers wrapped in classes. C++ iterators are unsafe. They come in begin and end pairs, and don't share common lifetime parameters, making borrow checking them impractical. The Safe C++ version uses slice iterators, which resemble Rust's `Iterator`.[@rust-iterator] These safe types use lifetime parameters making them robust against iterator invalidation. @@ -349,10 +349,6 @@ A memory-safe language should be robust against data races to shared mutable sta A thread-safe language enforces data race safety in its type system. Safe C++ makes it impossible, in a safe context, to produce data race UB. -** Figure out thread::join consuming function issue so we can do the thread sample. - - - ### Runtime checks One of the most common vulnerabilities is out-of-bounds access. By default, all array-like accesses are checked in Safe C++. This includes both arrays and slices. @@ -2586,7 +2582,9 @@ In addition to the core safety features, there are many new types that put a dem The US Government is telling industry to stop using C++ for reasons of national security. Academia is turning away in favor of languages like Rust and Swift that are built on modern technology. Tech executives are pushing their organizations to move to Rust.[@russinovich] All this dilutes the language's value to novices. That's trouble for companies which rely on a pipeline of new C++ developers to continue their operations. -Instead of being received as a threat, the safety model developed by Rust can be viewed as a way through for C++. The Rust community has spent a decade generating _soundness knowledge_, which is the tactics and strategies (interior mutability, send/sync, borrow checking, and so on) for achieving memory safety without the overhead of garbage collection. That soundness knowledge directly informs this memory-safe overhaul of C++. The sensible thing to do is to adopt the safety technology that security professionals insist that we use by bringing it into C++. +Instead of being received as a threat, Rust's safety model should be received as a way to rapidly improve C++. The Rust community spent a decade generating _soundness knowledge_, the tactics and strategy (interior mutability, send/sync, borrow checking) for achieving memory safety without the overhead of garbage collection. That soundness knowledge directly informs our extension of C++. If we want to + +The sensible thing to do is to adopt the safety technology that security professionals insist that we use by bringing it into C++. Everything in this proposal took about 18 months to design and implement in Circle. With participation from industry, we could resolve the remaining design questions and in another 18 months have a language and standard library robust enough for mainstream evaluation. While Safe C++ is a large extension to the language, the cost of building new tooling is not steep. If C++ continues to go forward without a memory safety strategy, that's because institutional users are choosing not to pursue it; it's not because memory-safe tooling is too expensive or difficult to build.