Skip to content

Commit 52375e0

Browse files
dgoffredodmehala
authored andcommitted
Code review
- update fuzz documentation - revise the base64 decoder - move ConfigManager into its own .cpp - remove namespace httputil::header - more specific error code - RuntimeID rc_id_ --> std::string client_id_ - TracerId --> TracerID - remove disambiguating "template" keyword - document k_apm_capabilities - missed a spot when removing namespace httputil::header - no need to optimize target file lookup - slightly safer product parsing
1 parent 973bf3a commit 52375e0

24 files changed

+214
-200
lines changed

BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cc_library(
44
"src/datadog/base64.cpp",
55
"src/datadog/cerr_logger.cpp",
66
"src/datadog/clock.cpp",
7+
"src/datadog/config_manager.cpp",
78
"src/datadog/collector_response.cpp",
89
# "src/datadog/curl.cpp", no libcurl
910
"src/datadog/datadog_agent_config.cpp",

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ target_sources(dd_trace_cpp-objects PRIVATE
104104
src/datadog/base64.cpp
105105
src/datadog/cerr_logger.cpp
106106
src/datadog/clock.cpp
107+
src/datadog/config_manager.cpp
107108
src/datadog/collector_response.cpp
108109
src/datadog/curl.cpp
109110
src/datadog/datadog_agent_config.cpp

bin/cmake-build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ cd "$(dirname "$0")"/..
66

77
mkdir -p .build
88
cd .build
9-
cmake ..
9+
cmake .. "$@"
1010
make -j "$(nproc)"

fuzz/README.md

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,19 @@ Fuzzers
33
Each subdirectory here contains the source of an executable that [fuzz tests][1]
44
some part of the library using [LLVM's libfuzzer][2].
55

6-
There is a toplevel CMake boolean option associated with each fuzzer. The naming
7-
convention is `FUZZ_<SUBDIRECTORY_WITH_UNDERSCORES>`, e.g.
8-
`FUZZ_W3C_PROPAGATION` for the fuzzer defined in
9-
[fuzz/w3c-propagation/](./w3c-propagation/). The resulting binary is called
10-
`fuzz` by convention.
6+
There is a toplevel CMake boolean option that adds all of the fuzzer
7+
executables to the build: `BUILD_FUZZERS`.
118

12-
When building a fuzzer, the toolchain must be clang-based. For example, this
13-
is how to build the fuzzer in [fuzz/w3c-propagation](./w3c-propagation/) from
14-
the root of the repository:
9+
When building the fuzzers, the toolchain must be clang-based. For example:
1510
```console
16-
$ rm -rf .build && mkdir .build # if toolchain or test setup need clearing
17-
$ cd .build
18-
$ CC=clang CXX=clang++ cmake .. -DFUZZ_W3C_PROPAGATION=ON
19-
$ make -j $(nproc)
20-
$ fuzz/w3c-propagation/fuzz
11+
$ rm -rf .build # if toolchain needs clearing
12+
$ bin/with-toolchain llvm bin/cmake-build -DBUILD_FUZZERS=1
13+
$ .build/fuzz/w3c-propagation/w3c-propagation-fuzz
2114

2215
[... fuzzer output ...]
2316
```
2417

18+
The fuzzer executables are named `.build/fuzz/*/*-fuzz` by convention.
19+
2520
[1]: https://en.wikipedia.org/wiki/Fuzzing
2621
[2]: https://llvm.org/docs/LibFuzzer.html

fuzz/base64/main.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#include <datadog/base64.h>
22
#include <datadog/string_view.h>
33

4+
#include <cstdint>
5+
46
namespace dd = datadog::tracing;
57

68
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, size_t size) {
7-
dd::base64::decode(dd::StringView{(char*)data, size});
9+
dd::base64_decode(dd::StringView{(const char*)data, size});
810
return 0;
911
}

src/datadog/base64.cpp

Lines changed: 60 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,98 @@
11
#include "base64.h"
22

3-
#include <stdint.h>
3+
#include <cstddef>
4+
#include <cstdint>
45

56
namespace datadog {
67
namespace tracing {
7-
namespace base64 {
88

9-
#define _ 255
10-
#define SENTINEL_VALUE _
11-
#define EOL 0
9+
constexpr uint8_t k_sentinel = 255;
10+
constexpr uint8_t _ = k_sentinel; // for brevity
11+
constexpr uint8_t k_eol = 0;
1212

13-
/*
14-
* Lookup table mapping the base64 table. Invalid inputs are mapped
15-
* to the value 255.
16-
* `=` map to 0.
17-
*/
13+
// Invalid inputs are mapped to the value 255. '=' maps to 0.
1814
constexpr uint8_t k_base64_table[]{
19-
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
20-
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
21-
_, _, _, _, _, 62, _, _, _, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
22-
61, _, _, _, EOL, _, _, _, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
23-
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, _, _, _, _,
24-
_, _, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
25-
43, 44, 45, 46, 47, 48, 49, 50, 51, _, _, _, _, _, _, _, _, _, _,
26-
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
27-
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
28-
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
29-
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
30-
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
31-
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
32-
_, _, _, _, _, _, _, _, _};
33-
34-
// TODO: support input without padding?
35-
std::string decode(StringView in) {
36-
const std::size_t in_size = in.size();
37-
38-
std::string out;
39-
out.reserve(in_size);
15+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
16+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
17+
_, _, _, _, _, _, _, 62, _, _, _, 63, 52, 53, 54, 55, 56, 57,
18+
58, 59, 60, 61, _, _, _, k_eol, _, _, _, 0, 1, 2, 3, 4, 5, 6,
19+
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
20+
25, _, _, _, _, _, _, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
21+
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, _, _, _,
22+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
23+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
24+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
25+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
26+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
27+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
28+
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
29+
_, _, _, _};
30+
31+
std::string base64_decode(StringView input) {
32+
const size_t in_size = input.size();
33+
34+
std::string output;
35+
output.reserve(in_size);
4036

4137
union {
4238
uint32_t buffer;
4339
uint8_t bytes[4];
4440
} decoder;
4541

46-
std::size_t i = 0;
42+
size_t i = 0;
4743

4844
for (; i + 4 < in_size;) {
49-
auto c0 = k_base64_table[static_cast<size_t>(in[i++])];
50-
auto c1 = k_base64_table[static_cast<size_t>(in[i++])];
51-
auto c2 = k_base64_table[static_cast<size_t>(in[i++])];
52-
auto c3 = k_base64_table[static_cast<size_t>(in[i++])];
45+
uint32_t c0 = k_base64_table[static_cast<size_t>(input[i++])];
46+
uint32_t c1 = k_base64_table[static_cast<size_t>(input[i++])];
47+
uint32_t c2 = k_base64_table[static_cast<size_t>(input[i++])];
48+
uint32_t c3 = k_base64_table[static_cast<size_t>(input[i++])];
5349

54-
if (c0 == SENTINEL_VALUE || c1 == SENTINEL_VALUE || c2 == SENTINEL_VALUE ||
55-
c3 == SENTINEL_VALUE) {
50+
if (c0 == k_sentinel || c1 == k_sentinel || c2 == k_sentinel ||
51+
c3 == k_sentinel) {
5652
return "";
5753
}
5854

59-
decoder.buffer =
60-
static_cast<uint32_t>(0) | static_cast<uint32_t>(c0) << 26 |
61-
static_cast<uint32_t>(c1) << 20 | static_cast<uint32_t>(c2) << 14 |
62-
static_cast<uint32_t>(c3) << 8;
55+
decoder.buffer = 0 | c0 << 26 | c1 << 20 | c2 << 14 | c3 << 8;
6356

64-
// NOTE(@dmehala): It might seem confusion to read those bytes in reverse
57+
// NOTE(@dmehala): It might seem confusing to read those bytes input reverse
6558
// order. It is related to the architecture endianess. For now the set of
6659
// architecture we support (x86_64 and arm64) are all little-endian.
67-
out.push_back(decoder.bytes[3]);
68-
out.push_back(decoder.bytes[2]);
69-
out.push_back(decoder.bytes[1]);
60+
// TODO(@dgoffredo): I'd prefer an endian-agnostic implementation.
61+
// nginx-datadog targets x86_64 and arm64 in its binary releases, but
62+
// dd-trace-cpp targets any standard C++17 compiler.
63+
output.push_back(decoder.bytes[3]);
64+
output.push_back(decoder.bytes[2]);
65+
output.push_back(decoder.bytes[1]);
7066
}
7167

72-
if ((in_size - i) < 4) return ""; // not padded input is not supported
68+
// If padding is missing, return the empty string in lieu of an Error.
69+
if ((in_size - i) < 4) return "";
7370

74-
auto c0 = k_base64_table[static_cast<size_t>(in[i++])];
75-
auto c1 = k_base64_table[static_cast<size_t>(in[i++])];
76-
auto c2 = k_base64_table[static_cast<size_t>(in[i++])];
77-
auto c3 = k_base64_table[static_cast<size_t>(in[i++])];
71+
uint32_t c0 = k_base64_table[static_cast<size_t>(input[i++])];
72+
uint32_t c1 = k_base64_table[static_cast<size_t>(input[i++])];
73+
uint32_t c2 = k_base64_table[static_cast<size_t>(input[i++])];
74+
uint32_t c3 = k_base64_table[static_cast<size_t>(input[i++])];
7875

79-
if (c0 == SENTINEL_VALUE || c1 == SENTINEL_VALUE || c2 == SENTINEL_VALUE ||
80-
c3 == SENTINEL_VALUE) {
76+
if (c0 == k_sentinel || c1 == k_sentinel || c2 == k_sentinel ||
77+
c3 == k_sentinel) {
8178
return "";
8279
}
8380

84-
decoder.buffer = static_cast<uint32_t>(0) | static_cast<uint32_t>(c0) << 26 |
85-
static_cast<uint32_t>(c1) << 20 |
86-
static_cast<uint32_t>(c2) << 14 |
87-
static_cast<uint32_t>(c3) << 8;
81+
decoder.buffer = 0 | c0 << 26 | c1 << 20 | c2 << 14 | c3 << 8;
8882

89-
if (c2 == EOL) {
90-
out.push_back(decoder.bytes[3]);
91-
} else if (c3 == EOL) {
92-
out.push_back(decoder.bytes[3]);
93-
out.push_back(decoder.bytes[2]);
83+
if (c2 == k_eol) {
84+
output.push_back(decoder.bytes[3]);
85+
} else if (c3 == k_eol) {
86+
output.push_back(decoder.bytes[3]);
87+
output.push_back(decoder.bytes[2]);
9488
} else {
95-
out.push_back(decoder.bytes[3]);
96-
out.push_back(decoder.bytes[2]);
97-
out.push_back(decoder.bytes[1]);
89+
output.push_back(decoder.bytes[3]);
90+
output.push_back(decoder.bytes[2]);
91+
output.push_back(decoder.bytes[1]);
9892
}
9993

100-
return out;
94+
return output;
10195
}
10296

103-
#undef EOL
104-
#undef SENTINEL_VALUE
105-
#undef _
106-
107-
} // namespace base64
10897
} // namespace tracing
10998
} // namespace datadog

src/datadog/base64.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
#pragma once
22

3+
#include <string>
4+
35
#include "string_view.h"
46

57
namespace datadog {
68
namespace tracing {
7-
namespace base64 {
89

9-
/*
10-
* Decode a base64-encoded string and returns the decoded data.
11-
*
12-
* It only supported padded base64-encoded string. Providing an unpadded
13-
* input will return an empty string.
14-
*/
15-
std::string decode(StringView in);
10+
// Return the result of decoding the specified padded base64-encoded `input`. If
11+
// `input` is not padded, then return the empty string instead.
12+
std::string base64_decode(StringView input);
1613

17-
} // namespace base64
1814
} // namespace tracing
1915
} // namespace datadog

src/datadog/config_manager.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include "config_manager.h"
2+
3+
namespace datadog {
4+
namespace tracing {
5+
6+
ConfigManager::ConfigManager(const FinalizedTracerConfig& config)
7+
: clock_(config.clock),
8+
default_trace_sampler_(
9+
std::make_shared<TraceSampler>(config.trace_sampler, clock_)),
10+
current_trace_sampler_(default_trace_sampler_) {}
11+
12+
std::shared_ptr<TraceSampler> ConfigManager::get_trace_sampler() {
13+
std::lock_guard<std::mutex> lock(mutex_);
14+
return current_trace_sampler_;
15+
}
16+
17+
void ConfigManager::update(const ConfigManager::Update& conf) {
18+
std::lock_guard<std::mutex> lock(mutex_);
19+
20+
if (conf.trace_sampler) {
21+
if (auto finalized_trace_sampler_cfg =
22+
finalize_config(*conf.trace_sampler)) {
23+
current_trace_sampler_ =
24+
std::make_shared<TraceSampler>(*finalized_trace_sampler_cfg, clock_);
25+
} else {
26+
// TODO: report error
27+
}
28+
} else {
29+
current_trace_sampler_ = default_trace_sampler_;
30+
}
31+
}
32+
33+
void ConfigManager::reset() {
34+
std::lock_guard<std::mutex> lock(mutex_);
35+
current_trace_sampler_ = default_trace_sampler_;
36+
}
37+
38+
nlohmann::json ConfigManager::config_json() const {
39+
std::lock_guard<std::mutex> lock(mutex_);
40+
return nlohmann::json{
41+
{"trace_sampler", current_trace_sampler_->config_json()}};
42+
}
43+
44+
} // namespace tracing
45+
} // namespace datadog

src/datadog/config_manager.h

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
// TODO: Document
4+
35
#include <mutex>
46

57
#include "clock.h"
@@ -10,54 +12,32 @@
1012
namespace datadog {
1113
namespace tracing {
1214

13-
struct ConfigUpdate {
14-
Optional<TraceSamplerConfig> trace_sampler;
15-
};
16-
1715
class ConfigManager {
1816
mutable std::mutex mutex_;
1917
Clock clock_;
2018
std::shared_ptr<TraceSampler> default_trace_sampler_;
2119
std::shared_ptr<TraceSampler> current_trace_sampler_;
2220

2321
public:
24-
ConfigManager(const FinalizedTracerConfig& config)
25-
: clock_(config.clock),
26-
default_trace_sampler_(
27-
std::make_shared<TraceSampler>(config.trace_sampler, clock_)),
28-
current_trace_sampler_(default_trace_sampler_) {}
22+
struct Update {
23+
Optional<TraceSamplerConfig> trace_sampler;
24+
};
2925

30-
std::shared_ptr<TraceSampler> get_trace_sampler() {
31-
std::lock_guard<std::mutex> lock(mutex_);
32-
return current_trace_sampler_;
33-
}
26+
ConfigManager(const FinalizedTracerConfig& config);
3427

35-
void update(const ConfigUpdate& conf) {
36-
std::lock_guard<std::mutex> lock(mutex_);
28+
// Return the `TraceSampler` consistent with the most recent configuration.
29+
std::shared_ptr<TraceSampler> get_trace_sampler();
3730

38-
if (conf.trace_sampler) {
39-
if (auto finalized_trace_sampler_cfg =
40-
finalize_config(*conf.trace_sampler)) {
41-
current_trace_sampler_ = std::make_shared<TraceSampler>(
42-
*finalized_trace_sampler_cfg, clock_);
43-
} else {
44-
// TODO: report error
45-
}
46-
} else {
47-
current_trace_sampler_ = default_trace_sampler_;
48-
}
49-
}
31+
// Apply the specified `conf` update.
32+
void update(const Update& conf);
5033

51-
void reset() {
52-
std::lock_guard<std::mutex> lock(mutex_);
53-
current_trace_sampler_ = default_trace_sampler_;
54-
}
34+
// Restore the configuration that was passed to this object's constructor,
35+
// overriding any previous calls to `update`.
36+
void reset();
5537

56-
nlohmann::json config_json() const {
57-
std::lock_guard<std::mutex> lock(mutex_);
58-
return nlohmann::json{
59-
{"trace_sampler", current_trace_sampler_->config_json()}};
60-
}
38+
// Return a JSON representation of the current configuration managed by this
39+
// object.
40+
nlohmann::json config_json() const;
6141
};
6242

6343
} // namespace tracing

0 commit comments

Comments
 (0)