Skip to content

mpgen: Work around c++20 / capnproto 0.8 incompatibility #194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
config: [default, llvm, gnu32, sanitize]
config: [default, llvm, gnu32, sanitize, olddeps]

name: build • ${{ matrix.config }}

Expand Down
23 changes: 22 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,29 @@ endif()

include("cmake/compat_find.cmake")

find_package(CapnProto 0.7.0 REQUIRED)
find_package(Threads REQUIRED)
find_package(CapnProto 0.7 REQUIRED)

# Check for list-of-pointers memory access bug from Nov 2022
# https://nvd.nist.gov/vuln/detail/CVE-2022-46149
# https://github.com/advisories/GHSA-qqff-4vw4-f6hx
# https://github.com/capnproto/capnproto/security/advisories/GHSA-qqff-4vw4-f6hx
# https://github.com/capnproto/capnproto/blob/master/security-advisories/2022-11-30-0-pointer-list-bounds.md
# https://capnproto.org/news/2022-11-30-CVE-2022-46149-security-advisory.html
# https://dwrensha.github.io/capnproto-rust/2022/11/30/out_of_bounds_memory_access_bug.html
if(CapnProto_VERSION STREQUAL "0.7.0"
OR CapnProto_VERSION STREQUAL "0.8.0"
OR CapnProto_VERSION STREQUAL "0.9.0"
OR CapnProto_VERSION STREQUAL "0.9.1"
OR CapnProto_VERSION STREQUAL "0.10.0"
OR CapnProto_VERSION STREQUAL "0.10.1"
OR CapnProto_VERSION STREQUAL "0.10.2")
message(FATAL_ERROR
"Cap'n Proto ${CapnProto_VERSION} is affected by CVE-2022-46149.\n"
"Please install an updated package.\n"
"Details: https://github.com/advisories/GHSA-qqff-4vw4-f6hx
")
endif()

set(MPGEN_EXECUTABLE "" CACHE FILEPATH "If specified, should be full path to an external mpgen binary to use rather than the one built internally.")

Expand Down
1 change: 1 addition & 0 deletions ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ CI_CONFIG=ci/configs/default.bash ci/scripts/run.sh
CI_CONFIG=ci/configs/llvm.bash ci/scripts/run.sh
CI_CONFIG=ci/configs/gnu32.bash ci/scripts/run.sh
CI_CONFIG=ci/configs/sanitize.bash ci/scripts/run.sh
CI_CONFIG=ci/configs/olddeps.bash ci/scripts/run.sh
```

By default CI jobs will reuse their build directories. `CI_CLEAN=1` can be specified to delete them before running instead.
5 changes: 5 additions & 0 deletions ci/configs/olddeps.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CI_DESC="CI job using old Cap'n Proto version"
CI_DIR=build-olddeps
export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter -Wno-error=array-bounds"
NIX_ARGS=(--argstr capnprotoVersion "0.7.1")
BUILD_ARGS=(-k)
29 changes: 29 additions & 0 deletions ci/patches/spaceship.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
commit e3da7da967b94f373c29a198ce45f30fb9f0e517
Author: Ed Catmur <[email protected]>
Date: Tue Jan 31 16:27:04 2023 +0000

Remove operator!= synthesized by spaceship

An operator!= suppresses the reversed equality comparison candidate generation.

This is visible in clang 16 (rc0 just released) and in gcc trunk (so probably gcc 13).

diff --git a/c++/src/kj/string.h b/c++/src/kj/string.h
index 193442aa..17835892 100644
--- a/c++/src/kj/string.h
+++ b/c++/src/kj/string.h
@@ -122,10 +122,14 @@ public:
inline constexpr const char* end() const { return content.end() - 1; }

inline constexpr bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
+#if !__cpp_impl_three_way_comparison
inline constexpr bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
+#endif

inline bool operator==(const StringPtr& other) const;
+#if !__cpp_impl_three_way_comparison
inline bool operator!=(const StringPtr& other) const { return !(*this == other); }
+#endif
inline bool operator< (const StringPtr& other) const;
inline bool operator> (const StringPtr& other) const { return other < *this; }
inline bool operator<=(const StringPtr& other) const { return !(other < *this); }
2 changes: 1 addition & 1 deletion doc/install.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# libmultiprocess Installation

Installation currently requires Cap'n Proto:
Installation currently requires Cap'n Proto 0.7 or higher:

```sh
apt install libcapnp-dev capnproto
Expand Down
29 changes: 28 additions & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,39 @@
, crossPkgs ? import <nixpkgs> {}
, enableLibcxx ? false # Whether to use libc++ toolchain and libraries instead of libstdc++
, minimal ? false # Whether to create minimal shell without extra tools (faster when cross compiling)
, capnprotoVersion ? null
}:

