I have implemented the pair boost::serialization::save_construct_data
and boost::serialization::load_construct_data
for a class that has no default constructor (helib::Context
). Within the implementation of boost::serialization::load_construct_data
I have to call some methods of the class being serialized. Unfortunately, when I access the pointer, I get the following error at runtime:
memory access violation at address: 0x00000000: no mapping at fault address
The implementation is the following:
namespace boost{
namespace serialization{
template<class Archive>
inline void save_construct_data(Archive & archive, const helib::Context * context, const unsigned int version){
archive << context->zMStar.getM();
archive << context->zMStar.getP();
archive << context->alMod.getR();
archive << context->smallPrimes;
archive << context->ctxtPrimes;
archive << context->specialPrimes;
archive << context->digits;
}
template<class Archive>
inline void load_construct_data(Archive & archive, helib::Context * context, const unsigned int version){
unsigned long m;
unsigned long p;
unsigned long r;
helib::IndexSet smallPrimes;
helib::IndexSet ctxtPrimes;
helib::IndexSet specialPrimes;
std::vector<helib::IndexSet> digits;
archive >> m;
archive >> p;
archive >> r;
archive >> smallPrimes;
archive >> ctxtPrimes;
archive >> specialPrimes;
archive >> digits;
::new(context)helib::Context(m, p, r);
//restore smallPrimes
for(long prime = smallPrimes.first(); prime <= smallPrimes.last(); prime = smallPrimes.next(prime)){
context->AddSmallPrime(prime);
}
//restore ctxtPrimes
for(long prime = ctxtPrimes.first(); prime <= ctxtPrimes.last(); prime = ctxtPrimes.next(prime))
context->AddCtxtPrime(prime);
//restore specialPrimes
for(long prime = specialPrimes.first(); prime <= specialPrimes.last(); prime = specialPrimes.next(prime))
context->AddSpecialPrime(prime);
//restore digits
context->digits = digits;
//last operation made in buildModchain
context->setModSizeTable();
}
template<class Archive>
void serialize(Archive & archive, helib::Context & context, const unsigned int version){}
}//namespace boost
}//namespace serialization
and here is the test calling the code:
BOOST_AUTO_TEST_CASE(serialization_context)
{
// Plaintext prime modulus
unsigned long p = 4999;
// Cyclotomic polynomial - defines phi(m)
unsigned long m = 32109;
// Hensel lifting (default = 1)
unsigned long r = 1;
// Number of bits of the modulus chain
unsigned long bits = 300;
// Number of columns of Key-Switching matix (default = 2 or 3)
unsigned long c = 2;
helib::Context * original_context_ptr = new helib::Context(m, p, r);
// Modify the context, adding primes to the modulus chain
buildModChain(*original_context_ptr, bits, c);
std::string filename = "context.serialized";
std::ofstream os(filename);
{
boost::archive::text_oarchive oarchive(os);
BOOST_TEST_MESSAGE("(m,p,r): " << original_context_ptr->zMStar.getM() << "," << original_context_ptr->zMStar.getP() << "," << original_context_ptr->alMod.getR());
oarchive << original_context_ptr;
}
helib::Context * restored_context_ptr = new helib::Context(2, 3, 1);
BOOST_TEST_MESSAGE("allocated memory for restored context, address " << restored_context_ptr);
{
std::ifstream ifs(filename);
boost::archive::text_iarchive iarchive(ifs);
iarchive >> restored_context_ptr;
BOOST_TEST_MESSAGE("(m,p,r): " << restored_context_ptr->zMStar.getM() << "," << restored_context_ptr->zMStar.getP() << "," << restored_context_ptr->alMod.getR());
}
BOOST_TEST((*restored_context_ptr == *original_context_ptr));
}
As you can see from the code, I have put some messages to try to diagnose the problem. When I run the test, I get the following printed out:
Running 2 test cases...
(m,p,r): 32109,4999,1
allocated memory for restored context, address 0x7fa7c060acb0
context instantiated, address 0x7fa7c060bff0
unknown location:0: fatal error: in "serialization_context": memory access violation at address: 0x00000000: no mapping at fault address
/Users/gianca/electronic-voting-poc/serialization.hpp:68: last checkpoint: adding small prime 0
Test is aborted
Test is aborted
Two things:
That last checkpoint information in the above message tells that the error is ocurring when executing context->AddSmallPrime(prime);
inside the load_construct_data
function. (I erased the BOOST_TEST_CHECKPOINT
from the code above for clarity).
I was surprised to see that the address allocated to receive the restored helib::Context
was not the same as the one used inside the boost::serialization::load_construct_data
when calling the placement new operator. I was expecting them to be the same. Nevertheless, I'm not an expert and I'm not sure this is related to the problem. Just wanted to give more, probably useful, information.
Thanks for any help.
I apologize for even posting the question. There was a problem with my implementation. I was confusing the indices with the actual values. The correct one is the following:
template<class Archive>
inline void save_construct_data(Archive & archive, const helib::Context * context, const unsigned int version){
archive << context->zMStar.getM();
archive << context->zMStar.getP();
archive << context->alMod.getR();
archive << context->smallPrimes;
archive << context->ctxtPrimes;
archive << context->specialPrimes;
archive << context->digits;
auto lastIndexPrime = context->allPrimes().last();
std::vector<long> primes(lastIndexPrime + 1);
for(auto index = context->smallPrimes.first(); index <= context->smallPrimes.last(); index = context->smallPrimes.next(index))
primes[index] = context->ithPrime(index);
for(auto index = context->ctxtPrimes.first(); index <= context->ctxtPrimes.last(); index = context->ctxtPrimes.next(index))
primes[index] = context->ithPrime(index);
for(auto index = context->specialPrimes.first(); index <= context->specialPrimes.last(); index = context->specialPrimes.next(index))
primes[index] = context->ithPrime(index);
archive << primes;
}
template<class Archive>
inline void load_construct_data(Archive & archive, helib::Context * context, const unsigned int version){
unsigned long m;
unsigned long p;
unsigned long r;
helib::IndexSet smallPrimes;
helib::IndexSet ctxtPrimes;
helib::IndexSet specialPrimes;
std::vector<helib::IndexSet> digits;
std::vector<long> primes;
archive >> m;
archive >> p;
archive >> r;
archive >> smallPrimes;
archive >> ctxtPrimes;
archive >> specialPrimes;
archive >> digits;
archive >> primes;
::new(context)helib::Context(m, p, r);
//restore smallPrimes
for(long index = smallPrimes.first(); index <= smallPrimes.last(); index = smallPrimes.next(index))
context->AddSmallPrime(primes[index]);
//restore ctxtPrimes
for(long index = ctxtPrimes.first(); index <= ctxtPrimes.last(); index = ctxtPrimes.next(index))
context->AddCtxtPrime(primes[index]);
//restore specialPrimes
for(long index = specialPrimes.first(); index <= specialPrimes.last(); index = specialPrimes.next(index))
context->AddSpecialPrime(primes[index]);
//restore digits
context->digits = digits;
//last operation made in buildModchain
endBuildModChain(*context);
}
User contributions licensed under CC BY-SA 3.0