Skip to content

Commit 998f840

Browse files
committed
More improvements around allocators
* Remove public constructors from owned_object, as these just duplicate ddwaf_object::make_* factory methods and may have confusing affects around some implicit conversions. * make borrowed objects destroy the current value when they're assigned to from an owned_object&&. This prevents some usages of to_borrowed(x), where x is uninitialized memory. * remove more implicit usages of the default allocator, causing runtime errors.
1 parent a734927 commit 998f840

File tree

117 files changed

+1668
-1350
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+1668
-1350
lines changed

fuzzer/http_endpoint_fingerprint/src/main.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
1717
{
1818
random_buffer buffer{bytes, size};
1919

20-
auto query = owned_object::make_map();
20+
auto query = owned_object::make_map(0, ddwaf::memory::get_default_resource());
2121
auto query_size = buffer.get<uint8_t>();
2222
for (uint8_t i = 0; i < query_size; ++i) {
2323
auto key = buffer.get<std::string_view>();
2424
auto value = buffer.get<std::string_view>();
2525
query.emplace(key, value);
2626
}
2727

28-
auto body = owned_object::make_map();
28+
auto body = owned_object::make_map(0, ddwaf::memory::get_default_resource());
2929
auto body_size = buffer.get<uint8_t>();
3030
for (uint8_t i = 0; i < body_size; ++i) {
3131
auto key = buffer.get<std::string_view>();
@@ -41,8 +41,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
4141
gen.eval_impl({.address = {}, .key_path = {}, .value = buffer.get<std::string_view>()},
4242
{.address = {}, .key_path = {}, .value = buffer.get<std::string_view>()},
4343
{{.address = {}, .key_path = {}, .value = query}},
44-
{{.address = {}, .key_path = {}, .value = body}}, cache, memory::get_default_resource(),
45-
deadline);
44+
{{.address = {}, .key_path = {}, .value = body}}, cache,
45+
ddwaf::memory::get_default_resource(), deadline);
4646

4747
return 0;
4848
}

fuzzer/http_header_fingerprint/src/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
2222

2323
random_buffer buffer{bytes, size};
2424

25-
auto header = owned_object::make_map();
25+
auto header = owned_object::make_map(0, ddwaf::memory::get_default_resource());
2626
auto header_size = buffer.get<uint8_t>();
2727
for (uint8_t i = 0; i < header_size; ++i) {
2828
auto value = buffer.get<std::string_view>();
@@ -41,7 +41,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
4141
processor_cache cache;
4242
ddwaf::timer deadline{2s};
4343
auto output = gen.eval_impl({.address = {}, .key_path = {}, .value = header}, cache,
44-
memory::get_default_resource(), deadline);
44+
ddwaf::memory::get_default_resource(), deadline);
4545

4646
return 0;
4747
}

fuzzer/http_network_fingerprint/src/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
2121

2222
random_buffer buffer{bytes, size};
2323

24-
auto header = owned_object::make_map();
24+
auto header = owned_object::make_map(0, ddwaf::memory::get_default_resource());
2525
auto header_size = buffer.get<uint8_t>();
2626
for (uint8_t i = 0; i < header_size; ++i) {
2727
auto value = buffer.get<std::string_view>();
@@ -40,7 +40,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
4040
processor_cache cache;
4141
ddwaf::timer deadline{2s};
4242
auto output = gen.eval_impl({.address = {}, .key_path = {}, .value = header}, cache,
43-
memory::get_default_resource(), deadline);
43+
ddwaf::memory::get_default_resource(), deadline);
4444

4545
return 0;
4646
}

fuzzer/jwt_decode/src/main.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
1818
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1919
std::string_view value{reinterpret_cast<const char *>(bytes), size};
2020

21-
auto headers = object_builder::map({{"authorization", value}});
21+
auto headers =
22+
object_builder::map({{"authorization", value}}, ddwaf::memory::get_default_resource());
2223

2324
jwt_decode gen{"id", {}, {}, false, true};
2425

2526
processor_cache cache;
2627
ddwaf::timer deadline{2s};
2728
static const std::vector<std::variant<std::string, int64_t>> key_path{"authorization"};
2829
auto output = gen.eval_impl({.address = {}, .key_path = key_path, .value = headers}, cache,
29-
memory::get_default_resource(), deadline);
30+
ddwaf::memory::get_default_resource(), deadline);
3031

