mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-09-24 20:20:37 +00:00
fix: bound plain-text runs in parse_prompt_attention regex (#1919)
This commit is contained in:
parent
9a977388a8
commit
4a7da26b73
@ -821,7 +821,11 @@ std::vector<std::pair<std::string, float>> parse_prompt_attention(const std::str
|
||||
float round_bracket_multiplier = 1.1f;
|
||||
float square_bracket_multiplier = 1 / 1.1f;
|
||||
|
||||
std::regex re_attention(R"(\\\(|\\\)|\\\[|\\\]|\\\\|\\|\(|\[|:([+-]?[.\d]+)\)|\)|\]|\bBREAK\b|[^\\()\[\]:B]+|:|\bB)");
|
||||
// libstdc++ std::regex recurses per matched character, so unbounded runs
|
||||
// overflow the stack. Split runs are merged back below.
|
||||
const int max_plain_text_run = 1024;
|
||||
std::regex re_attention(R"(\\\(|\\\)|\\\[|\\\]|\\\\|\\|\(|\[|\)|\]|\bBREAK\b|[^\\()\[\]:B]{1,)" +
|
||||
std::to_string(max_plain_text_run) + R"(}|:|\bB)");
|
||||
std::regex re_break(R"(\s*\bBREAK\b\s*)");
|
||||
|
||||
auto multiply_range = [&](int start_position, float multiplier) {
|
||||
@ -830,22 +834,55 @@ std::vector<std::pair<std::string, float>> parse_prompt_attention(const std::str
|
||||
}
|
||||
};
|
||||
|
||||
// Kept out of the regex: bounding the repetition rejects valid long weights,
|
||||
// leaving it unbounded overflows the stack.
|
||||
auto lex_weight = [](const std::string& s, float& value) -> size_t {
|
||||
size_t end = 0;
|
||||
if (end < s.size() && (s[end] == '+' || s[end] == '-')) {
|
||||
++end;
|
||||
}
|
||||
while (end < s.size() && (std::isdigit((unsigned char)s[end]) || s[end] == '.')) {
|
||||
++end;
|
||||
}
|
||||
if (end >= s.size() || s[end] != ')') {
|
||||
return 0;
|
||||
}
|
||||
std::string number = s.substr(0, end);
|
||||
char* number_end = nullptr;
|
||||
float parsed = std::strtof(number.c_str(), &number_end);
|
||||
const char* expected = number.c_str() + number.size();
|
||||
// Without this ".", "+." and "1.2.3" would silently become weights.
|
||||
if (number.empty() || number_end != expected || !std::isfinite(parsed)) {
|
||||
return 0;
|
||||
}
|
||||
value = parsed;
|
||||
return end + 1;
|
||||
};
|
||||
|
||||
std::smatch m, m2;
|
||||
std::string remaining_text = text;
|
||||
|
||||
while (std::regex_search(remaining_text, m, re_attention)) {
|
||||
std::string text = m[0];
|
||||
std::string weight = m[1];
|
||||
std::string suffix = m.suffix();
|
||||
|
||||
if (text == ":") {
|
||||
float weight_value = 1.0f;
|
||||
size_t weight_length = lex_weight(suffix, weight_value);
|
||||
if (weight_length > 0) {
|
||||
if (!round_brackets.empty()) {
|
||||
multiply_range(round_brackets.back(), weight_value);
|
||||
round_brackets.pop_back();
|
||||
}
|
||||
remaining_text = suffix.substr(weight_length);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (text == "(") {
|
||||
round_brackets.push_back((int)res.size());
|
||||
} else if (text == "[") {
|
||||
square_brackets.push_back((int)res.size());
|
||||
} else if (!weight.empty()) {
|
||||
if (!round_brackets.empty()) {
|
||||
multiply_range(round_brackets.back(), std::stof(weight));
|
||||
round_brackets.pop_back();
|
||||
}
|
||||
} else if (text == ")" && !round_brackets.empty()) {
|
||||
multiply_range(round_brackets.back(), round_bracket_multiplier);
|
||||
round_brackets.pop_back();
|
||||
@ -860,7 +897,7 @@ std::vector<std::pair<std::string, float>> parse_prompt_attention(const std::str
|
||||
res.push_back({text, 1.0f});
|
||||
}
|
||||
|
||||
remaining_text = m.suffix();
|
||||
remaining_text = suffix;
|
||||
}
|
||||
|
||||
for (int pos : round_brackets) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user