The recursion depth limit added to JsonDecode() in 2.16.2 gave the C++
function a second parameter with a default value. Function pointers do not
carry default arguments, so the DSL function binding deduced an arity of 2
via boost::function_types::function_arity and required two arguments. As a
result `Json.decode("...")` failed with "Too few arguments for function",
an undocumented breaking change in a patch release.
Wrap JsonDecode() in a single-argument shim (mirroring the existing
JsonEncodeShim) so the registered function keeps its one-parameter contract
while still applying the default depth limit internally.
refs #10913
More relaxed memory_order = less safety guarantees = faster execution.
This is safe because std::shared_ptr does the same. See also:
https://en.cppreference.com/w/cpp/atomic/memory_order
"Typical use for relaxed memory ordering is incrementing counters, such as the reference counters of std::shared_ptr, since this only requires atomicity, but not ordering or synchronization (note that decrementing the std::shared_ptr counters requires acquire-release synchronization with the destructor)."
In the `boost::asio::spawn()` call for newer Boost versions with
`std::allocator_arg`, switch from `fixedsize_stack` to
`protected_fixedsize_stack` in order to allocate the stacks with guard pages.
This is done as an additional safeguard in case there was still some way to
overflow, this at least reliably crashes the process instead of going into
undefined behavior, which could even result in code execution.
Unfortunately, the old-style `spawn()` function with
`boost::coroutines::attributes` does not - at least to my knowledge - provide a
way to request a stack allocated with guard pages, hence this is only enabled
for Boost 1.87 and later with this commit.
Add validation checks to code paths reachable from the HTTP API (except full
config file deployments via /v1/config) that prevent creating deeply nested
data structures that could later cause a stack overflow.
If parsing JSON is rejected due to the depth limit introduced in the last
commit, also include the path (like root["object"]["children"]...) that exceeds
the allowed nesting depth.
Data structures parsed from JSON may be accessed recursively, so deeply nested
structures may wreak havoc by overflowing the stack. Thus, enforce a general
nesting depth limit of 24 by default (which should be more than enough for
reasonable use), with the ability to pass a different limit to JsonDecode() if
needed.
int is just not the right type to use for an index variable, so change it to
size_t, even if it's unlikely to be called on sufficently large inputs that it
would actually make a difference.
Forgot to replace one of the two uses of SHA_DIGEST_LENGTH with length in
6cd3a483a0. All users use it for SHA1 so far, so
there was no wrong usage yet.
`strand.running_in_this_thread()` relies on thread-local storage
internally, and may return false positives if the coroutine is resumed
in a different thread than it was suspended in. In debug builds, this is
not problem, since there's no TLS optimization done by the compiler, but
in release builds, the compiler might cache the address of the
thread-local variable read before the coroutine suspension, and thus
potentially reuse the same address in a different thread after
resumption, which would cause `running_in_this_thread()` to return false
or even crash (but we didn't see any crashes related to this). So,
perform the assertion only in debug builds to prevent potential wrong
usages of the `Timeout` class. For more details, see [^1][^2][^3].
[^1]: https://github.com/chriskohlhoff/asio/issues/1366
[^2]: https://bugs.llvm.org/show_bug.cgi?id=19177
[^3]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=26461
Escape all user-supplied template imports when creating an Icinga 2 DSL
configuration object. Without the escape, a `"` within the template name
would allow escaping the created object and create other Icinga 2 DSL
objects, exceeding potential user privileges.
The same bug was present in ConfigWriter::EmitComment, but as this
method is dead code, it could just be removed.
This is inefficient and involves possible bad surprises regarding
waiting durations on busy nodes. Instead, use `AsioConditionVariable#Wait()`
if there are no free slots. It's notified by others'
`CpuBoundWork#~CpuBoundWork()` once finished.
Without this change, it is easy to pass a temporary, for example a vector
returned by a function to ParallelFor(). With this commit a type-constraint
is added to disable the use of this function for rvalue sequences.
An alternative would have been to capture rvalue-references in the function,
but that would have made the function unnecessarily complex, involving tuple-capture
and `shared_ptr`s, while it is usually easy to control lifetime at the call-site.
This also enables the use of the function with "containers" that
don't have a size function but implement an overload for `std::size()`,
like c-arrays with fixed sizes.
This commit refactors the ValueGenerator class to be a template that can
work with any container type. Previously, one has to manually take care
of the used container by lazily iterating over it within a lambda. Now,
the `ValueGenerator` class itself takes care of all the iteration,
making it easier to use and less error-prone. The new base `Generator`
class is required to allow the `JsonEncoder` to handle generators in a
type-erased manner.
This adds generalized IncomingHttpMessage and OutgoingHttpMessage templates
that support different types of streams (via a std::variant) and can both
be used for either requests or responses.
The tacked on metadata from the old HttpRequest and server connection from
the old HttpServerConnection have been moved to HttpApi(Request|Response)
classes that derive from the above generalized message types.