3132
return 0;
3233
}

fuzzer/session_fingerprint/src/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
1717
{
1818
random_buffer buffer{bytes, size};
1919

20-
auto cookies = owned_object::make_map();
20+
auto cookies = owned_object::make_map(0, ddwaf::memory::get_default_resource());
2121
auto cookies_size = buffer.get<uint8_t>();
2222
for (uint8_t i = 0; i < cookies_size; ++i) {
2323
auto key = buffer.get<std::string_view>();
@@ -34,7 +34,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size)
3434
auto output = gen.eval_impl({{.address = {}, .key_path = {}, .value = cookies}},
3535
{{.address = {}, .key_path = {}, .value = buffer.get<std::string_view>()}},
3636
{{.address = {}, .key_path = {}, .value = buffer.get<std::string_view>()}}, cache,
37-
memory::get_default_resource(), deadline);
37+
ddwaf::memory::get_default_resource(), deadline);
3838

3939
return 0;
4040
}

include/ddwaf.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,9 @@ typedef void (*ddwaf_log_cb)(
219219
*
220220
* @return Handle to the WAF instance or NULL on error.
221221
*
222-
* @note If config is NULL, default values will be used, including the default
223-
* free function (ddwaf_object_free).
224-
*
225222
* @note If ruleset is NULL, the diagnostics object will not be initialised.
223+
*
224+
* @note The deallocation of the diagnostics must be made with default allocator.
226225
**/
227226
ddwaf_handle ddwaf_init(const ddwaf_object *ruleset, ddwaf_object *diagnostics);
228227

@@ -279,6 +278,7 @@ const char *const *ddwaf_known_actions(const ddwaf_handle handle, uint32_t *size
279278
* Context object to perform matching using the provided WAF instance.
280279
*
281280
* @param handle Handle of the WAF instance containing the ruleset definition. (nonnull)
281+
* @param output Allocator used to serve output objects created during evaluation (nonnull)
282282
283283
* @return Handle to the context instance.
284284
*
@@ -304,6 +304,9 @@ ddwaf_context ddwaf_context_init(const ddwaf_handle handle, ddwaf_allocator outp
304304
* relevant address associated to the value, which can be of an arbitrary
305305
* type.
306306
*
307+
* @param alloc (nullable) Allocator used to free the data provided. If NULL,
308+
* the data will not be freed.
309+
*
307310
* @param result (nullable) Object map containing the following items:
308311
* - events: an array of the generated events.
309312
* - actions: a map of the generated actions in the format:
@@ -318,6 +321,9 @@ ddwaf_context ddwaf_context_init(const ddwaf_handle handle, ddwaf_allocator outp
318321
* This structure must be freed by the caller and will contain all
319322
* specified keys when the value returned by ddwaf_context_eval is either
320323
* DDWAF_OK or DDWAF_MATCH and will be empty otherwise.
324+
* IMPORTANT: This object is not allocated with the allocator
325+
* passed in this call. It uses the allocator given to
326+
* ddwaf_context_init instead.
321327
* @param timeout Maximum time budget in microseconds.
322328
*
323329
* @return Return code of the operation.
@@ -380,6 +386,9 @@ ddwaf_subcontext ddwaf_subcontext_init(ddwaf_context context);
380386
* {string, <value>} in which each key represents the relevant address
381387
* associated to the value, which can be of an arbitrary type.
382388
*
389+
* @param alloc (nullable) Allocator used to free the data provided. If NULL,
390+
* the data will not be freed.
391+
*
383392
* @param result (nullable) Object map containing the following items:
384393
* - events: an array of the generated events.
385394
* - actions: a map of the generated actions in the format:
@@ -394,6 +403,9 @@ ddwaf_subcontext ddwaf_subcontext_init(ddwaf_context context);
394403
* This structure must be freed by the caller and will contain all
395404
* specified keys when the value returned by ddwaf_subcontext_eval is either
396405
* DDWAF_OK or DDWAF_MATCH and will be empty otherwise.
406+
* IMPORTANT: This object is not allocated with the allocator
407+
* passed in this call. It uses the allocator given to
408+
* ddwaf_context_init instead.
397409
* @param timeout Maximum time budget in microseconds.
398410
*
399411
* @return Return code of the operation.
@@ -509,7 +521,7 @@ ddwaf_handle ddwaf_builder_build_instance(ddwaf_builder builder);
509521
* of those matching the filter.
510522
*
511523
* @note This function is not thread-safe and the memory of the paths object must
512-
* be freed by the caller.
524+
* be freed by the caller using the default allocator.
513525
**/
514526
uint32_t ddwaf_builder_get_config_paths(ddwaf_builder builder, ddwaf_object *paths, const char *filter, uint32_t filter_len);
515527

src/attribute_collector.hpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,40 @@ class attribute_collector {
4848
attribute_collector &operator=(attribute_collector &&other) noexcept = default;
4949
~attribute_collector() = default;
5050

51-
// For types where owned_object has a single-argument constructor
51+
bool insert(std::string_view key, bool value)
52+
{
53+
return insert(key, owned_object::make_boolean(value, attributes_.alloc()));
54+
}
55+
5256
template <typename T>
53-
bool insert(std::string_view key, T &&value)
54-
requires std::constructible_from<owned_object, T>
57+
bool insert(std::string_view key, T value)
58+
requires std::is_integral_v<T> && std::is_signed_v<T>
5559
{
56-
return insert(key, owned_object{std::forward<T>(value)});
60+
return insert(key, owned_object::make_signed(value, attributes_.alloc()));
5761
}
5862

59-
// For types that require an allocator
6063
template <typename T>
61-
bool insert(std::string_view key, T &&value, nonnull_ptr<memory::memory_resource> alloc)
62-
requires std::constructible_from<owned_object, T, nonnull_ptr<memory::memory_resource>>
64+
bool insert(std::string_view key, T value)
65+
requires std::is_integral_v<T> && std::is_unsigned_v<T> && (!std::same_as<T, bool>)
66+
{
67+
return insert(key, owned_object::make_unsigned(value, attributes_.alloc()));
68+
}
69+
70+
template <typename T>
71+
bool insert(std::string_view key, T value)
72+
requires std::is_floating_point_v<T>
73+
{
74+
return insert(key, owned_object::make_float(value, attributes_.alloc()));
75+
}
76+
77+
template <typename T>
78+
bool insert(std::string_view key, T &&value)
79+
requires std::convertible_to<T, std::string_view> &&
80+
(!std::is_integral_v<std::remove_cvref_t<T>>) &&
81+
(!std::is_floating_point_v<std::remove_cvref_t<T>>)
6382
{
64-
return insert(key, owned_object{std::forward<T>(value), alloc});
83+
return insert(key, owned_object::make_string(
84+
std::string_view(std::forward<T>(value)), attributes_.alloc()));
6585
}
6686

6787
bool insert(std::string_view key, owned_object &&object);

src/dynamic_string.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ namespace ddwaf {
1313

1414
owned_object dynamic_string::to_object(nonnull_ptr<memory::memory_resource> alloc)
1515
{
16-
owned_object object;
17-
if (size_ == capacity_ && alloc->is_equal(*alloc_)) {
18-
// safety: the allocators compare equal; by definition this means alloc
19-
// (the deallocator for the owned_object) can deallocate memory from
20-
// alloc_ (the allocator for this dynamic_string)
21-
object = owned_object::unsafe_make_string_nocopy(buffer_, size_, alloc);
22-
} else {
23-
object = owned_object::make_string(buffer_, size_, alloc);
16+
bool should_copy = !(size_ == capacity_ && alloc->is_equal(*alloc_));
17+
owned_object object = should_copy ? owned_object::make_string(buffer_, size_, alloc)
18+
: // safety: the allocators compare equal; by definition
19+
// this means alloc (the deallocator for the owned_object)
20+
// can deallocate memory from alloc_ (the allocator for
21+
// this dynamic_string)
22+
owned_object::unsafe_make_string_nocopy(buffer_, size_, alloc);
23+
24+
if (should_copy) {
2425
alloc_->deallocate(buffer_, capacity_, alignof(char));
2526
}
2627
buffer_ = nullptr;

src/evaluation_engine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void set_context_event_address(object_store &store)
4242
return;
4343
}
4444

45-
store.insert(event_addr_idx, event_addr, owned_object{true});
45+
store.insert(event_addr_idx, event_addr, owned_object::make_boolean(true));
4646
}
4747

4848
} // namespace

0 commit comments

Comments
 (0)