Menu

#17 potential bug while using multithreading

open
nobody
None
5
2012-12-10
2012-12-10
Anonymous
No

I have thread pool and each thread runs tasks. There is rpc client call in task. When i run thread pool segmentation fault occurs. I joined ulxmlrpcpp source code to my project and i started to debug. I found a bug in ulxr_tcpip_connection.cpp in constructor TcpIpConnection(bool I_am_server, const CppString &dom, unsigned prt). What is the bug? The function getHostAdress(const CppString &dom) returns struct hostent* and this pointer points to the static data. The function gethostbyname(const char*) is called under thread lock and such calling is true because of non thread safety of this function. But after the function getHostAdress(const CppString &dom) has finished its work thread lock becomes unlock and static data can be overwrite by other threads. When we use the return value of the function getHostAdress(const CppString &dom) in constructor, the function memcpy() fails with error segmentation fault. I did some changes in ulxr_tcpip_connection.h and ulxr_tcpip_connection.cpp to eliminate this error.
ULXR_API_IMPL(struct in_addr*)
TcpIpConnection::getHostAdress(const CppString &dom)
{
unsigned start = 0;
if (dom.substr(start, 5) == ULXR_PCHAR("http:"))
start += 5;

if (dom.substr(start, 2) == ULXR_PCHAR("//"))
start += 2;

std::size_t slash = dom.find (ULXR_PCHAR("/"), start);
if (slash != CppString::npos)
pimpl->serverdomain = dom.substr(start, slash-1);
else
pimpl->serverdomain = dom;

#ifndef ULXR_OMIT_REENTRANT_PROTECTOR
Mutex::Locker lock(gethostbynameMutex);
#endif
struct hostent * he = gethostbyname(getLatin1(pimpl->serverdomain).c_str() );
if(he != NULL) {
struct in_addr *paddr = new in_addr();
memcpy(paddr, he->h_addr_list[0], he->h_length);
return paddr;
}
return NULL;
}

ULXR_API_IMPL(void) TcpIpConnection::setProxy(long adr, unsigned port)
{
ULXR_TRACE(ULXR_PCHAR("setProxy ") << adr << ULXR_PCHAR(" ") << port);
pimpl->hostdata.sin_addr.s_addr = htonl(adr);
pimpl->hostdata.sin_port = htons(port);
}

ULXR_API_IMPL(void) TcpIpConnection::setProxy(const CppString &dom, unsigned port)
{
ULXR_TRACE(ULXR_PCHAR("setProxy ") << dom << ULXR_PCHAR(" ") << port);
//struct hostent *hp = getHostAdress(dom);
struct in_addr *paddr = getHostAdress(dom);
if (paddr == 0)
throw ConnectionException(SystemError,
ulxr_i18n(ULXR_PCHAR("Host adress for proxy not found: ")) + dom, 500);
memcpy(&(pimpl->hostdata.sin_addr), paddr, sizeof(struct in_addr));
delete paddr;
pimpl->hostdata.sin_port = htons(port);
}
ULXR_API_IMPL0
TcpIpConnection::TcpIpConnection(bool I_am_server, const CppString &dom, unsigned prt)
Connection()
, pimpl(new PImpl)
{
ULXR_TRACE(ULXR_PCHAR("TcpIpConnection(bool, string, uint)") << dom << ULXR_PCHAR(" ") << pimpl->port);
init(prt);

pimpl->remote_name = dom;

//struct hostent *hp = getHostAdress(dom);
struct in_addr *paddr = getHostAdress(dom);
if (paddr == 0)
throw ConnectionException(SystemError,
ulxr_i18n(ULXR_PCHAR("Host adress not found: ")) + pimpl->serverdomain, 500);
memcpy(&(pimpl->hostdata.sin_addr), paddr, sizeof(struct in_addr));
delete paddr;

if (I_am_server)
{
pimpl->server_data = new ServerSocketData(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
if (getServerHandle() < 0)
throw ConnectionException(SystemError,
ulxr_i18n(ULXR_PCHAR("Could not create socket: "))
+ ULXR_GET_STRING(getErrorString(getLastError())), 500);
#ifdef ULXR_REUSE_SOCKET
int sockOpt = 1;
if (::setsockopt(getServerHandle(), SOL_SOCKET, SO_REUSEADDR,
(const char*)&sockOpt, sizeof(sockOpt)) < 0)
throw ConnectionException(SystemError,
ulxr_i18n(ULXR_PCHAR("Could not set reuse flag for socket: "))
+ ULXR_GET_STRING(getErrorString(getLastError())), 500);
#endif

int iOptVal = getTimeout() * 1000;
int iOptLen = sizeof(int);
::setsockopt(getServerHandle(), SOL_SOCKET, SO_RCVTIMEO, (char*)&iOptVal, iOptLen);
::setsockopt(getServerHandle(), SOL_SOCKET, SO_SNDTIMEO, (char*)&iOptVal, iOptLen);

if((::bind(getServerHandle(), (sockaddr*) &pimpl->hostdata, sizeof(pimpl->hostdata))) < 0)
throw ConnectionException(SystemError,
ulxr_i18n(ULXR_PCHAR("Could not bind adress: "))
+ ULXR_GET_STRING(getErrorString(getLastError())), 500);

listen(getServerHandle(), 5);
}
}

Discussion


Log in to post a comment.

MongoDB Logo MongoDB