Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ build:asan --define signal_trace=disabled
build:asan --copt -DADDRESS_SANITIZER=1
build:asan --copt -D__SANITIZE_ADDRESS__
build:asan --test_env=ASAN_OPTIONS=handle_abort=1:allow_addr2line=true:check_initialization_order=true:strict_init_order=true
build:asan --test_env=UBSAN_OPTIONS=halt_on_error=true:print_stacktrace=1
build:asan --test_env=ASAN_SYMBOLIZER_PATH

# Clang ASAN/UBSAN
Expand Down
1 change: 0 additions & 1 deletion ci/build_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ export BAZEL_BUILD_OPTIONS="--strategy=Genrule=standalone --spawn_strategy=stand
--verbose_failures ${BAZEL_OPTIONS} --action_env=HOME --action_env=PYTHONUSERBASE \
--jobs=${NUM_CPUS} --show_task_finish --experimental_generate_json_trace_profile ${BAZEL_BUILD_EXTRA_OPTIONS}"
export BAZEL_TEST_OPTIONS="${BAZEL_BUILD_OPTIONS} --test_env=HOME --test_env=PYTHONUSERBASE \
--test_env=UBSAN_OPTIONS=print_stacktrace=1 \
--cache_test_results=no --test_output=all ${BAZEL_EXTRA_TEST_OPTIONS}"
[[ "${BAZEL_EXPUNGE}" == "1" ]] && "${BAZEL}" clean --expunge

Expand Down
40 changes: 31 additions & 9 deletions source/extensions/filters/common/lua/lua.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ namespace Lua {
*/
#define DECLARE_LUA_FUNCTION_EX(Class, Name, Index) \
static int static_##Name(lua_State* state) { \
Class* object = static_cast<Class*>(luaL_checkudata(state, Index, typeid(Class).name())); \
Class* object = ::Envoy::Extensions::Filters::Common::Lua::alignAndCast<Class>( \
luaL_checkudata(state, Index, typeid(Class).name())); \
object->checkDead(state); \
return object->Name(state); \
} \
Expand All @@ -60,6 +61,32 @@ namespace Lua {
*/
#define DECLARE_LUA_CLOSURE(Class, Name) DECLARE_LUA_FUNCTION_EX(Class, Name, lua_upvalueindex(1))

/**
* Calculate the maximum space needed to be aligned.
*/
template <typename T> constexpr size_t maximumSpaceNeededToAlign() {
// The allocated memory can be misaligned up to `alignof(T) - 1` bytes. Adding it to the size to
// allocate.
return sizeof(T) + alignof(T) - 1;
}

template <typename T> inline T* alignAndCast(void* mem) {
size_t size = maximumSpaceNeededToAlign<T>();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: const or just inline the call below.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

4th parameter of std::align takes size_t& so this cannot be a const or inlined.

return static_cast<T*>(std::align(alignof(T), sizeof(T), mem, size));
}

/**
* Create a new user data and assign its metatable.
*/
template <typename T> inline T* allocateLuaUserData(lua_State* state) {
void* mem = lua_newuserdata(state, maximumSpaceNeededToAlign<T>());
luaL_getmetatable(state, typeid(T).name());
ASSERT(lua_istable(state, -1));
lua_setmetatable(state, -2);

return alignAndCast<T>(mem);
}

/**
* This is the base class for all C++ objects that we expose out to Lua. The goal is to hide as
* much ugliness as possible. In general, to use this, do the following:
Expand Down Expand Up @@ -90,14 +117,9 @@ template <class T> class BaseLuaObject : protected Logger::Loggable<Logger::Id::
*/
template <typename... ConstructorArgs>
static std::pair<T*, lua_State*> create(lua_State* state, ConstructorArgs&&... args) {
// Create a new user data and assign its metatable.
void* mem = lua_newuserdata(state, sizeof(T));
luaL_getmetatable(state, typeid(T).name());
ASSERT(lua_istable(state, -1));
lua_setmetatable(state, -2);

// Memory is allocated via Lua and it is raw. We use placement new to run the constructor.
ENVOY_LOG(trace, "creating {} at {}", typeid(T).name(), mem);
T* mem = allocateLuaUserData<T>(state);
ENVOY_LOG(trace, "creating {} at {}", typeid(T).name(), static_cast<void*>(mem));
return {new (mem) T(std::forward<ConstructorArgs>(args)...), state};
}

Expand All @@ -119,7 +141,7 @@ template <class T> class BaseLuaObject : protected Logger::Loggable<Logger::Id::
// manually because the memory is raw and was allocated by Lua.
to_register.push_back(
{"__gc", [](lua_State* state) {
T* object = static_cast<T*>(luaL_checkudata(state, 1, typeid(T).name()));
T* object = alignAndCast<T>(luaL_checkudata(state, 1, typeid(T).name()));
ENVOY_LOG(trace, "destroying {} at {}", typeid(T).name(), static_cast<void*>(object));
object->~T();
return 0;
Expand Down
4 changes: 3 additions & 1 deletion test/extensions/filters/common/lua/lua_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ namespace Common {
namespace Lua {
namespace {

class TestObject : public BaseLuaObject<TestObject> {
// Setting large alignment requirement here so it fails the UBSAN tests if Lua allocated memory is
// not aligned by Envoy. See https://github.com/envoyproxy/envoy/issues/5551 for details.
class alignas(32) TestObject : public BaseLuaObject<TestObject> {
public:
~TestObject() { onDestroy(); }

Expand Down
1 change: 1 addition & 0 deletions tools/spelling_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ accessors
acls
addr
agg
alignof
alloc
alloca
allocator
Expand Down