Igor Baidiuk avatar Igor Baidiuk committed b997c49

Made API partially safe against Lua error processing

Comments (0)

Files changed (3)

 - Boost (author compiles against 1.50) with tagged layout, with default include
 and lib locations. Set BOOST_ROOT to Boost's distribution root directory.
 Compile with --layout=tagged variant=debug|release link=static threading=multi runtime-link=static
-- Lua 5.1.5 compiled from source. DLL and lib are expected to be in $LUA_ROOT/src
+- Lua 5.1.5 compiled from source. Currently expected to be built as CPP
+(no cpecial wrapping for setjmp/longjmp error processing).
+DLL and lib are expected to be in $LUA_ROOT/src
 
 Compiled as shared library, with runtime and Boost linked in statically
 

lua.channels.vcxproj

       <AdditionalDependencies>lua51.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <PostBuildEvent>
-      <Command>@xcopy $(TargetPath) $(SolutionDir)\tests\bin\$(ConfigurationName)\ /I /Q /Y
-@xcopy $(LUA_ROOT)\src\lua51.dll $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q
-@xcopy $(LUA_ROOT)\src\lua.exe $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q
-@xcopy $(LUA_ROOT)\src\luac.exe $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q
+      <Command>@xcopy $(TargetPath) $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q /Y
+@xcopy $(LUA_ROOT)\src\lua51.dll $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q /Y
+@xcopy $(LUA_ROOT)\src\lua.exe $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q /Y
+@xcopy $(LUA_ROOT)\src\luac.exe $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q /Y
 </Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
       <AdditionalDependencies>lua51.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <PostBuildEvent>
-      <Command>@xcopy $(TargetPath) $(SolutionDir)\tests\bin\$(ConfigurationName)\ /I /Q /Y
-@xcopy $(LUA_ROOT)\src\lua51.dll $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q
-@xcopy $(LUA_ROOT)\src\lua.exe $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q
-@xcopy $(LUA_ROOT)\src\luac.exe $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q
+      <Command>@xcopy $(TargetPath) $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q /Y
+@xcopy $(LUA_ROOT)\src\lua51.dll $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q /Y
+@xcopy $(LUA_ROOT)\src\lua.exe $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q /Y
+@xcopy $(LUA_ROOT)\src\luac.exe $(SolutionDir)\tests\bin\$(ConfigurationName)\ /D /I /Q /Y
 </Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
 	return chan; // fully legitimate since refers to Lua userdata object
 }
 
+static bool newNamedChannel(lua_State* L, const char* name)
+{
+	if (!*name) // disallow empty stings for channel names
+		return lua_pushstring(L, "Channel name must be a non-empty string"), false;
+	boost::mutex::scoped_lock lock(channelMapMutex);
+
+	if (channelMap.count(name))
+		return lua_pushfstring(L, "Channel '%s' already exists", name), false;
+
+	channelMap.emplace(name, newChannel(L));
+	return true;
+}
+
 int Channel__new(lua_State* L)
 {
 	const char* chanName = luaL_optstring(L, 1, 0);
 
 	if (chanName) // named channel case
 	{
-		if (!*chanName) // disallow empty stings for channel names
-			luaL_error(L, "Channel name must be a non-empty string");
-		boost::mutex::scoped_lock lock(channelMapMutex);
-
-		if (channelMap.count(chanName))
-			luaL_error(L, "Channel '%s' already exists", chanName);
-
-		channelMap.emplace(chanName, newChannel(L));
+		if (!newNamedChannel(L, chanName))
+			lua_error(L);
 	}
 	else // unnamed channel case
 	{
 	return 1;
 }
 
+static bool getChannel(lua_State* L, const char* name)
+{
+	boost::mutex::scoped_lock lock(channelMapMutex);
+	// Here, find channel by name and capture it
+	// We can guarantee that channel is valid only after capture
+	ChannelPtr chanPtr;
+	ChannelMap::iterator chan = channelMap.find(name);
+	if (chan != channelMap.end())
+		chanPtr = chan->second.lock();
+
+	if (!chanPtr)
+		return lua_pushfstring(L, "Channel '%s' does not exist", name), false;
+
+	// initialize shared pointer to channel with inplace new
+	void* chanptr_buffer = lua_newuserdata(L, sizeof(ChannelPtr));
+	ChannelPtr& newChan = *(new (chanptr_buffer) ChannelPtr(chanPtr));
+	SetChannelMetatable(L);
+
+	return true;
+}
+
 int Channel__get(lua_State* L)
 {
 	luaL_checktype(L, 1, LUA_TSTRING);
 	if (!chanName || !*chanName)
 		luaL_error(L, "Channel name must be a non-empty string");
 
-	boost::mutex::scoped_lock lock(channelMapMutex);
-	// Here, find channel by name and capture it
-	// We can guarantee that channel is valid only after capture
-	ChannelPtr chanPtr;
-	ChannelMap::iterator chan = channelMap.find(chanName);
-	if (chan != channelMap.end())
-		chanPtr = chan->second.lock();
-
-	if (!chanPtr)
-		luaL_error(L, "Channel '%s' does not exist", chanName);
-
-	// initialize shared pointer to channel with inplace new
-	void* chanptr_buffer = lua_newuserdata(L, sizeof(ChannelPtr));
-	ChannelPtr& newChan = *(new (chanptr_buffer) ChannelPtr(chanPtr));
-	SetChannelMetatable(L);
+	if (!getChannel(L, chanName))
+		lua_error(L);
 
 	return 1;
 }
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.