Improve performance of VariableOrigin instances

- The previous approach would create a std::unique_ptr and store it in
  a std::list in VariableValue (Origins)
- The new approach now stores Origins in a std::vector and constructs
  VariableOrigin elements in-place on insertion.
- Instead of having two heap-allocations for every added VariableOrigin
  instance, this performs only one.
- If multiple origins are added, std::vector's growth strategy may even
  prevent a heap-allocation. There's a cost on growing the size of the
  vector, because a copy of current elements will be necessary.
  - Introduced reserveOrigin method to notify that multiple insertions
    will be made, so that we can use std::vector's reserve and do a
    single allocation (and copy of previous elements), and then just
    initialize the new elements in-place.
This commit is contained in:
Eduardo Arias 2024-06-01 14:54:49 +00:00
parent 7c174e95fa
commit dc0a06fc70
9 changed files with 78 additions and 115 deletions

View File

@ -47,11 +47,12 @@ class AnchoredSetVariableTranslationProxy {
VariableValue *newVariableValue = new VariableValue(name, &l->at(i)->getKey(), &l->at(i)->getKey()); VariableValue *newVariableValue = new VariableValue(name, &l->at(i)->getKey(), &l->at(i)->getKey());
const VariableValue *oldVariableValue = l->at(i); const VariableValue *oldVariableValue = l->at(i);
l->at(i) = newVariableValue; l->at(i) = newVariableValue;
newVariableValue->reserveOrigin(oldVariableValue->getOrigin().size());
for (const auto &oldOrigin : oldVariableValue->getOrigin()) { for (const auto &oldOrigin : oldVariableValue->getOrigin()) {
std::unique_ptr<VariableOrigin> newOrigin(new VariableOrigin); newVariableValue->addOrigin(
newOrigin->m_length = oldVariableValue->getKey().size(); oldVariableValue->getKey().size(),
newOrigin->m_offset = oldOrigin->m_offset - oldVariableValue->getKey().size() - 1; oldOrigin.m_offset - oldVariableValue->getKey().size() - 1
newVariableValue->addOrigin(std::move(newOrigin)); );
} }
delete oldVariableValue; delete oldVariableValue;
} }

View File

@ -63,7 +63,7 @@ class AnchoredVariable {
void append(const std::string &a, size_t offset, void append(const std::string &a, size_t offset,
bool spaceSeparator = false); bool spaceSeparator = false);
void append(const std::string &a, size_t offset, void append(const std::string &a, size_t offset,
bool spaceSeparator, int size); bool spaceSeparator, size_t size);
void evaluate(std::vector<const VariableValue *> *l); void evaluate(std::vector<const VariableValue *> *l);
std::string * evaluate(); std::string * evaluate();

View File

@ -15,6 +15,7 @@
#ifdef __cplusplus #ifdef __cplusplus
#include <string> #include <string>
#include <memory>
#endif #endif
#ifndef HEADERS_MODSECURITY_VARIABLE_ORIGIN_H_ #ifndef HEADERS_MODSECURITY_VARIABLE_ORIGIN_H_
@ -36,14 +37,17 @@ class VariableOrigin {
VariableOrigin() VariableOrigin()
: m_length(0), : m_length(0),
m_offset(0) { } m_offset(0) { }
VariableOrigin(size_t length, size_t offset)
: m_length(length),
m_offset(offset) { }
std::string toText() { std::string toText() const {
std::string offset = std::to_string(m_offset); const auto offset = std::to_string(m_offset);
std::string len = std::to_string(m_length); const auto len = std::to_string(m_length);
return "v" + offset + "," + len; return "v" + offset + "," + len;
} }
int m_length; size_t m_length;
size_t m_offset; size_t m_offset;
}; };

View File

@ -18,7 +18,7 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <list> #include <vector>
#include <utility> #include <utility>
#endif #endif
@ -37,7 +37,7 @@ namespace modsecurity {
class Collection; class Collection;
class VariableValue { class VariableValue {
public: public:
using Origins = std::list<std::unique_ptr<VariableOrigin>>; using Origins = std::vector<VariableOrigin>;
explicit VariableValue(const std::string *key, explicit VariableValue(const std::string *key,
const std::string *value = nullptr) const std::string *value = nullptr)
@ -62,11 +62,9 @@ class VariableValue {
m_keyWithCollection(o->m_keyWithCollection), m_keyWithCollection(o->m_keyWithCollection),
m_value(o->m_value) m_value(o->m_value)
{ {
reserveOrigin(o->m_orign.size());
for (const auto &i : o->m_orign) { for (const auto &i : o->m_orign) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin()); addOrigin(i);
origin->m_offset = i->m_offset;
origin->m_length = i->m_length;
m_orign.push_back(std::move(origin));
} }
} }
@ -98,8 +96,14 @@ class VariableValue {
} }
void addOrigin(std::unique_ptr<VariableOrigin> origin) { void addOrigin(const VariableOrigin &origin) {
m_orign.push_back(std::move(origin)); m_orign.emplace_back(origin);
}
template<typename... Args>
void addOrigin(Args&&... args) {
m_orign.emplace_back(args...);
} }
@ -107,6 +111,12 @@ class VariableValue {
return m_orign; return m_orign;
} }
void reserveOrigin(Origins::size_type additionalSize) {
m_orign.reserve(m_orign.size() + additionalSize);
}
private: private:
Origins m_orign; Origins m_orign;
std::string m_collection; std::string m_collection;

