Skip to content

[v2] Use allocators internally instead of malloc/free and stop generating zero-terminated strings#418

Merged
Anilm3 merged 18 commits into
anilm3/v2from
anilm3/v2-use-allocators-internally
Jul 4, 2025
Merged

[v2] Use allocators internally instead of malloc/free and stop generating zero-terminated strings#418
Anilm3 merged 18 commits into
anilm3/v2from
anilm3/v2-use-allocators-internally

Conversation

@Anilm3

@Anilm3 Anilm3 commented Jun 11, 2025

Copy link
Copy Markdown
Collaborator

This is the first PR in the process to introduce allocators, in a limited fashion, to the libddwaf interface. The main changes done here are the following:

  • Renamed ddwaf_run to ddwaf_context_eval.
  • Removed ddwaf_object_free from ddwaf_config, as a consequence benchmarks were failing so a temporary free_objects boolean has been added to ddwaf_context_eval until allocators can be passed to the context.
  • All calls to malloc / free have been replaced with the use of a std::pmr::new_delete_resource. With this change, all allocated memory is accounted for and no capacity is needed for output strings.
  • Output strings are no longer nul-terminated.
  • A new function called ddwaf_object_clone has been added to the interface.

The use of allocators is rudimentary as the goal is to propagate an allocator directly from the context, rather than getting a default one, however the PR is already relatively large so those changes will be done in the next PR.

Remaining work (Next PRs):

  • Update objects to use allocators more effectively.
  • Check for allocator compatibility where relevant.
  • Propagate allocator from the context.
  • Have a clear distinction between input , output and internal allocators.
  • Update interface:
    • Pass input / ouput allocators to context_init.
    • Pass allocators to memory-allocating ddwaf_object functions.

@codecov-commenter

codecov-commenter commented Jun 11, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.48148% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.88%. Comparing base (6c1b9f2) to head (29abeb0).

Files with missing lines Patch % Lines
src/interface.cpp 48.00% 10 Missing and 3 partials ⚠️
src/object.hpp 76.00% 0 Missing and 6 partials ⚠️
src/context.hpp 72.72% 2 Missing and 1 partial ⚠️
src/dynamic_string.hpp 92.10% 1 Missing and 2 partials ⚠️
src/utf8.cpp 78.57% 0 Missing and 3 partials ⚠️
src/cow_string.hpp 94.11% 0 Missing and 1 partial ⚠️
src/processor/jwt_decode.cpp 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           anilm3/v2     #418      +/-   ##
=============================================
- Coverage      85.99%   85.88%   -0.12%     
=============================================
  Files            176      176              
  Lines           9063     9054       -9     
  Branches        3835     3853      +18     
