2017-12-02 2 views
1

boost :: archive를 사용하는 응용 프로그램에서 표준이 아닌 표준 문자열을 조사하고 있습니다. 비표준 문자열은 아래 예제와 같이 비 관입 스타일로 정의 된 (비) 직렬화를가집니다. 직렬화 및 직렬화 해제는 예상대로 작동하지만 이식 된 응용 프로그램이 이전 메시지를 받으면 잘못된 할당으로 인해 충돌합니다. 이것은 문자열의 크기 앞에 5 바이트 (모두 0)가 삽입되어 발생합니다.비 침입 직렬화가 5 바이트 0 프리픽스를 추가하는 이유는 무엇입니까?

이러한 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 = "ABCDEF"; 
    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(); 
} 
+0

'오래된 메시지'가 무엇인가요? 여분의 바이트에 관해서는, 나는 그것이 단지 버전 데이터라고 생각할 것이다 ... –

+0

오래된 메시지는 커스텀 문자열이 사용 된 메시지이다. – choeger

+0

@ choeger 혼란을 없애기 위해 질문 문구를 수정하십시오! +1 자체 우수 샘플 포함 – sehe

답변

2

그래서, 당신은 그것이 std::string 것처럼 own_string 이전에 직렬화를 직렬화하는 것입니다.

boost(1.65.1) doc에서

: 기본적으로

는, 직렬화 각 클래스에 대한 클래스 정보는 아카이브에 기록됩니다. 이 정보에는 버전 번호, 구현 수준 및 추적 동작이 포함됩니다. 이는 프로그램의 후속 버전이 클래스의 현재 특성 값 중 일부를 변경하는 경우에도 아카이브를 올바르게 deserialize 할 수 있도록하기 위해 필요합니다. 이 데이터의 공간 오버 헤드는 최소화됩니다. 각 클래스는 클래스 정보가 이미 아카이브에 포함되어 있는지 확인하기 위해 검사해야하기 때문에 약간의 런타임 오버 헤드가 있습니다. 어떤 경우에는 이것조차 너무 많이 고려 될 수 있습니다. 이 추가 오버 헤드는 구현 레벨 클래스 특성을 boost :: serialization :: object_serializable로 설정하여 제거 할 수 있습니다.

이제 (*) 이것은 표준 클래스의 기본값입니다. 사실, 추가 전역 범위에서

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

은 test_X_string 결과가 같은 바이트가됩니다. 이것은 관찰 된 여분의 바이트 차이를 설명해야합니다.

그렇다면 표준 클래스 직렬화 특징 (다른 사람들은 저보다 잘 알 수 있음)과 관련하여 특정 보증을 찾지 못했습니다.

이 문제를 방지하는 또 다른 방법은 클래스의 정보가 저장되지 않습니다 그래서 모든 기본 형식의 템플릿 my_wrapper의 모든 전문에 직렬화 특성을 할당하는 것입니다 :

(*)는 실제로 section about portability of traits settings는 것을 언급하고있다. 이는 STL 컬렉션

그래서 이것은 당신에게 (따라서 표준 : : 문자열을 포함) 표준 컬렉션이 경우 동일 바이트를 줄 것이다 충분한 신뢰를 줄 수 있습니다에 대한 직렬화의 우리의 구현을 위해 무엇을 수행하고있다한다.

0

문서화되지 않은 구현 세부 정보를 요청하는 것으로 생각됩니다. 이유가있을 필요는 없습니다. 이것은 아카이브 형식의 구현 세부 사항입니다.

흥미로운 질문입니다.

라이브러리에 유형 (객체 추적, 유형 정보, 버전 관리)에 대한 모든 기능을 원하지 않는다고 말해야합니다. 특히 이것은 동일한 발자국을 달성하는 방법을 보여줍니다.당신은 분명 기능을 잃게

주 당신은 Live On 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 = "ABCDEF"; 
    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) 

해제이 샘플에서는 노이즈/오버 헤드의 다른 많은 소스를 제거합니다.

관련 문제