Skip to content

Commit a334bbe

Browse files
committed
Squashed 'src/ipc/libmultiprocess/' changes from 1b8d4a6f1e54..13424cf2ecc1
13424cf2ecc1 Merge bitcoin-core/libmultiprocess#205: cmake: check for Cap'n Proto / Clang / C++20 incompatibility 72dce118649b Merge bitcoin-core/libmultiprocess#200: event loop: add LogOptions struct and reduce the log size 85003409f964 eventloop: add `LogOptions` struct 657d80622f81 cmake: capnproto pkg missing helpful error d314057775a5 cmake: check for Cap'n Proto / Clang / C++20 incompatibility 878e84dc3030 Merge bitcoin-core/libmultiprocess#203: cmake: search capnproto in package mode only 1a85da5873c2 Merge bitcoin-core/libmultiprocess#202: doc: correct the build instructions for the example df01873e1ecb Merge bitcoin-core/libmultiprocess#197: ci: Add freebsd and macos build 3bee07ab3367 cmake: search capnproto in package mode only b6d3dc44194c doc: correct the build instructions for example fa1ac3000055 ci: Add macos and freebsd task git-subtree-dir: src/ipc/libmultiprocess git-subtree-split: 13424cf2ecc1e5eadc85556cf1f4c65e915f702a
1 parent dd68d0f commit a334bbe

File tree

10 files changed

+129
-23
lines changed

10 files changed

+129
-23
lines changed

.github/workflows/ci.yml

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
uses: vmactions/openbsd-vm@v1
1919
with:
2020
prepare: |
21-
pkg_add -v cmake ninja git python bash
21+
pkg_add -v cmake ninja git bash
2222
run: |
2323
git clone --depth=1 https://codeberg.org/OpenBSD/ports.git /usr/ports
2424
sync: 'rsync'
@@ -34,6 +34,45 @@ jobs:
3434
cd ${{ github.workspace }}
3535
CI_CONFIG="ci/configs/openbsd.bash" bash ci/scripts/ci.sh
3636
37+
build-freebsd:
38+
runs-on: ubuntu-latest
39+
name: build • freebsd
40+
defaults:
41+
run:
42+
shell: freebsd {0}
43+
steps:
44+
- uses: actions/checkout@v5
45+
46+
- name: Start FreeBSD VM
47+
uses: vmactions/freebsd-vm@v1
48+
with:
49+
prepare: |
50+
pkg install -y cmake ninja bash capnproto
51+
sync: 'rsync'
52+
copyback: false
53+
54+
- name: Run CI script
55+
run: |
56+
cd ${{ github.workspace }}
57+
CI_CONFIG="ci/configs/freebsd.bash" bash ci/scripts/ci.sh
58+
59+
build-macos:
60+
runs-on: macos-latest
61+
name: build • macos
62+
63+
steps:
64+
- uses: actions/checkout@v5
65+
66+
- name: Install dependencies
67+
env:
68+
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
69+
run: |
70+
brew install --quiet ninja capnp
71+
72+
- name: Run CI script
73+
run: |
74+
CI_CONFIG="ci/configs/macos.bash" bash ci/scripts/ci.sh
75+
3776
build:
3877
runs-on: ubuntu-latest
3978

CMakeLists.txt

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,20 @@ endif()
1313
include("cmake/compat_find.cmake")
1414

1515
find_package(Threads REQUIRED)
16-
find_package(CapnProto 0.7 REQUIRED)
16+
find_package(CapnProto 0.7 QUIET NO_MODULE)
17+
if(NOT CapnProto_FOUND)
18+
message(FATAL_ERROR
19+
"Cap'n Proto is required but was not found.\n"
20+
"To resolve, choose one of the following:\n"
21+
" - Install Cap'n Proto (version 1.0+ recommended)\n"
22+
" - For Bitcoin Core compilation build with -DENABLE_IPC=OFF to disable multiprocess support\n"
23+
)
24+
endif()
25+
26+
# Cap'n Proto compatibility checks
27+
set(CAPNPROTO_ISSUES "")
28+
set(CAPNPROTO_CVE_AFFECTED FALSE)
29+
set(CAPNPROTO_CLANG_INCOMPATIBLE FALSE)
1730

