为什么非犯罪序列化添加了5个字节零前缀

Why does an non-intrusive serialization add a 5 byte zero prefix?

本文关键字:5个 字节 前缀 添加 犯罪 序列化 为什么      更新时间:2023-10-16

我正在调查使用Boost :: Archive的应用程序中从非标准到标准字符串的端口。非标准字符串具有以下示例所示的非侵入性样式定义的(de-)序列化。序列化和次要化可以按预期工作,但是当移植应用程序收到旧消息时,它会出现不良的分配。这是由5个字节(全零)的插入在字符串大小之前引起的。

是什么原因导致插入这5个字节?这是某种魔术标记吗?

示例:

#include <iostream>
#include <string>
#include <sstream>
#include <boost/serialization/split_free.hpp>
#include <boost/archive/binary_oarchive.hpp>
struct own_string { // simplified custom string class
    std::string content;
};
namespace boost
{
    namespace serialization
    {
        template<class Archive>
        inline void save(
            Archive & ar,
            const own_string & t,
            const unsigned int /* file_version */)
        {
            size_t size = t.content.size();
            ar << size;
            ar.save_binary(&t.content[0], size);
        }
        template<class Archive>
        inline void load(
            Archive & ar,
            own_string & t,
            const unsigned int /* file_version */)
        {
            size_t size;
            ar >> size;
            t.content.resize(size);
            ar.load_binary(&t.content[0], size);
        }
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
        template<class Archive>
        inline void serialize(
            Archive & ar,
            own_string & t,
            const unsigned int file_version)
        {
            boost::serialization::split_free(ar, t, file_version);
        }
    } // namespace serialization
} // namespace boost
std::string string_to_hex(const std::string& input)
{
    static const char* const lut = "0123456789ABCDEF";
    size_t len = input.length();
    std::string output;
    output.reserve(2 * len);
    for (size_t i = 0; i < len; ++i)
    {
        const unsigned char c = input[i];
        output.push_back(lut[c >> 4]);
        output.push_back(lut[c & 15]);
    }
    return output;
}
void test_normal_string()
{
    std::stringstream ss;
    boost::archive::binary_oarchive ar{ss};
    std::string test = "";
    std::cout << string_to_hex(ss.str()) << std::endl;
    ar << test;
    //adds 00 00 00 00 00 00 00 00
    std::cout << string_to_hex(ss.str()) << std::endl;
}
void test_own_string()
{
    std::stringstream ss;
    boost::archive::binary_oarchive ar{ss};
    std::string test = "";
    own_string otest{test};
    std::cout << string_to_hex(ss.str()) << std::endl;
    ar << otest;
    //adds 00 00 00 00 00 00 00 00 00 00 00 00 00
    std::cout << string_to_hex(ss.str()) << std::endl;
}
int main()
{
    test_normal_string();
    test_own_string();
}

,因此,您需要对先前序列化的own_string进行挑选,就好像它是std::string一样。

来自boost(1.65.1)doc:

默认情况下,对于每个类别的类别,类信息都写入档案。此信息包括版本号,实现级别和跟踪行为。这是必要的,以便即使程序的后续版本更改了类的某些当前特征值,也可以正确地进行档案化。这些数据的空间最小。有一点运行时开销,因为必须检查每个类以查看其是否已经包含在存档中的类信息。在某些情况下,即使这也可能被认为太多了。可以通过将实现级别类特征设置为:boost :: serialization :: object_serializable来消除此额外开销。

现在,可能(*)这是标准类的默认值。实际上,添加

BOOST_CLASS_IMPLEMENTATION(own_string, boost::serialization::object_serializable)

在全局范围内使test_x_string结果以相同的字节结果。这应该解释观察到的额外字节差异。

也就是说,我没有找到有关标准类序列化特征的任何特定保证(其他人可能比我更了解)。

(*)实际上有关特质设置可移植性的部分提到:

避免此问题的另一种方法是为所有原始类型的模板my_wrapper的所有专业化分配序列化特征,以使类信息永远不会保存。这是我们为STL Collections实施序列化

已完成的工作。

因此,这可能会给您足够的信心,即在这种情况下标准收集(包括std :: string)将给出相同的字节。

我认为您要求无证件实现详细信息。不必有一个原因。这是存档格式的实现细节。

这是一个有趣的问题。

您必须告诉库您不需要类型的所有功能(对象跟踪,类型信息,版本使用)。具体而言,这说明了如何实现相同的足迹。

注意,您显然会失去禁用的功能

活在coliru

#include <iostream>
#include <string>
#include <sstream>
struct own_string { // simplified custom string class
    std::string content;
};
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/tracking.hpp>
BOOST_CLASS_IMPLEMENTATION(own_string, boost::serialization::level_type::object_serializable)
BOOST_CLASS_TRACKING(own_string, boost::serialization::track_never)
//#include <boost/serialization/wrapper.hpp>
//BOOST_CLASS_IS_WRAPPER(own_string)
#include <boost/serialization/array_wrapper.hpp>
namespace boost
{
    namespace serialization
    {
        template<class Archive>
        inline void save(
            Archive & ar,
            const own_string & t,
            const unsigned int /* file_version */)
        {
            size_t size = t.content.size();
            ar & size;
            if (size)
                ar & boost::serialization::make_array(&t.content[0], size);
        }
        template<class Archive>
        inline void load(
            Archive & ar,
            own_string & t,
            const unsigned int /* file_version */)
        {
            size_t size;
            ar & size;
            t.content.resize(size);
            if (size)
                ar & boost::serialization::make_array(&t.content[0], size);
        }
        // split non-intrusive serialization function member into separate
        // non intrusive save/load member functions
        template<class Archive>
        inline void serialize(
            Archive & ar,
            own_string & t,
            const unsigned int file_version)
        {
            boost::serialization::split_free(ar, t, file_version);
        }
    } // namespace serialization
} // namespace boost
std::string string_to_hex(const std::string& input)
{
    static const char* const lut = "0123456789ABCDEF";
    size_t len = input.length();
    std::string output;
    output.reserve(2 * len);
    for (size_t i = 0; i < len; ++i)
    {
        const unsigned char c = input[i];
        output.push_back(lut[c >> 4]);
        output.push_back(lut[c & 15]);
    }
    return output;
}
#include <boost/archive/binary_oarchive.hpp>
void test_normal_string()
{
    std::stringstream ss;
    {
        boost::archive::binary_oarchive ar{ss, boost::archive::no_header|boost::archive::no_codecvt};
        std::string test = "";
        //std::cout << string_to_hex(ss.str()) << std::endl;
        ar << test;
    }
    //adds 00 00 00 00 00 00 00 00
    std::string bytes = ss.str();
    std::cout << string_to_hex(bytes) << " (" << bytes.size() << " bytes)n";
}
void test_own_string()
{
    std::stringstream ss;
    {
        boost::archive::binary_oarchive ar{ss, boost::archive::no_header|boost::archive::no_codecvt};
        own_string otest{""};
        //std::cout << string_to_hex(ss.str()) << std::endl;
        ar << otest;
    }
    //adds 00 00 00 00 00 00 00 00 00 00 00 00 00
    std::string bytes = ss.str();
    std::cout << string_to_hex(bytes) << " (" << bytes.size() << " bytes)n";
}
int main()
{
    test_normal_string();
    test_own_string();
}

打印

0000000000000000 (8 bytes)
0000000000000000 (8 bytes)

请注意,样品删除了许多其他噪声/高架来源。