=============================================
- Hits            7794     7776      -18     
- Misses           492      498       +6     
- Partials         777      780       +3     
Flag Coverage Δ
waf_test 85.88% <81.48%> (-0.12%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pr-commenter

pr-commenter Bot commented Jun 11, 2025

Copy link
Copy Markdown

Benchmarks clang

Benchmark execution time: 2025-07-02 12:13:08

Comparing candidate commit 29abeb0 in PR branch anilm3/v2-use-allocators-internally with baseline commit 6c1b9f2 in branch anilm3/v2.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 1 metrics, 0 unstable metrics.

@pr-commenter

pr-commenter Bot commented Jun 11, 2025

Copy link
Copy Markdown

Benchmarks gcc

Benchmark execution time: 2025-07-02 12:16:46

Comparing candidate commit 29abeb0 in PR branch anilm3/v2-use-allocators-internally with baseline commit 6c1b9f2 in branch anilm3/v2.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 1 metrics, 0 unstable metrics.

@pr-commenter

pr-commenter Bot commented Jun 11, 2025

Copy link
Copy Markdown

Benchmarks clang-pgo

Benchmark execution time: 2025-07-02 12:29:54

Comparing candidate commit 29abeb0 in PR branch anilm3/v2-use-allocators-internally with baseline commit 6c1b9f2 in branch anilm3/v2.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 1 metrics, 0 unstable metrics.

@Anilm3 Anilm3 changed the title Use allocators internally instead of malloc/free Use allocators internally instead of malloc/free and stop generating zero-terminated strings Jun 11, 2025
@Anilm3
Anilm3 force-pushed the anilm3/v2-use-allocators-internally branch from 7418204 to 1d40b34 Compare June 17, 2025 10:33
@Anilm3
Anilm3 marked this pull request as ready for review June 17, 2025 15:25
@Anilm3
Anilm3 requested a review from a team as a code owner June 17, 2025 15:26
@Anilm3 Anilm3 changed the title Use allocators internally instead of malloc/free and stop generating zero-terminated strings [v2] Use allocators internally instead of malloc/free and stop generating zero-terminated strings Jun 18, 2025
@Anilm3
Anilm3 requested a review from Copilot June 19, 2025 15:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

This PR begins adding allocator support internally by replacing malloc/free, removes zero-terminated-string handling, renames the core API, and adds object cloning.

  • Renamed ddwaf_run API to ddwaf_context_eval and updated all callers and docs
  • Swapped raw malloc/free for memory::memory_resource allocations in dynamic_string and cow_string
  • Stopped generating null-terminated buffers and introduced a free_objects flag and ddwaf_object_clone

Reviewed Changes

Copilot reviewed 20 out of 77 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/exclusion/common.hpp Removed unnecessary ddwaf.h include
src/dynamic_string.hpp Migrated to memory_resource, removed null term logic
src/dynamic_string.cpp Updated to_object() to use allocators and flag deallocation
src/cow_string.hpp Swapped free for memory_resource, added capacity tracking
src/context_allocator.hpp Switched from std::pmr::memory_resource to custom type
src/context.hpp Renamed runeval, added insert(), threaded allocator
src/context.cpp Renamed implementation of run to eval
src/condition/scalar_condition.cpp Simplified transform API usage
src/builder/waf_builder.hpp Dropped free_fn parameter from constructor
src/builder/ruleset_builder.hpp/.cpp Removed free_fn storage and assignment
smoketest/smoke.c Updated test to call new ddwaf_context_eval API
libddwaf.def Exported renamed API and new clone function
include/ddwaf.h Updated interface signature, removed free_fn, added clone
fuzzer/global/src/interface.cpp Updated config init and calls to new API
examples/example.cpp Updated example to use renamed API
benchmark/run_fixture.cpp Updated benchmark calls to new API
benchmark/main.cpp Adjusted config initialization
README.md Updated usage example to renamed API
BINDING_IMPL_NOTES.md Updated documentation to renamed API

Comment thread src/dynamic_string.hpp
Comment thread README.md
Comment thread examples/example.cpp
Comment thread BINDING_IMPL_NOTES.md

@cataphract cataphract left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So is the idea to have three allocators?

  • The context allocator, for libddwaf-side allocations whose lifetime is the context's.
  • A general allocator for undifferentiated allocations.
  • An output data allocator?

I see that you removed free_fn, which was controlled deallocation for the input. I think that's fine because it was not very useful: you either retained ownership, in which case you could yourself destroy the objects once you closed the context, or you passed ownership and let libddwaf do it. So a boolean suffices.

If the idea is to have a general "user allocator" that does:

  1. allocation of input via the ddwaf functions
  2. allocation of output
  3. deallocation of input (after run for ephemeral, after context close for persistent)
  4. deallocation of output (via call to ddwaf_function)

then I have reservations. It's not clear to me that having the same allocator for input and for output is useful. I also don't see how this is any better than the status quo:

  • For input, we already have all the control we need (with free_fn = 0), provided we don't use the libddwaf functions to build the objects. Whether the libddwaf functions can be efficiently and ergonomically used a custom input allocator, that remains to be seen.
  • For output, it's not clear to me that anyone would want to have their custom allocator. In Java, where the native memory is not unified (only certain byte buffers can be shared memory between the native side and the java side), I could see some advantages, as you would be able to read the output ddwaf objects directly from java if your allocator wrote in direct byte buffers. Though probably not worth it, unless the output objects get bigger. But in any case, I think you still want to distinguish between allocated input and output (their lifetimes are not the same for instance, so implementing a winkout deallocator that handles both at the same time is complicated)

Comment thread src/condition/scalar_condition.cpp
Comment thread src/context.hpp
Comment thread src/cow_string.hpp
Comment thread src/cow_string.hpp
Comment thread src/cow_string.hpp
Comment thread src/dynamic_string.hpp
Comment thread src/context.hpp
@github-actions

github-actions Bot commented Jul 2, 2025

Copy link
Copy Markdown

Artifact Size Comparison 📦

Artifact Previous Release This PR Difference
darwin-arm64::libddwaf.a 83315344 86890096 0.04%
darwin-arm64::libddwaf.a.stripped 4352184 4439672 0.02%
darwin-arm64::libddwaf.dylib 1919536 1919872 0.00%
darwin-universal::libddwaf.a 167911160 175249960 0.04%
darwin-universal::libddwaf.a.stripped 9268592 9458528 0.02%
darwin-universal::libddwaf.dylib 4033072 4033408 0.00%
darwin-x86_64::libddwaf.a 84595768 88359816 0.04%
darwin-x86_64::libddwaf.a.stripped 4916360 5018808 0.02%
darwin-x86_64::libddwaf.dylib 2091048 2091368 0.00%
linux-aarch64::libddwaf.a 68876962 70415352 0.02%
linux-aarch64::libddwaf.a.stripped 11720766 11880116 0.01%
linux-aarch64::libddwaf.so 2429048 2428240 0.00%
linux-armv7::libddwaf.a 60213732 61491288 0.02%
linux-armv7::libddwaf.a.stripped 10612116 10760340 0.01%
linux-armv7::libddwaf.so 2103320 2087444 0.00%
linux-i386::libddwaf.a 58414994 59716812 0.02%
linux-i386::libddwaf.a.stripped 9009642 9144040 0.01%
linux-i386::libddwaf.so 2302460 2298376 0.00%
linux-x86_64::libddwaf.a 68977050 70537918 0.02%
linux-x86_64::libddwaf.a.stripped 11389686 11528722 0.01%
linux-x86_64::libddwaf.so 2602216 2597952 0.00%
windows-win32::ddwaf.dll 3292160 3334144 0.01%
windows-win32::ddwaf.lib 11684 11938 0.02%
windows-win32::ddwaf_static.lib 46934870 48049316 0.02%
windows-x64::ddwaf.dll 4021248 4037120 0.00%
windows-x64::ddwaf.lib 11464 11712 0.02%
windows-x64::ddwaf_static.lib 54410908 55505420 0.02%

Anilm3 added a commit that referenced this pull request Jul 2, 2025
@Anilm3

Anilm3 commented Jul 2, 2025

Copy link
Copy Markdown
Collaborator Author

As discussed offline, the idea is to have 3 allocators:

  • Input allocator: this will be provided by the caller when using the object API and when passing data to the context (for now we're just passing a boolean in this PR).
  • Output allocator: this will be provided by the caller on context init.
  • Context allocator: this will be the one used internally for "persistent" (i.e. non-ephemeral) allocations.

Eventually the plan is to expose allocators (memory resources), such as a monotonic and an unsynchronized pool one. The user allocator will still be an option but I don't know if it'll be of interest, I think there is more value in being able to choose from an existing one to optimise your allocations around your concurrency model, than being able to allocate memory from your runtime.

@Anilm3
Anilm3 requested a review from cataphract July 3, 2025 15:34
@Anilm3
Anilm3 merged commit 154cbfe into anilm3/v2 Jul 4, 2025
53 checks passed
@Anilm3
Anilm3 deleted the anilm3/v2-use-allocators-internally branch July 4, 2025 14:05
Anilm3 added a commit that referenced this pull request Oct 1, 2025
* Object view: read only abstraction to ddwaf_object (#341)
* [v2] Remove mingw builds (#381)
* Writable objects: owned and borrowed object and object limits removal (#378, #382)
* [v2] Refactor and improve object types (#387)
* [v2] Update unit tests to use new abstractions (#389)
* [v2] Update `raw_configuration` type to use `object_view` (#390)
* [v2] Remove remaining uses of ddwaf_object in `src` and `tests/unit` (#391)
* [v2] JWT Decoding Processor (#401)
* [v2] First iteration of object layout changes (#394)
* Split context data insertion from evaluation (#407)
* [v2] Second iteration of object layout changes (#408)
* [v2] Add new fingerprint and object view tests (#414)
* Reenable attribute collector unit test (#415)
* [v2] Container view types (#413)
* Exclude assertions from coverage (#416)
* [v2] Use allocators internally instead of malloc/free and stop generating zero-terminated strings (#418)
* Add memory resource to owned and borrowed objects (#428)
* [v2] Propagate allocators from context (#420)
* [v2] Update interface and expose allocators (#427)
* Refactor evaluation stages out of the context (#442)
* Subcontext: replace ephemerals with a new scope with user-defined lifetime derived from the context (#443)
* Validator: Add support for testing subcontexts and attributes (#451)
* [v2] Pass allocator to context and subcontext eval and add new allocators (#452)
* Update logger to avoid dependencies on ddwaf.h (#453)
* [v2] Return DDWAF_MATCH when there are events, attributes or actions (#455)
* [v2] Cleanup: remove exclusion namespace and some redundant references (#456)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants