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);
}
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);
}
}