Skip to content

Subcontext: replace ephemerals with a new scope with user-defined lifetime derived from the context#443

Merged
Anilm3 merged 11 commits into
anilm3/v2from
anilm3/subcontext
Sep 10, 2025
Merged

Subcontext: replace ephemerals with a new scope with user-defined lifetime derived from the context#443
Anilm3 merged 11 commits into
anilm3/v2from
anilm3/subcontext

Conversation

@Anilm3

@Anilm3 Anilm3 commented Aug 21, 2025

Copy link
Copy Markdown
Collaborator

This PR introduces the subcontext, new evaluation scope derived from the context with the goal of replacing ephemerals. The lifetime of an ephemeral is that of the call in which they are provided, in contrast, the lifetime of the data provided to the subcontext is that of the subcontext itself, in a similar manner to the data provided to the context.

A subcontext represents a short-lived scope to evaluate data which may be generated multiple times within a request, for example, a downstream request generates new data (url, method, body, query parameters, etc) which is not entirely linked to the main request and may need to be evaluated multiple times from different downstream requests, therefore a subcontext may be used to encompoass the lifetime of the downstream request.

At this stage, the subcontext implementation has been achieved by keeping track of the current evaluation scope (context or subcontext), where each subcontext is distinctly identified by a 32-bit ID, therefore cache invalidation is done through the comparison of the scope.

Also note that only one subcontext may exist at a time.

Pending:

  • Due to the size of this PR, comprehensive coverage will be completed in a separate PR.
  • The validator doesn't currently support subcontexts, this will be addressed separately.

@Anilm3
Anilm3 force-pushed the anilm3/subcontext branch from 28ea3ed to 17bb5a1 Compare August 21, 2025 16:12
@pr-commenter

pr-commenter Bot commented Sep 1, 2025

Copy link
Copy Markdown

Benchmarks clang

Benchmark execution time: 2025-09-10 11:56:45

Comparing candidate commit c8d5afd in PR branch anilm3/subcontext with baseline commit ef7f023 in branch anilm3/v2.

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

scenario:global-benchmark.random.clang

  • 🟩 execution_time [-35.068ms; -35.041ms] or [-12.823%; -12.813%]

@pr-commenter

pr-commenter Bot commented Sep 1, 2025

Copy link
Copy Markdown

Benchmarks gcc

Benchmark execution time: 2025-09-10 11:57:54

Comparing candidate commit c8d5afd in PR branch anilm3/subcontext with baseline commit ef7f023 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 Sep 1, 2025

Copy link
Copy Markdown

Benchmarks clang-pgo

Benchmark execution time: 2025-09-10 12:11:54

Comparing candidate commit c8d5afd in PR branch anilm3/subcontext with baseline commit ef7f023 in branch anilm3/v2.

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

@Anilm3
Anilm3 force-pushed the anilm3/subcontext branch 11 times, most recently from 8662c14 to 860dd72 Compare September 2, 2025 21:23
@codecov-commenter

codecov-commenter commented Sep 2, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 79.13669% with 87 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.71%. Comparing base (ef7f023) to head (c8d5afd).

Files with missing lines Patch % Lines
src/interface.cpp 45.09% 19 Missing and 9 partials ⚠️
src/processor/base.hpp 35.71% 7 Missing and 11 partials ⚠️
src/evaluation_engine.hpp 73.07% 4 Missing and 3 partials ⚠️
src/utils.hpp 77.41% 6 Missing and 1 partial ⚠️
src/exclusion/common.hpp 83.33% 0 Missing and 5 partials ⚠️
src/object_store.hpp 71.42% 0 Missing and 4 partials ⚠️
src/context.hpp 91.42% 3 Missing ⚠️
src/module.cpp 81.25% 2 Missing and 1 partial ⚠️
src/argument_retriever.hpp 0.00% 0 Missing and 2 partials ⚠️
src/condition/negated_scalar_condition.cpp 84.61% 1 Missing and 1 partial ⚠️
... and 5 more
Additional details and impacted files
@@              Coverage Diff              @@
##           anilm3/v2     #443      +/-   ##
=============================================
- Coverage      85.04%   84.71%   -0.33%     
=============================================
  Files            183      183              
  Lines           9554     9657     +103     
  Branches        4173     4211      +38     
=============================================
+ Hits            8125     8181      +56     
- Misses           572      607      +35     
- Partials         857      869      +12     
Flag Coverage Δ
waf_test 84.71% <79.13%> (-0.33%) ⬇️

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.

@github-actions

github-actions Bot commented Sep 3, 2025

Copy link
Copy Markdown

Artifact Size Comparison 📦

