提问人:tchatow 提问时间:5/6/2023 更新时间:5/11/2023 访问量:212
Flatbuffers 从流中验证SizePrefixedBuffer
Flatbuffers VerifySizePrefixedBuffer from stream
问:
这个问题是关于从 C++ 中的流中读取大小前缀为 Flatbuffers 的正确模式。
考虑一个数据流 - 即。消息所在的 TCP 由其大小前缀分隔。我最初的印象是可以使用以下代码提取这些:
while (true) {
flatbuffers::Verifier v(buf.data(), buf.size());
if (v.VerifySizePrefixedBuffer<Message>(nullptr)) {
const flatbuffers::uoffset_t off = flatbuffers::GetPrefixedSize(buf.data());
const auto msg = flatbuffers::GetSizePrefixedRoot<Message>(buf.data());
// Use message
buf.erase(buf.begin(), buf.begin() + 4 + off);
} else {
break;
}
}
但是,这被证明是不正确的 - 检查提供给验证程序的缓冲区的大小是否等于 size 前缀,而不是“至少”。VerifySizePrefixedBuffer
来自 verifier.h:
Check(ReadScalar<uoffset_t>(buf_) == size_ - sizeof(uoffset_t))
这意味着,如果缓冲区中有多条消息,我们不能使用验证程序来检查是否只有第一条消息有效。相反,必须首先读取消息大小并将其提供给验证程序:
while (buf.size() >= 4) {
const flatbuffers::uoffset_t off = flatbuffers::GetPrefixedSize(buf.data());
flatbuffers::Verifier v(buf.data(), 4 + off);
if (v.VerifySizePrefixedBuffer<Message>(nullptr)) {
const auto msg = flatbuffers::GetSizePrefixedRoot<Message>(buf.data());
// Use message
buf.erase(buf.begin(), buf.begin() + 4 + off);
} else {
break;
}
}
这似乎是在重复验证者检查前缀有效性的工作。我应该使用其他模式还是这是预期的用法?
答:
0赞
Moop
5/6/2023
#1
仅适用于“已完成”缓冲区,它无法验证部分缓冲区。它验证所有偏移量是否都指向缓冲区中的有效区域,即您不会尝试读取不在缓冲区中的数据。verifier
假设你的第一个块进来了,并且那个卡盘指向第二个块中的某个区域。验证程序将失败,说 超出了它目前拥有的缓冲区的范围。Offset
Offset
Size 前缀用于帮助分块代码正确接收缓冲区的长度并将块拼接在一起。您应该使用 to 获取预期的大小,然后使用它来将块拼接在一起,直到读取那么多数据。之后,您可以使用大小的前缀验证程序。GetPrefixedSize()
你想要这样的东西:
const auto expected_size = flatbuffers::GetPrefixedSize(buf.data());
while(buf.size() < expected_size) {
append_to_buf(buf); // however you get your next chunk
}
flatbuffers::Verifier v(buf.data(), expected_size + sizeof(expected_size));
if (!v.VerifySizePrefixedBuffer<Message>()) {
// ERROR in verification
}
const auto msg = flatbuffers::GetSizePrefixedRoot<Message>(buf.data());
// Use the msg.
// Optionally, consume the buffer to start reading the next message if you have more than one.
buf.erase(buf.begin(), buf.begin() + sizeof(expected_size) + expected_size);
评论
0赞
tchatow
5/11/2023
嗨,我不确定这是否真的是我所问的关键。 如果缓冲区的大小不完全相等,则失败。因此,您被迫将完全相同的大小传递给验证者 - 仅此而已。我更多地从设计的角度质疑这一点——为什么验证者要求你向它提供它可以自己推断的信息?一个更明智的实现,IMO,是验证器检查你的缓冲区至少足够大(甚至可能有一个out参数来返回它找到的大小)。VerifySizePrefixedBuffer
sizeof(expected_size) + expected_size
0赞
Moop
5/11/2023
好的,所以问题更多的是关于验证器中的 == vs <= 检查,而不是关于流方面,这可能只是一个错误,我不得不考虑一下它可能会破坏任何东西。但是关于你关于流媒体的问题,你仍然需要调用buff,这样你就知道你从流媒体中读取了足够多的内容,从而拥有一个完整的平坦缓冲区。这就是我在这个答案中试图展示的。一旦你有了预期的大小,创建 .GetPrefixedSize
Verifier
v(buf.data(), expected_size + sizeof(expected_size))
0赞
Moop
5/12/2023
为此提交了 github.com/google/flatbuffers/issues/7956。
评论