Skip to content

Commit ab911ac

Browse files
codewbpcode
andauthored
lua: fix a bug where the lifetime of userdata will result in crash (#35063)
Commit Message: lua: fix a bug where the lifetime of userdata will result in crash Additional Description: The RouteHandleWrapper will be desotryed when the lua doing the gc. And the embedded HeaderMapRef will call the reset() when it's destructed and will refer the invalid lua_State pointer and finally result in a crash. Risk Level: low. Testing: unit. Docs Changes: n/a. Release Notes: added. Platform Specific Features: n/a. --------- Signed-off-by: wbpcode <[email protected]> Co-authored-by: wbpcode <[email protected]>
1 parent 4b0d8d9 commit ab911ac

3 files changed

Lines changed: 22 additions & 0 deletions

File tree

changelogs/current.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ bug_fixes:
237237
- area: datadog
238238
change: |
239239
Bumped the version of datadog to resolve a crashing bug in earlier versions of the library.
240+
- area: lua
241+
change: |
242+
Fixed a bug where the user data will reference a dangling pointer to the Lua state and cause a crash.
240243
241244
removed_config_or_runtime:
242245
# *Normally occurs at the end of the* :ref:`deprecation period <deprecated>`

source/extensions/router/cluster_specifiers/lua/lua_cluster_specifier.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class PerLuaCodeSetup : Logger::Loggable<Logger::Id::lua> {
2525

2626
int clusterFunctionRef() { return lua_state_.getGlobalRef(cluster_function_slot_); }
2727

28+
void runtimeGC() { lua_state_.runtimeGC(); }
29+
2830
private:
2931
uint64_t cluster_function_slot_{};
3032

@@ -58,6 +60,11 @@ class RouteHandleWrapper : public Filters::Common::Lua::BaseLuaObject<RouteHandl
5860

5961
static ExportedFunctions exportedFunctions() { return {{"headers", static_luaHeaders}}; }
6062

63+
// All embedded references should be reset when the object is marked dead. This is to ensure that
64+
// we won't do the resetting in the destructor, which may be called after the referenced
65+
// coroutine's lua_State is closed. And if that happens, the resetting will cause a crash.
66+
void onMarkDead() override { headers_wrapper_.reset(); }
67+
6168
private:
6269
/**
6370
* @return a handle to the headers.

test/extensions/router/cluster_specifiers/lua/lua_cluster_specifier_test.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,16 @@ TEST_F(LuaClusterSpecifierPluginTest, NormalLuaCode) {
8080
Http::TestRequestHeaderMapImpl headers{{":path", "/"}, {"header_key", "fake"}};
8181
auto route = plugin_->route(mock_route, headers);
8282
EXPECT_EQ("fake_service", route->routeEntry()->clusterName());
83+
// Force the runtime to gc and destroy all the userdata.
84+
config_->perLuaCodeSetup()->runtimeGC();
8385
}
8486

8587
{
8688
Http::TestRequestHeaderMapImpl headers{{":path", "/"}, {"header_key", "header_value"}};
8789
auto route = plugin_->route(mock_route, headers);
8890
EXPECT_EQ("web_service", route->routeEntry()->clusterName());
91+
// Force the runtime to gc and destroy all the userdata.
92+
config_->perLuaCodeSetup()->runtimeGC();
8993
}
9094
}
9195

@@ -98,12 +102,16 @@ TEST_F(LuaClusterSpecifierPluginTest, ErrorLuaCode) {
98102
Http::TestRequestHeaderMapImpl headers{{":path", "/"}, {"header_key", "fake"}};
99103
auto route = plugin_->route(mock_route, headers);
100104
EXPECT_EQ("default_service", route->routeEntry()->clusterName());
105+
// Force the runtime to gc and destroy all the userdata.
106+
config_->perLuaCodeSetup()->runtimeGC();
101107
}
102108

103109
{
104110
Http::TestRequestHeaderMapImpl headers{{":path", "/"}, {"header_key", "header_value"}};
105111
auto route = plugin_->route(mock_route, headers);
106112
EXPECT_EQ("default_service", route->routeEntry()->clusterName());
113+
// Force the runtime to gc and destroy all the userdata.
114+
config_->perLuaCodeSetup()->runtimeGC();
107115
}
108116
}
109117

@@ -116,12 +124,16 @@ TEST_F(LuaClusterSpecifierPluginTest, ReturnTypeNotStringLuaCode) {
116124
Http::TestRequestHeaderMapImpl headers{{":path", "/"}, {"header_key", "fake"}};
117125
auto route = plugin_->route(mock_route, headers);
118126
EXPECT_EQ("fake_service", route->routeEntry()->clusterName());
127+
// Force the runtime to gc and destroy all the userdata.
128+
config_->perLuaCodeSetup()->runtimeGC();
119129
}
120130

121131
{
122132
Http::TestRequestHeaderMapImpl headers{{":path", "/"}, {"header_key", "header_value"}};
123133
auto route = plugin_->route(mock_route, headers);
124134
EXPECT_EQ("default_service", route->routeEntry()->clusterName());
135+
// Force the runtime to gc and destroy all the userdata.
136+
config_->perLuaCodeSetup()->runtimeGC();
125137
}
126138
}
127139

0 commit comments

Comments
 (0)