Artifact Previous Release This PR Difference
darwin-arm64::libddwaf.a 89560336 94148616 0.05%
darwin-arm64::libddwaf.a.stripped 4545616 4832136 0.06%
darwin-arm64::libddwaf.dylib 1960784 2027392 0.03%
darwin-universal::libddwaf.a 180532808 189922208 0.05%
darwin-universal::libddwaf.a.stripped 9690824 10294952 0.06%
darwin-universal::libddwaf.dylib 4139856 4272000 0.03%
darwin-x86_64::libddwaf.a 90972424 95773544 0.05%
darwin-x86_64::libddwaf.a.stripped 5145160 5462768 0.06%
darwin-x86_64::libddwaf.dylib 2147776 2214968 0.03%
linux-aarch64::libddwaf.a 72647358 75350702 0.03%
linux-aarch64::libddwaf.a.stripped 11778162 12191594 0.03%
linux-aarch64::libddwaf.so 2453368 2479968 0.01%
linux-armv7::libddwaf.a 64279684 66587906 0.03%
linux-armv7::libddwaf.a.stripped 10783356 11181730 0.03%
linux-armv7::libddwaf.so 2138996 2140528 0.00%
linux-i386::libddwaf.a 62427430 64714434 0.03%
linux-i386::libddwaf.a.stripped 9321362 9681938 0.03%
linux-i386::libddwaf.so 2382908 2401736 0.00%
linux-x86_64::libddwaf.a 73129494 75830276 0.03%
linux-x86_64::libddwaf.a.stripped 11599138 11990424 0.03%
linux-x86_64::libddwaf.so 2649632 2674736 0.00%
windows-arm64::ddwaf.dll 4769280 4866048 0.02%
windows-arm64::ddwaf.lib 11698 14560 0.24%
windows-arm64::ddwaf_static.lib 57431616 59684262 0.03%
windows-win32::ddwaf.dll 3356160 3444736 0.02%
windows-win32::ddwaf.lib 11922 14842 0.24%
windows-win32::ddwaf_static.lib 49113786 51342800 0.04%
windows-x64::ddwaf.dll 4088832 4156928 0.01%
windows-x64::ddwaf.lib 11698 14560 0.24%
windows-x64::ddwaf_static.lib 56948354 59200398 0.03%

@Anilm3
Anilm3 force-pushed the anilm3/subcontext branch 5 times, most recently from b8231e7 to c4d3558 Compare September 6, 2025 17:02
@Anilm3

Anilm3 commented Sep 6, 2025

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

Codex Review: Here are some suggestions.

Reply with @codex fix comments to fix any unresolved comments.

About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".

Comment thread src/exclusion/object_filter.cpp
@Anilm3 Anilm3 changed the title [WIP] Subcontext Subcontext: replace ephemerals with a new scope of user-defined lifetime derived from the context Sep 8, 2025
@Anilm3
Anilm3 marked this pull request as ready for review September 8, 2025 08:05
@Anilm3
Anilm3 requested a review from a team as a code owner September 8, 2025 08:05

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

Codex Review: Here are some suggestions.

Reply with @codex fix comments to fix any unresolved comments.

About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".

Comment thread src/processor/fingerprint.cpp
@Anilm3 Anilm3 changed the title Subcontext: replace ephemerals with a new scope of user-defined lifetime derived from the context Subcontext: replace ephemerals with a new scope with user-defined lifetime derived from the context Sep 9, 2025
Comment thread include/ddwaf.h Outdated
Comment thread include/ddwaf.h
Comment thread src/context.hpp
return engine_->eval(deadline);
}

subcontext create_subcontext() { return subcontext{engine_, mr_}; }

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.

I don't think the subcontext should use the same (monotonic) memory resource as the parent. If we have a long running application that, say, makes a bunch of http API calls using subcontexts, the memory could increase indefinitely, as it wouldn't be reclaimed upon subcontext destruction.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The memory resource set in the thread local for the subcontext must be the same one as the parent or the existing structures may suddenly use two different memory resources, with potentially unknown consequences. However, I tried to avoid allocating anything with limited lifetime within the subcontext using this resource, if you find anything I can fix it.

Comment thread include/ddwaf.h
*
* @note The WAF instance needs to be valid for the lifetime of the subcontext.
**/
ddwaf_subcontext ddwaf_subcontext_init(ddwaf_context context);

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.

It looks like, for the purposes of thread safety, contexts and their subcontexts should be treated as the same object (more or less). These requirements are not documented.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'm going to make some changes in the next PR to forbid the simultaneous use of contexts and subcontexts, I'll update the remaining docs once I've done it.

Comment thread include/ddwaf.h Outdated
Comment thread src/object_store.hpp Outdated
Comment thread src/object_store.hpp

memory::list<owned_object> input_objects_;
std::list<owned_object> ephemeral_objects_;
std::list<owned_object> subcontext_objects_;

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.

I think there are two viable/consistent options here (see my comment about the reuse of the memory resource from the parent ctx). I'm assuming that the subcontext, when running, should make no allocations affecting the parent:

  1. use a separate monotonic resource for the subcontext. The thread-local allocator would route the request to either the resource of the context or the active subrequests depending on the active scope. You would need to able to completely clear the subcontext_objects_ and subcontext_targets_ upon subcontext destruction (no preallocated arrays should remain).
  2. keep using std::list / std::unordered_set. But the thread local allocator should refuse (abort() or at least log an error) if there were allocations to the mr_ during subcontext evaluation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'll give it some thought...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

After some thought, I think it's fine for the subcontext to use the context allocator, as along as it doesn't involve subcontext specific caching (e.g. updating a fixed-size cache which could be created in either the context or subcontext).

I know there's a risk of misuse, without larger changes it may not be possible to address, but I'll keep it in mind.

Comment thread src/patch Outdated
Comment thread src/condition/negated_scalar_condition.cpp Outdated
Comment thread src/exclusion/object_filter.cpp Outdated
@Anilm3
Anilm3 force-pushed the anilm3/subcontext branch 3 times, most recently from eccc7a4 to 9eb5e4e Compare September 10, 2025 11:30
@Anilm3
Anilm3 merged commit 7c65d96 into anilm3/v2 Sep 10, 2025
54 checks passed
@Anilm3
Anilm3 deleted the anilm3/subcontext branch September 10, 2025 16:31
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.

3 participants