1831
# Check for list-of-pointers memory access bug from Nov 2022
1932
# https://nvd.nist.gov/vuln/detail/CVE-2022-46149
@@ -29,11 +42,43 @@ if(CapnProto_VERSION STREQUAL "0.7.0"
2942
OR CapnProto_VERSION STREQUAL "0.10.0"
3043
OR CapnProto_VERSION STREQUAL "0.10.1"
3144
OR CapnProto_VERSION STREQUAL "0.10.2")
45+
set(CAPNPROTO_CVE_AFFECTED TRUE)
46+
string(APPEND CAPNPROTO_ISSUES "- CVE-2022-46149 security vulnerability (details: https://github.com/advisories/GHSA-qqff-4vw4-f6hx)\n")
47+
endif()
48+
49+
# Check for Cap'n Proto / Clang / C++20 incompatibility
50+
# Cap'n Proto 0.9.x and 0.10.x are incompatible with Clang 16+ when using C++20
51+
# due to P2468R2 implementation. This was fixed in Cap'n Proto 1.0+.
52+
# See: https://github.com/bitcoin-core/libmultiprocess/issues/199
53+
if((CapnProto_VERSION VERSION_GREATER_EQUAL "0.9.0") AND
54+
(CapnProto_VERSION VERSION_LESS "1.0.0") AND
55+
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND
56+
(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "16") AND
57+
(CMAKE_CXX_STANDARD EQUAL 20))
58+
set(CAPNPROTO_CLANG_INCOMPATIBLE TRUE)
59+
string(APPEND CAPNPROTO_ISSUES "- Incompatible with Clang ${CMAKE_CXX_COMPILER_VERSION} when using C++20\n")
60+
endif()
61+
62+
if(CAPNPROTO_CVE_AFFECTED OR CAPNPROTO_CLANG_INCOMPATIBLE)
63+
set(RESOLUTION_OPTIONS "")
64+
65+
# Fixes both issues
66+
string(APPEND RESOLUTION_OPTIONS " - Upgrade to Cap'n Proto version 1.0 or newer (recommended)\n")
67+
68+
if(CAPNPROTO_CVE_AFFECTED AND NOT CAPNPROTO_CLANG_INCOMPATIBLE)
69+
string(APPEND RESOLUTION_OPTIONS " - Upgrade to a patched minor version (0.7.1, 0.8.1, 0.9.2, 0.10.3, or later)\n")
70+
elseif(CAPNPROTO_CLANG_INCOMPATIBLE AND NOT CAPNPROTO_CVE_AFFECTED)
71+
string(APPEND RESOLUTION_OPTIONS " - Use GCC instead of Clang\n")
72+
endif()
73+
74+
string(APPEND RESOLUTION_OPTIONS " - For Bitcoin Core compilation build with -DENABLE_IPC=OFF to disable multiprocess support\n")
75+
3276
message(FATAL_ERROR
33-
"Cap'n Proto ${CapnProto_VERSION} is affected by CVE-2022-46149.\n"
34-
"Please install an updated package.\n"
35-
"Details: https://github.com/advisories/GHSA-qqff-4vw4-f6hx
36-
")
77+
"The version of Cap'n Proto detected: ${CapnProto_VERSION} has known compatibility issues:\n"
78+
"${CAPNPROTO_ISSUES}"
79+
"To resolve, choose one of the following:\n"
80+
"${RESOLUTION_OPTIONS}"
81+
)
3782
endif()
3883

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

ci/configs/freebsd.bash

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CI_DESC="CI config for FreeBSD"
2+
CI_DIR=build-freebsd
3+
export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter"
4+
CMAKE_ARGS=(-G Ninja)
5+
BUILD_ARGS=(-k 0)

ci/configs/macos.bash

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CI_DESC="CI config for macOS"
2+
CI_DIR=build-macos
3+
export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter"
4+
CMAKE_ARGS=(-G Ninja)
5+
BUILD_ARGS=(-k 0)

doc/usage.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ A simple interface description can be found at [test/mp/test/foo.capnp](../test/
1919
A more complete example can be found in [example](../example/) and run with:
2020

2121
```sh
22-
make -C build example
23-
build/example/mpexample
22+
mkdir build
23+
cd build
24+
cmake ..
25+
make mpexamples
26+
example/mpexample
2427
```

include/mp/proxy-io.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ class Logger
130130
std::ostringstream m_buffer;
131131
};
132132

133+
struct LogOptions {
134+
135+
//! External logging callback.
136+
LogFn log_fn;
137+
138+
//! Maximum number of characters to use when representing
139+
//! request and response structs as strings.
140+
size_t max_chars{200};
141+
};
142+
133143
std::string LongThreadName(const char* exe_name);
134144

135145
//! Event loop implementation.
@@ -204,12 +214,12 @@ class EventLoop
204214

205215
Logger log()
206216
{
207-
Logger logger(false, m_log_fn);
217+
Logger logger(false, m_log_opts.log_fn);
208218
logger << "{" << LongThreadName(m_exe_name) << "} ";
209219
return logger;
210220
}
211-
Logger logPlain() { return {false, m_log_fn}; }
212-
Logger raise() { return {true, m_log_fn}; }
221+
Logger logPlain() { return {false, m_log_opts.log_fn}; }
222+
Logger raise() { return {true, m_log_opts.log_fn}; }
213223

214224
//! Process name included in thread names so combined debug output from
215225
//! multiple processes is easier to understand.
@@ -255,8 +265,8 @@ class EventLoop
255265
//! List of connections.
256266
std::list<Connection> m_incoming_connections;
257267

258-
//! External logging callback.
259-
LogFn m_log_fn;
268+
//! Logging options
269+
LogOptions m_log_opts;
260270

261271
//! External context pointer.
262272
void* m_context;

include/mp/proxy-types.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -631,13 +631,13 @@ void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, Fiel
631631
IterateFields().handleChain(*invoke_context, request, FieldList(), typename FieldObjs::BuildParams{&fields}...);
632632
proxy_client.m_context.loop->logPlain()
633633
<< "{" << thread_context.thread_name << "} IPC client send "
634-
<< TypeName<typename Request::Params>() << " " << LogEscape(request.toString());
634+
<< TypeName<typename Request::Params>() << " " << LogEscape(request.toString(), proxy_client.m_context.loop->m_log_opts.max_chars);
635635

636636
proxy_client.m_context.loop->m_task_set->add(request.send().then(
637637
[&](::capnp::Response<typename Request::Results>&& response) {
638638
proxy_client.m_context.loop->logPlain()
639639
<< "{" << thread_context.thread_name << "} IPC client recv "
640-
<< TypeName<typename Request::Results>() << " " << LogEscape(response.toString());
640+
<< TypeName<typename Request::Results>() << " " << LogEscape(response.toString(), proxy_client.m_context.loop->m_log_opts.max_chars);
641641
try {
642642
IterateFields().handleChain(
643643
*invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
@@ -701,7 +701,7 @@ kj::Promise<void> serverInvoke(Server& server, CallContext& call_context, Fn fn)
701701

702702
int req = ++server_reqs;
703703
server.m_context.loop->log() << "IPC server recv request #" << req << " "
704-
<< TypeName<typename Params::Reads>() << " " << LogEscape(params.toString());
704+
<< TypeName<typename Params::Reads>() << " " << LogEscape(params.toString(), server.m_context.loop->m_log_opts.max_chars);
705705

706706
try {
707707
using ServerContext = ServerInvokeContext<Server, CallContext>;
@@ -718,7 +718,7 @@ kj::Promise<void> serverInvoke(Server& server, CallContext& call_context, Fn fn)
718718
[&]() { return kj::Promise<CallContext>(kj::mv(call_context)); })
719719
.then([&server, req](CallContext call_context) {
720720
server.m_context.loop->log() << "IPC server send response #" << req << " " << TypeName<Results>()
721-
<< " " << LogEscape(call_context.getResults().toString());
721+
<< " " << LogEscape(call_context.getResults().toString(), server.m_context.loop->m_log_opts.max_chars);
722722
});
723723
} catch (const std::exception& e) {
724724
server.m_context.loop->log() << "IPC server unhandled exception: " << e.what();

include/mp/util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ std::string ThreadName(const char* exe_name);
203203

204204
//! Escape binary string for use in log so it doesn't trigger unicode decode
205205
//! errors in python unit tests.
206-
std::string LogEscape(const kj::StringTree& string);
206+
std::string LogEscape(const kj::StringTree& string, size_t max_size);
207207

208208
//! Callback type used by SpawnProcess below.
209209
using FdToArgsFn = std::function<std::vector<std::string>(int fd)>;

src/mp/proxy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,9 @@ EventLoop::EventLoop(const char* exe_name, LogFn log_fn, void* context)
187187
: m_exe_name(exe_name),
188188
m_io_context(kj::setupAsyncIo()),
189189
m_task_set(new kj::TaskSet(m_error_handler)),
190-
m_log_fn(std::move(log_fn)),
191190
m_context(context)
192191
{
192+
m_log_opts.log_fn = log_fn;
193193
int fds[2];
194194
KJ_SYSCALL(socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
195195
m_wait_fd = fds[0];

src/mp/util.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,11 @@ std::string ThreadName(const char* exe_name)
7676
return std::move(buffer).str();
7777
}
7878

79-
std::string LogEscape(const kj::StringTree& string)
79+
std::string LogEscape(const kj::StringTree& string, size_t max_size)
8080
{
81-
const int MAX_SIZE = 1000;
8281
std::string result;
8382
string.visit([&](const kj::ArrayPtr<const char>& piece) {
84-
if (result.size() > MAX_SIZE) return;
83+
if (result.size() > max_size) return;
8584
for (const char c : piece) {
8685
if (c == '\\') {
8786
result.append("\\\\");
@@ -92,7 +91,7 @@ std::string LogEscape(const kj::StringTree& string)
9291
} else {
9392
result.push_back(c);
9493
}
95-
if (result.size() > MAX_SIZE) {
94+
if (result.size() > max_size) {
9695
result += "...";
9796
break;
9897
}

0 commit comments

Comments
 (0)