Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

98 Serialization sanitizer support #101

Draft
wants to merge 14 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/checkpoint_traversal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ struct CustomDispatch {
static void serializeNonIntrusive(SerializerT& s, T& t) {
serialize(s, t);
}
static void serializeNonIntrusiveEnum(SerializerT& s, T& t) {
checkpoint::serializeEnum(s, t);
}
};

// std::vector specialization for dispatcher, vector is always non-intrusive so
Expand Down
3 changes: 3 additions & 0 deletions src/checkpoint/dispatch/dispatch.impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@

#include "checkpoint/common.h"
#include "checkpoint/dispatch/dispatch.h"
#include "checkpoint/serializers/sanitizer.h"

namespace checkpoint {

Expand Down Expand Up @@ -87,6 +88,8 @@ T* Traverse::reconstruct(SerialByteType* mem) {

template <typename T, typename SizerT, typename...Args>
SerialSizeType Standard::size(T& target, Args&&... args) {
Traverse::with<T, serializers::Sanitizer>(target);

auto sizer = Traverse::with<T, SizerT>(target, std::forward<Args>(args)...);
return sizer.getSize();
}
Expand Down
6 changes: 5 additions & 1 deletion src/checkpoint/dispatch/dispatch_serializer_nonbyte.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ struct BasicDispatcher {
static void serializeNonIntrusive(SerializerT& s, T& t) {
serialize(s, t);
}

static void serializeNonIntrusiveEnum(SerializerT& s, T& t) {
serializeEnum(s, t);
}
};

template <
Expand Down Expand Up @@ -167,7 +171,7 @@ struct SerializerDispatchNonByte {
void applyElm(
SerializerT& s, T* val, isEnum<U>* = nullptr
) {
serializeEnum(s, *val);
Dispatcher::serializeNonIntrusiveEnum(s, *val);
}

/**
Expand Down
11 changes: 11 additions & 0 deletions src/checkpoint/serializers/base_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ enum struct eSerializationMode : int8_t {
Packing = 2,
Sizing = 3,
Footprinting = 4,
Sanitizing = 5,
Invalid = -1
};

Expand Down Expand Up @@ -148,6 +149,16 @@ struct Serializer {
serdes.contiguousBytes(static_cast<void*>(ptr), sizeof(T), num_elms);
}

/**
* \brief Tell the serializer that some data is skipped in the traversal.
*
* \note Used/implemented in serialization sanitizer.
*
* \return pointer to the \c char* buffer
*/
template <typename... Args>
void skip(Args&&... args) { }

/**
* \brief Get a buffer if it is associated with the serializer
*
Expand Down
69 changes: 69 additions & 0 deletions src/checkpoint/serializers/sanitizer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
//@HEADER
// *****************************************************************************
//
// sanitizer.cc
// DARMA Toolkit v. 1.0.0
// DARMA/checkpoint => Serialization Library
//
// Copyright 2019 National Technology & Engineering Solutions of Sandia, LLC
// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
// Government retains certain rights in this software.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact [email protected]
//
// *****************************************************************************
//@HEADER
*/

#if !defined INCLUDED_CHECKPOINT_SERIALIZERS_SANITIZER_CC
#define INCLUDED_CHECKPOINT_SERIALIZERS_SANITIZER_CC

#include "checkpoint/serializers/sanitizer.h"

#include <memory>

extern "C" {

checkpoint::sanitizer::Runtime* checkpoint_sanitizer_rt() {
static std::unique_ptr<checkpoint::sanitizer::Runtime> base_rt;
if (base_rt == nullptr) {
base_rt = std::make_unique<checkpoint::sanitizer::Runtime>();
}
return base_rt.get();
}

/// function that informs sanitizer if its enabled
bool checkpoint_sanitizer_enabled() {
return false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to have this be a member of the Runtime object?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These have to be C functions because they are LD preloaded by the serializer runtime.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you point me at where you picked up that constraint? That doesn't sound right to me, since LD_PRELOAD should just be importing whatever symbols it finds in a foo.so library into the list that ld.so will resolve against. If those are C function names or C++ mangled names shouldn't matter.

That said, this isn't a big deal.


} /* end extern "C" */

#endif /*INCLUDED_CHECKPOINT_SERIALIZERS_SANITIZER_CC*/
257 changes: 257 additions & 0 deletions src/checkpoint/serializers/sanitizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
/*
//@HEADER
// *****************************************************************************
//
// sanitizer.h
// DARMA Toolkit v. 1.0.0
// DARMA/checkpoint => Serialization Library
//
// Copyright 2019 National Technology & Engineering Solutions of Sandia, LLC
// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
// Government retains certain rights in this software.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact [email protected]
//
// *****************************************************************************
//@HEADER
*/

#if !defined INCLUDED_CHECKPOINT_SERIALIZERS_SANITIZER_H
#define INCLUDED_CHECKPOINT_SERIALIZERS_SANITIZER_H

#include "checkpoint/common.h"
#include "checkpoint/serializers/base_serializer.h"

#include <memory>
#include <string>

namespace checkpoint { namespace sanitizer {

/**
* \struct Runtime
*
* \brief Base class for sanitizer runtime implemented by the sanitizer
*/
struct Runtime {

virtual ~Runtime() = default;

/**
* \brief Check that a member is serialized
*
* \param[in] addr the memory address of the element
* \param[in] name the name of the element
* \param[in] tinfo the typeinfo of the element
*/
virtual void checkMember(void* addr, std::string name, std::string tinfo) {}

/**
* \brief Inform sanitizer that a member's serialization is skipped
*
* \param[in] addr the memory address of the element
* \param[in] name the name of the element
* \param[in] tinfo the typeinfo of the element
*/
virtual void skipMember(void* addr, std::string name, std::string tinfo) {}

/**
* \brief Inform sanitizer that a member is serialized
*
* \param[in] addr the memory address of the element
* \param[in] num the number of elements
* \param[in] tinfo the typeinfo of the element
*/
virtual void isSerialized(void* addr, std::size_t num, std::string tinfo) {}

/**
* \brief Push a stack frame of the current serializer context we are entering
*
* \param[in] tinfo the name of the type recursed into
*/
virtual void push(std::string tinfo) {}

/**
* \brief Pop a stack frame of the current serializer context we are leaving
*
* \param[in] tinfo the name of the type recursed out of
*/
virtual void pop(std::string tinfo) {}

};

}} /* end namespace checkpoint::sanitizer */

extern "C" {

/// pimpl to runtime that contains runtime sanitizer logic
checkpoint::sanitizer::Runtime* checkpoint_sanitizer_rt();

/// function that informs sanitizer if its enabled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo "it's"

bool checkpoint_sanitizer_enabled();

} /* end extern "C" */

namespace checkpoint { namespace serializers {

/**
* \struct SanitizerDispatch
*
* \brief Custom dispatcher at compile-time for sanitization pass injected into
* user code
*/
template <typename SerializerT, typename T>
struct SanitizerDispatch {

/**
* \brief Overload for traversing an intrusive serialize function of \c t
*
* \param[in] s the serializer
* \param[in] t the element
*/
static void serializeIntrusive(SerializerT& s, T& t);

/**
* \brief Overload for traversing a non-intrusive serialize function over an
* enum \c t
*
* \param[in] s the serializer
* \param[in] t the element
*/
static void serializeNonIntrusiveEnum(SerializerT& s, T& t);

/**
* \brief Overload for traversing a non-intrusive serialize function of \c t
*
* \param[in] s the serializer
* \param[in] t the element
*/
static void serializeNonIntrusive(SerializerT& s, T& t);
};

/**
* \struct BaseSanitizer
*
* \brief The base class for the sanitizer pass that applies the typed
* overloaded for the sanitization traversal.
*/
struct BaseSanitizer : checkpoint::Serializer {

/// The custom dispatcher that intercepts traversal at compile-time
template <typename U, typename V>
using DispatcherType = SanitizerDispatch<U, V>;

/**
* \internal \brief Construct the default sanitizer
*/
BaseSanitizer() : BaseSanitizer(checkpoint::eSerializationMode::Sanitizing) {}

/**
* \internal \brief Construct a \c BaseSanitizer in a certain serialization
* mode
*
* \param[in] in_mode the serialization mode
*/
explicit BaseSanitizer(checkpoint::eSerializationMode in_mode)
: checkpoint::Serializer(in_mode)
{ }

/**
* \internal \brief Construct from other sanitizer-like class
*/
template <typename U>
explicit BaseSanitizer(U& cl)
: checkpoint::Serializer(cl.getMode())
{ }

/**
* \brief Check that member is actually serialized
*
* \param[in] t address of the element
* \param[in] t_name pretty print of the name for diagnostic output to user
*/
template <typename T>
void check(T& t, std::string t_name);

/**
* \brief Tell the sanitizer that a certain member will be skipped. Typically,
* this is called if the data does not need to be serialized or is indirectly
* saved.
*
* \param[in] t address of the element
* \param[in] t_name pretty print of the name for diagnostic output to user
*/
template <typename T>
void skip(T& t, std::string t_name = "");

/**
* \brief Traverse contiguous data for sanitization purposes
*
* \param[in,out] s serializer
* \param[in] t pointer to the element start
* \param[in] num_elsm the number of elements starting at \c t
*/
template <typename SerializerT, typename T>
void contiguousTyped(SerializerT& s, T* t, std::size_t num_elms);

/**
* \brief Do nothing on contiguous bytes
*/
void contiguousBytes(void*, std::size_t, std::size_t) { }
};

/**
* \struct Sanitizer
*
* \brief The special type for sanitization that is specialized for traversal
* over a class. \c BaseSanitizer does all the heavy lifting---this just
* providing the compiler dispatch to the correct template overload.
*/
struct Sanitizer : BaseSanitizer { };

/**
* \struct NonSanitizingSanitizer
*
* \brief A type for sanitization that explicitly does not match the partial
* specialization to purposely invoke the regular serialization method on a
* class.
*/
struct NonSanitizingSanitizer : BaseSanitizer {
/**
* \internal \brief Construct from normal sanitizer
*/
explicit NonSanitizingSanitizer(Sanitizer& s)
: BaseSanitizer(s)
{ }
};

}} /* end namespace checkpoint::serializers */

#include "checkpoint/serializers/sanitizer.impl.h"

#endif /*INCLUDED_CHECKPOINT_SERIALIZERS_SANITIZER_H*/
Loading