Fixed SIGSEGV
This commit is contained in:
1 parent
f03882d3f4
commit
5b0019d50d
50 files changed
+1565
-821
No files matched your search
+121
-49
@@ -7,7 +7,6 @@
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -143,15 +142,99 @@ namespace {
|
||||
return key;
|
||||
}
|
||||
|
||||
std::string UnescapeDescription(const std::string "ed) {
|
||||
std::string description;
|
||||
for (std::size_t i = 0; i < quoted.size(); ++i) {
|
||||
if (quoted[i] == '\\')
|
||||
++i;
|
||||
description += quoted[i];
|
||||
// VAL_ and SG_MUL_VAL_ share a small, forward-only statement reader.
|
||||
class StatementTokens {
|
||||
public:
|
||||
StatementTokens(const std::string &text, const std::string &keyword)
|
||||
: text(text), keyword(keyword) {
|
||||
if (Word() != keyword)
|
||||
Fail();
|
||||
RequireSpace();
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
bool SkipSpaces() {
|
||||
const std::size_t begin = position;
|
||||
while (position < text.size() && (text[position] == ' ' || text[position] == '\t'))
|
||||
++position;
|
||||
return position != begin;
|
||||
}
|
||||
|
||||
void RequireSpace() {
|
||||
if (!SkipSpaces())
|
||||
Fail();
|
||||
}
|
||||
|
||||
bool Consume(char character) {
|
||||
if (position == text.size() || text[position] != character)
|
||||
return false;
|
||||
++position;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Expect(char character) {
|
||||
SkipSpaces();
|
||||
if (!Consume(character))
|
||||
Fail();
|
||||
}
|
||||
|
||||
std::string Word() {
|
||||
const std::size_t begin = position;
|
||||
while (position < text.size() && text[position] != ' ' && text[position] != '\t' &&
|
||||
text[position] != ';' && text[position] != '"')
|
||||
++position;
|
||||
if (position == begin)
|
||||
Fail();
|
||||
return text.substr(begin, position - begin);
|
||||
}
|
||||
|
||||
std::uint64_t Unsigned() {
|
||||
SkipSpaces();
|
||||
const std::size_t begin = position;
|
||||
while (position < text.size() && text[position] >= '0' && text[position] <= '9')
|
||||
++position;
|
||||
std::uint64_t value = 0U;
|
||||
const std::from_chars_result parsed =
|
||||
std::from_chars(text.data() + begin, text.data() + position, value);
|
||||
if (position == begin || parsed.ec != std::errc() || parsed.ptr != text.data() + position)
|
||||
Fail();
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string Description() {
|
||||
if (!Consume('"'))
|
||||
Fail();
|
||||
std::string description;
|
||||
while (position < text.size()) {
|
||||
char character = text[position++];
|
||||
if (character == '"')
|
||||
return description;
|
||||
if (character == '\\') {
|
||||
if (position == text.size())
|
||||
Fail();
|
||||
character = text[position++];
|
||||
if (character != '"' && character != '\\')
|
||||
Fail();
|
||||
}
|
||||
description += character;
|
||||
}
|
||||
Fail();
|
||||
}
|
||||
|
||||
void End() {
|
||||
SkipSpaces();
|
||||
if (position != text.size())
|
||||
Fail();
|
||||
}
|
||||
|
||||
private:
|
||||
[[noreturn]] void Fail() const {
|
||||
throw std::runtime_error("Malformed " + keyword + " statement.");
|
||||
}
|
||||
|
||||
const std::string &text;
|
||||
const std::string keyword;
|
||||
std::size_t position = 0U;
|
||||
};
|
||||
|
||||
FrameInfo *FindUniqueFrame(DbcDatabase &database, std::uint32_t canId, bool isExtended, const std::string &statement = "VAL_") {
|
||||
FrameInfo *frame = nullptr;
|
||||
@@ -438,33 +521,28 @@ bool DbcStatementDispatcher::Dispatch(const std::string &line,
|
||||
}
|
||||
|
||||
void DbcValueDescriptionHandler::Handle(const std::string &line, DbcParseContext &context) const {
|
||||
static const std::regex header(R"(^VAL_[ \t]+([^ \t]+)[ \t]+([^ \t;]+)[ \t]+(.*)$)");
|
||||
static const std::regex pair(R"dbc(^([^ \t]+)[ \t]+"((?:[^"\\]|\\["\\])*)")dbc");
|
||||
std::smatch fields;
|
||||
if (!std::regex_match(line, fields, header))
|
||||
throw std::runtime_error("Malformed or unsupported VAL_ statement.");
|
||||
const std::uint32_t rawId = ParseDecimal(fields[1].str(), std::numeric_limits<std::uint32_t>::max(), "VAL_ CAN ID");
|
||||
if ((rawId & 0x60000000U) != 0U)
|
||||
throw std::runtime_error("VAL_ CAN ID exceeds the 29-bit identifier range.");
|
||||
StatementTokens tokens(line, "VAL_");
|
||||
const std::uint32_t rawId = ParseCanId(tokens.Word());
|
||||
tokens.RequireSpace();
|
||||
PendingValueDescriptions pending;
|
||||
NormalizeCanId(rawId, pending.canId, pending.isExtended);
|
||||
pending.signalName = fields[2].str();
|
||||
pending.signalName = tokens.Word();
|
||||
tokens.RequireSpace();
|
||||
pending.lineNumber = context.lineNumber;
|
||||
std::string rest = fields[3].str();
|
||||
while (rest != ";") {
|
||||
if (!std::regex_search(rest, fields, pair))
|
||||
throw std::runtime_error("Malformed VAL_ value/description pair or missing semicolon.");
|
||||
const std::string number = fields[1].str();
|
||||
while (!tokens.Consume(';')) {
|
||||
const std::string number = tokens.Word();
|
||||
const RawSignalValue key = ParseValueKey(number);
|
||||
const std::string description = UnescapeDescription(fields[2].str());
|
||||
tokens.RequireSpace();
|
||||
const std::string description = tokens.Description();
|
||||
if (!pending.descriptions.emplace(key, description).second)
|
||||
throw std::runtime_error("Duplicate VAL_ value key: " + number);
|
||||
const std::size_t consumed = static_cast<std::size_t>(fields.length());
|
||||
rest.erase(0, consumed);
|
||||
if (!rest.empty() && rest[0] != ';' && rest[0] != ' ' && rest[0] != '\t')
|
||||
const bool separated = tokens.SkipSpaces();
|
||||
if (tokens.Consume(';'))
|
||||
break;
|
||||
if (!separated)
|
||||
throw std::runtime_error("Missing whitespace between VAL_ pairs.");
|
||||
rest = dbc_detail::TrimText(rest);
|
||||
}
|
||||
tokens.End();
|
||||
if (pending.descriptions.empty())
|
||||
throw std::runtime_error("VAL_ requires at least one value/description pair.");
|
||||
context.pendingValues.push_back(std::move(pending));
|
||||
@@ -487,35 +565,29 @@ void DbcParseContext::ResolveValueDescriptions(const std::string &filePath) {
|
||||
}
|
||||
|
||||
void DbcMultiplexingHandler::Handle(const std::string &line, DbcParseContext &context) const {
|
||||
static const std::regex syntax(R"(^SG_MUL_VAL_[ \t]+([0-9]+)[ \t]+([^ \t;]+)[ \t]+([^ \t;]+)[ \t]+(.+);[ \t]*$)");
|
||||
static const std::regex rangeSyntax(R"(^[ \t]*([0-9]+)[ \t]*-[ \t]*([0-9]+)[ \t]*$)");
|
||||
std::smatch fields;
|
||||
if (!std::regex_match(line, fields, syntax))
|
||||
throw std::runtime_error("Malformed SG_MUL_VAL_ statement.");
|
||||
StatementTokens tokens(line, "SG_MUL_VAL_");
|
||||
PendingMultiplexing pending;
|
||||
NormalizeCanId(ParseCanId(fields[1].str()), pending.canId, pending.isExtended);
|
||||
pending.signalName = fields[2].str();
|
||||
pending.selectorName = fields[3].str();
|
||||
NormalizeCanId(ParseCanId(tokens.Word()), pending.canId, pending.isExtended);
|
||||
tokens.RequireSpace();
|
||||
pending.signalName = tokens.Word();
|
||||
tokens.RequireSpace();
|
||||
pending.selectorName = tokens.Word();
|
||||
tokens.RequireSpace();
|
||||
pending.lineNumber = context.lineNumber;
|
||||
const std::string list = fields[4].str();
|
||||
std::size_t begin = 0U;
|
||||
for (;;) {
|
||||
const std::size_t comma = list.find(',', begin);
|
||||
const std::string item = list.substr(begin, comma == std::string::npos ? comma : comma - begin);
|
||||
if (!std::regex_match(item, fields, rangeSyntax))
|
||||
throw std::runtime_error("Malformed multiplex range.");
|
||||
MultiplexRange range;
|
||||
const std::string lower = fields[1].str();
|
||||
const std::string upper = fields[2].str();
|
||||
const std::from_chars_result low = std::from_chars(lower.data(), lower.data() + lower.size(), range.minimum);
|
||||
const std::from_chars_result high = std::from_chars(upper.data(), upper.data() + upper.size(), range.maximum);
|
||||
if (low.ec != std::errc() || high.ec != std::errc() || range.minimum > range.maximum)
|
||||
range.minimum = tokens.Unsigned();
|
||||
tokens.Expect('-');
|
||||
range.maximum = tokens.Unsigned();
|
||||
if (range.minimum > range.maximum)
|
||||
throw std::runtime_error("Invalid multiplex range.");
|
||||
pending.ranges.push_back(range);
|
||||
if (comma == std::string::npos)
|
||||
tokens.SkipSpaces();
|
||||
if (tokens.Consume(';'))
|
||||
break;
|
||||
begin = comma + 1U;
|
||||
tokens.Expect(',');
|
||||
}
|
||||
tokens.End();
|
||||
context.pendingMultiplexing.push_back(std::move(pending));
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user