View File

@ -52,26 +52,16 @@ void AnchoredSetVariable::unset() {
void AnchoredSetVariable::set(const std::string &key, void AnchoredSetVariable::set(const std::string &key,
const std::string &value, size_t offset, size_t len) { const std::string &value, size_t offset, size_t len) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
VariableValue *var = new VariableValue(&m_name, &key, &value); VariableValue *var = new VariableValue(&m_name, &key, &value);
var->addOrigin(len, offset);
origin->m_offset = offset;
origin->m_length = len;
var->addOrigin(std::move(origin));
emplace(key, var); emplace(key, var);
} }
void AnchoredSetVariable::set(const std::string &key, void AnchoredSetVariable::set(const std::string &key,
const std::string &value, size_t offset) { const std::string &value, size_t offset) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
VariableValue *var = new VariableValue(&m_name, &key, &value); VariableValue *var = new VariableValue(&m_name, &key, &value);
var->addOrigin(value.size(), offset);
origin->m_offset = offset;
origin->m_length = value.size();
var->addOrigin(std::move(origin));
emplace(key, var); emplace(key, var);
} }

View File

@ -54,58 +54,40 @@ void AnchoredVariable::unset() {
void AnchoredVariable::set(const std::string &a, size_t offset, void AnchoredVariable::set(const std::string &a, size_t offset,
size_t offsetLen) { size_t offsetLen) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
m_offset = offset; m_offset = offset;
m_value.assign(a.c_str(), a.size()); m_value.assign(a.c_str(), a.size());
origin->m_offset = offset; m_var->addOrigin(offsetLen, offset);
origin->m_length = offsetLen;
m_var->addOrigin(std::move(origin));
} }
void AnchoredVariable::set(const std::string &a, size_t offset) { void AnchoredVariable::set(const std::string &a, size_t offset) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
m_offset = offset; m_offset = offset;
m_value.assign(a.c_str(), a.size()); m_value.assign(a.c_str(), a.size());
origin->m_offset = offset; m_var->addOrigin(m_value.size(), offset);
origin->m_length = m_value.size();
m_var->addOrigin(std::move(origin));
} }
void AnchoredVariable::append(const std::string &a, size_t offset, void AnchoredVariable::append(const std::string &a, size_t offset,
bool spaceSeparator) { bool spaceSeparator) {
std::unique_ptr<VariableOrigin> origin(
new VariableOrigin());
if (spaceSeparator && !m_value.empty()) { if (spaceSeparator && !m_value.empty()) {
m_value.append(" " + a); m_value.append(" " + a);
} else { } else {
m_value.append(a); m_value.append(a);
} }
m_offset = offset; m_offset = offset;
origin->m_offset = offset; m_var->addOrigin(a.size(), offset);
origin->m_length = a.size();
m_var->addOrigin(std::move(origin));
} }
void AnchoredVariable::append(const std::string &a, size_t offset, void AnchoredVariable::append(const std::string &a, size_t offset,
bool spaceSeparator, int size) { bool spaceSeparator, size_t size) {
std::unique_ptr<VariableOrigin> origin(
new VariableOrigin());
if (spaceSeparator && !m_value.empty()) { if (spaceSeparator && !m_value.empty()) {
m_value.append(" " + a); m_value.append(" " + a);
} else { } else {
m_value.append(a); m_value.append(a);
} }
m_offset = offset; m_offset = offset;
origin->m_offset = offset; m_var->addOrigin({size, offset});
origin->m_length = size;
m_var->addOrigin(std::move(origin));
} }

View File