let
lib = pkgs.lib;
llvm = crossPkgs.llvmPackages_20;
capnproto = crossPkgs.capnproto.override (lib.optionalAttrs enableLibcxx { clangStdenv = llvm.libcxxStdenv; });
capnprotoHashes = {
"0.7.0" = "sha256-Y/7dUOQPDHjniuKNRw3j8dG1NI9f/aRWpf8V0WzV9k8=";
"0.7.1" = "sha256-3cBpVmpvCXyqPUXDp12vCFCk32ZXWpkdOliNH37UwWE=";
"0.8.0" = "sha256-rfiqN83begjJ9eYjtr21/tk1GJBjmeVfa3C3dZBJ93w=";
"0.8.1" = "sha256-OZqNVYdyszro5rIe+w6YN00g6y8U/1b8dKYc214q/2o=";
"0.9.0" = "sha256-yhbDcWUe6jp5PbIXzn5EoKabXiWN8lnS08hyfxUgEQ0=";
"0.9.2" = "sha256-BspWOPZcP5nCTvmsDE62Zutox+aY5pw42d6hpH3v4cM=";
"0.10.0" = "sha256-++F4l54OMTDnJ+FO3kV/Y/VLobKVRk461dopanuU3IQ=";
"0.10.4" = "sha256-45sxnVyyYIw9i3sbFZ1naBMoUzkpP21WarzR5crg4X8=";
"1.0.0" = "sha256-NLTFJdeOzqhk4ATvkc17Sh6g/junzqYBBEoXYGH/czo=";
"1.0.2" = "sha256-LVdkqVBTeh8JZ1McdVNtRcnFVwEJRNjt0JV2l7RkuO8=";
"1.1.0" = "sha256-gxkko7LFyJNlxpTS+CWOd/p9x/778/kNIXfpDGiKM2A=";
"1.2.0" = "sha256-aDcn4bLZGq8915/NPPQsN5Jv8FRWd8cAspkG3078psc=";
};
capnprotoBase = if capnprotoVersion == null then crossPkgs.capnproto else crossPkgs.capnproto.overrideAttrs (old: {
version = capnprotoVersion;
src = crossPkgs.fetchFromGitHub {
owner = "capnproto";
repo = "capnproto";
rev = "v${capnprotoVersion}";
hash = lib.attrByPath [capnprotoVersion] "" capnprotoHashes;
};
patches = lib.optionals (lib.versionAtLeast capnprotoVersion "0.9.0" && lib.versionOlder capnprotoVersion "0.10.4") [ ./ci/patches/spaceship.patch ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

88d9504: do I read this correctly as: apply patch to versions 0.9.0 <= ... < 0.10.4?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #194 (comment)

88d9504: do I read this correctly as: apply patch to versions 0.9.0 <= ... < 0.10.4?

Yes that's right. These versions of capnproto added some c++20 support which didn't actually work with later compiler versions.

} // (lib.optionalAttrs (lib.versionOlder capnprotoVersion "0.10") {
env = { }; # Drop -std=c++20 flag forced by nixpkgs
}));
capnproto = capnprotoBase.override (lib.optionalAttrs enableLibcxx { clangStdenv = llvm.libcxxStdenv; });
clang = if enableLibcxx then llvm.libcxxClang else llvm.clang;
clang-tools = llvm.clang-tools.override { inherit enableLibcxx; };
in crossPkgs.mkShell {
Expand Down
10 changes: 5 additions & 5 deletions src/mp/gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ static void Generate(kj::StringPtr src_prefix,
const std::vector<kj::Own<const kj::ReadableDirectory>>& import_dirs)
{
std::string output_path;
if (src_prefix == ".") {
if (src_prefix == kj::StringPtr{"."}) {
output_path = src_file;
} else if (!src_file.startsWith(src_prefix) || src_file.size() <= src_prefix.size() ||
src_file[src_prefix.size()] != '/') {
Expand All @@ -156,7 +156,7 @@ static void Generate(kj::StringPtr src_prefix,
}

std::string include_path;
if (include_prefix == ".") {
if (include_prefix == kj::StringPtr{"."}) {
include_path = src_file;
} else if (!src_file.startsWith(include_prefix) || src_file.size() <= include_prefix.size() ||
src_file[include_prefix.size()] != '/') {
Expand Down Expand Up @@ -425,8 +425,8 @@ static void Generate(kj::StringPtr src_prefix,

const std::string method_prefix = Format() << message_namespace << "::" << method_interface.getShortDisplayName()
<< "::" << Cap(method_name);
const bool is_construct = method_name == "construct";
const bool is_destroy = method_name == "destroy";
const bool is_construct = method_name == kj::StringPtr{"construct"};
const bool is_destroy = method_name == kj::StringPtr{"destroy"};

struct Field
{
Expand Down Expand Up @@ -465,7 +465,7 @@ static void Generate(kj::StringPtr src_prefix,
field.result_is_set = true;
}

if (!param && field_name == "result") {
if (!param && field_name == kj::StringPtr{"result"}) {
field.retval = true;
has_result = true;
}
Expand Down