@ -317,8 +317,8 @@ bool RuleWithOperator::evaluate(Transaction *trans,
if (ret == true) { if (ret == true) {
ruleMessage->m_match = m_operator->resolveMatchMessage(trans, ruleMessage->m_match = m_operator->resolveMatchMessage(trans,
key, value); key, value);
for (auto &i : v->getOrigin()) { for (const auto &i : v->getOrigin()) {
ruleMessage->m_reference.append(i->toText()); ruleMessage->m_reference.append(i.toText());
} }
ruleMessage->m_reference.append(*valueTemp.second); ruleMessage->m_reference.append(*valueTemp.second);

View File

@ -39,50 +39,41 @@ namespace variables {
void RemoteUser::evaluate(Transaction *transaction, void RemoteUser::evaluate(Transaction *transaction,
RuleWithActions *rule, RuleWithActions *rule,
std::vector<const VariableValue *> *l) { std::vector<const VariableValue *> *l) {
size_t pos; std::vector<const VariableValue *> l2;
std::string base64;
VariableValue *var;
std::string header;
std::vector<const VariableValue *> *l2 = \ transaction->m_variableRequestHeaders.resolve("authorization", &l2);
new std::vector<const VariableValue *>();
transaction->m_variableRequestHeaders.resolve("authorization", l2);
if (l2->size() < 1) { if (!l2.empty()) {
goto clear; const auto *v = l2[0];
const auto &header = v->getValue();
std::string base64;
if (header.compare(0, 6, "Basic ") == 0) {
base64 = std::string(header, 6, header.length());
}
base64 = Utils::Base64::decode(base64);
const auto pos = base64.find(":");
if (pos != std::string::npos) {
transaction->m_variableRemoteUser.assign(std::string(base64, 0, pos));
auto var = std::make_unique<VariableValue>(&v->getKeyWithCollection(),
&transaction->m_variableRemoteUser);
var->reserveOrigin(v->getOrigin().size());
for (const auto &i : v->getOrigin()) {
var->addOrigin(i);
}
l->push_back(var.release());
}
for (auto &a : l2) {
delete a;
}
} }
header = std::string(l2->at(0)->getValue());
if (header.compare(0, 6, "Basic ") == 0) {
base64 = std::string(header, 6, header.length());
}
base64 = Utils::Base64::decode(base64);
pos = base64.find(":");
if (pos == std::string::npos) {
goto clear;
}
transaction->m_variableRemoteUser.assign(std::string(base64, 0, pos));
var = new VariableValue(&l2->at(0)->getKeyWithCollection(),
&transaction->m_variableRemoteUser);
for (const auto &i : l2->at(0)->getOrigin()) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
origin->m_offset = i->m_offset;
origin->m_length = i->m_length;
var->addOrigin(std::move(origin));
}
l->push_back(var);
clear:
for (auto &a : *l2) {
delete a;
}
l2->clear();
delete l2;
} }

View File

@ -49,15 +49,12 @@ class Rule_DictElement : public VariableDictElement { \
if (!r || r->m_ruleId == 0) { if (!r || r->m_ruleId == 0) {
return; return;
} }
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
std::string *a = new std::string(std::to_string(r->m_ruleId)); std::string *a = new std::string(std::to_string(r->m_ruleId));
VariableValue *var = new VariableValue(&m_rule, &m_rule_id, VariableValue *var = new VariableValue(&m_rule, &m_rule_id,
a a
); );
delete a; delete a;
origin->m_offset = 0; var->addOrigin();
origin->m_length = 0;
var->addOrigin(std::move(origin));
l->push_back(var); l->push_back(var);
} }
@ -75,15 +72,12 @@ class Rule_DictElement : public VariableDictElement { \
return; return;
} }
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
std::string *a = new std::string(r->m_rev); std::string *a = new std::string(r->m_rev);
VariableValue *var = new VariableValue(&m_rule, &m_rule_rev, VariableValue *var = new VariableValue(&m_rule, &m_rule_rev,
a a
); );
delete a; delete a;
origin->m_offset = 0; var->addOrigin();
origin->m_length = 0;
var->addOrigin(std::move(origin));
l->push_back(var); l->push_back(var);
} }
@ -98,15 +92,12 @@ class Rule_DictElement : public VariableDictElement { \
} }
if (r && r->hasSeverity()) { if (r && r->hasSeverity()) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
std::string *a = new std::string(std::to_string(r->severity())); std::string *a = new std::string(std::to_string(r->severity()));
VariableValue *var = new VariableValue(&m_rule, &m_rule_severity, VariableValue *var = new VariableValue(&m_rule, &m_rule_severity,
a a
); );
delete a; delete a;
origin->m_offset = 0; var->addOrigin();
origin->m_length = 0;
var->addOrigin(std::move(origin));
l->push_back(var); l->push_back(var);
} }
} }
@ -122,15 +113,12 @@ class Rule_DictElement : public VariableDictElement { \
} }
if (r && r->hasLogData()) { if (r && r->hasLogData()) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
std::string *a = new std::string(r->logData(t)); std::string *a = new std::string(r->logData(t));
VariableValue *var = new VariableValue(&m_rule, &m_rule_logdata, VariableValue *var = new VariableValue(&m_rule, &m_rule_logdata,
a a
); );
delete a; delete a;
origin->m_offset = 0; var->addOrigin();
origin->m_length = 0;
var->addOrigin(std::move(origin));
l->push_back(var); l->push_back(var);
} }
} }
@ -145,15 +133,12 @@ class Rule_DictElement : public VariableDictElement { \
} }
if (r && r->hasMsg()) { if (r && r->hasMsg()) {
std::unique_ptr<VariableOrigin> origin(new VariableOrigin());
std::string *a = new std::string(r->msg(t)); std::string *a = new std::string(r->msg(t));
VariableValue *var = new VariableValue(&m_rule, &m_rule_msg, VariableValue *var = new VariableValue(&m_rule, &m_rule_msg,
a a
); );
delete a; delete a;
origin->m_offset = 0; var->addOrigin();
origin->m_length = 0;
var->addOrigin(std::move(origin));
l->push_back(var); l->push_back(var);
} }
} }