When I just run my program:ns-server everytime, it will show me that it decrypts message fail, but when I use valgrind try to find why this error happens, it works fine. Every time when I use valgrind to debug it, it works fine.
the valgrind result is :
valgrind --leak-check=yes ./ns-server
==44887== Memcheck, a memory error detector
==44887== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==44887== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==44887== Command: ./ns-server
==44887==
first get nextlen 564
nextlen is 564
==44887== Thread 2:
==44887== Invalid read of size 1
==44887== at 0x6C49: strlen (vg_replace_strmem.c:427)
==44887== by 0x100134E6F: StringBuffer::setString(char const*) (in ./ns-server)
==44887== by 0x100159A4F: XString::setFromAnsi(char const*) (in ./ns-server)
==44887== by 0x100025396: CkRsa::DecryptStringENC(char const*, bool, CkString&) (in ./ns-server)
==44887== by 0x1000130EA: My_RSA::MyDecryption(char*, CkString&) (RSAsample.cpp:52)
==44887== by 0x1000021C1: Server::Register(char*, int, char*) (Server.cpp:164)
==44887== by 0x100001EAB: Server::Evaluate_MSG(void*) (Server.cpp:75)
==44887== by 0x409898: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
==44887== by 0x409729: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
==44887== by 0x40DFC8: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
==44887== Address 0x100b3f150 is 0 bytes after a block of size 128 alloc'd
==44887== at 0x47E1: malloc (vg_replace_malloc.c:300)
==44887== by 0x1000020F4: Server::Register(char*, int, char*) (Server.cpp:154)
==44887== by 0x100001EAB: Server::Evaluate_MSG(void*) (Server.cpp:75)
==44887== by 0x409898: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
==44887== by 0x409729: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
==44887== by 0x40DFC8: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
==44887==
This is part of the result.
In this result, it mentions:
by 0x100134E6F: StringBuffer::setString(char const*) (in ./ns-server)
==44887== by 0x100159A4F: XString::setFromAnsi(char const*) (in ./ns-server)
==44887== by 0x100025396: CkRsa::DecryptStringENC(char const*, bool, CkString&) (in ./ns-server)
But these 3 functions come from static library which I download them from http://www.chilkatsoft.com/refdoc/vcCkRsaRef.html does this mean the error actually happen in these functions? Why when I run with valgrind, my project can output the right result?When I run it without any debugging tool, it will output "decrypt fail". Valgrind will change something related to my program?
My code is as follows:
int main(int argc, const char * argv[])
{
Server myServer(SERVER_PORT);//initialize server's port num,set up socket
myServer.Start();
return 0;
}
int Server::Start()
{
send_public_key server_pub_key;
server_pub_key.heads.random=random()%10;
server_pub_key.heads.request_type=PUBLICKEY;
server_pub_key.heads.length=sizeof(send_public_key);
strcpy(server_pub_key.pubkey,server_rsa.publickey);
TCPServer.SetupListen(PortListen,Evaluate_MSG,"",0,PUBLICKEY,(char *)&server_pub_key,server_pub_key.heads.length);
return 0;
}
int TCPConnect::SetupListen(int port, void * trifunc(void *),char * refuseMSG,int refuseLen,int pub,char *msg,int length)
{
if((mi_SocketToListen=socket(AF_INET,SOCK_STREAM,0))==-1)
{
printf("create socket failed\n");
return errno;
}
struct sockaddr_in ts_SocketAddrToListen;
ts_SocketAddrToListen.sin_addr.s_addr=INADDR_ANY;
SetupSocketAddrToTarget(NULL, port, ts_SocketAddrToListen,1);
if( bind(mi_SocketToListen,(struct sockaddr *)&ts_SocketAddrToListen,sizeof(struct sockaddr)) == -1)
{
printf("establish socket failed!\n");
return errno;
}
if(listen(mi_SocketToListen,99)==-1)
{
printf("listen failed\n");
return errno;
}
while (1)
{
int ti_sockfd;
struct sockaddr_in ts_sockaddr;
socklen_t ti_size = sizeof(struct sockaddr_in);
if((ti_sockfd=accept(mi_SocketToListen,(struct sockaddr *)&ts_sockaddr,&ti_size))==-1)
{
printf("accept user failed\n");
return errno;
}
if (threadlist.size() < mi_MaxConnection)
{
if(pub==80)//if this needs me to send a public key immediately afther i accept it
{
SendMsg(ti_sockfd, msg,length);
}
mm_clients.insert(std::pair<int,struct sockaddr_in>(ti_sockfd,ts_sockaddr));
pthread_t tp_threadfd;
pthread_create(&tp_threadfd,NULL,trifunc,(void *)&ti_sockfd);
threadlist.push_back(tp_threadfd);
}
else
{
SendMsg(ti_sockfd, refuseMSG, refuseLen);
CloseConnect(ti_sockfd,NULL);
}
}
return 0;
};
void * Server::Evaluate_MSG(void *arg)
{
int socketfd = *((int *) arg);
header checkheader;
int err;
while (true)
{
err = 0;
char * msg;
char *ip;
ip=(char *)malloc(sizeof(char)*INET_ADDRSTRLEN);
memset(ip,0,sizeof(char)*INET_ADDRSTRLEN);
int nextlen=Server::TCPServer.GetNextlen(socketfd);
msg=(char *)malloc(sizeof(char)*nextlen);
memset(msg,0,sizeof(char)*nextlen);
msg=Server::TCPServer.Receive(socketfd, nextlen);
//Server::TCPServer.Receive(socketfd,msg);
struct sockaddr_in sender_ip;
memset(&sender_ip,0,sizeof(struct sockaddr_in));
sender_ip=Server::TCPServer.GetInfoBySocket(socketfd);
inet_ntop(AF_INET,&sender_ip.sin_addr,ip,INET_ADDRSTRLEN);
memset(&checkheader,0,sizeof(header));
memcpy(&checkheader,msg,sizeof(header));
switch(checkheader.request_type)
{
case REGISTER:
err = Register(msg, socketfd,ip);
break;
case LOGIN:
err=Login(msg, socketfd,ip);
break;
default:
break;
}
free(ip);
free(msg);
if (err<0)
{
cout<<"error!"<<endl;
pthread_exit(0);
}
}
}
int Server::Register(char *msg,int sockfd,char *ip)
{
request_register reg;
memset(®,0,sizeof(request_register));
memcpy(®,msg,sizeof(request_register));
if(reg.real_pass!=REAL_PASS)
{
//ignore
}
else
{
send_user_success success_err;
success_err.heads.random=random()%10;
success_err.heads.length=sizeof(success_err);
CkString user_name_outData;
char *recv_username;
recv_username=(char *)malloc(sizeof(char)*LENGTH_CIPHERTEXT);
memset(recv_username,0,sizeof(char)*LENGTH_CIPHERTEXT);
memcpy(recv_username,reg.username,sizeof(char)*LENGTH_CIPHERTEXT);
server_rsa.MyDecryption(recv_username,user_name_outData);
//it decrypt fails
cout<<"after returning:"<<user_name_outData.getString()<<endl;
-------------------Above is part of function of Register(), it is too long, I just post part of it----------------
bool My_RSA::MyDecryption(char *ciphertext,CkString &outData)
{
rsaDecryptor.put_EncodingMode("hex");
rsaDecryptor.ImportPrivateKey(privatekey);
bool userPrivateKey;
userPrivateKey=true;
const char *cipher;
cipher=ciphertext;
const char * decryptedStr ;
decryptedStr= new char[SAY_MAX];
memset((char *)decryptedStr,0,sizeof(char)*SAY_MAX);
bool test=(char *) rsaDecryptor.DecryptStringENC(ciphertext, userPrivateKey, outData);//(decryptedStr, userPrivateKey);
if (!test) {
cout<<"decrypt failed"<<endl;
return false;
}
return true;
}
The error is: it will shows "decrypt failed" when I run without any debug tool, but it will decrypt definitely with valgrind.
This is header(part):
static std::map <string,struct user_info> user_info_map;//string is user's name
static My_RSA server_rsa;
class Server
{
public:
Server(int p);
protected:
static TCPConnect TCPServer;
public:
int PortListen;
protected:
static int Register(char *msg,int sockfd,char *ip);
static int Login(char *msg,int sockfd,char *ip);
static int Lock_Un_Out(char *msg,int sockfd,int lock_unlock);
static int Check_User(int sockfd);
static int Send_User(char *msg,int sockfd);
static int Update(char *msg,int sockfd);
public:
int Start();
static void * Evaluate_MSG(void *arg);
};
The error is part is that it decrypts fail, but I don't think it is related to the function of DecryptStringENC because when I run it with valgrind or Xcode, it works fine frequently.
Now I see why an error happens. When I pass ciphertext into MyDecryption(char *ciphertext,CkString &outData)
I set the size of it is 128bytes(Because when I use strlen to see the ciphertext's size, it shows 128). But I sudden think about that maybe I should malloc ciphertext with size of 129 bytes because '/0' will be attached to a string. Then, problem solves!!!!!!!
Related
I'm new and I'm using debian 10 x64. Why is error in the line with SEND? Someone can sugest me how to fix that problem?
send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000),
I got that ERROR LOG:
==24819== Thread 3:
==24819== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==24819== at 0x51442B4: __libc_send (send.c:28)
==24819== by 0x51442B4: send (send.c:23)
==24819== by 0x1FCFC9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:117)
==24819== by 0x231624: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==24819== by 0x22ECF4: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==24819== by 0x214DE1: Player::onThingAppear(Thing const*) (player.cpp:2165)
==24819== by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==24819== by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==24819== by 0x223995: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==24819== by 0x208C43: ConnectionHandler(void*) (otserv.cpp:575)
==24819== by 0x5139F26: start_thread (pthread_create.c:479)
==24819== by 0x55F12AE: clone (clone.S:95)
==24819== Address 0x111137f1 is 289 bytes inside a block of size 16,912 alloc'd
==24819== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==24819== by 0x2086ED: ConnectionHandler(void*) (otserv.cpp:510)
==24819== by 0x5139F26: start_thread (pthread_create.c:479)
==24819== by 0x55F12AE: clone (clone.S:95)
==24819==
CODE:
bool NetworkMessage::WriteToSocket(SOCKET socket)
{
if (m_MsgSize == 0)
return true;
m_MsgBuf[0] = (unsigned char)(m_MsgSize);
m_MsgBuf[1] = (unsigned char)(m_MsgSize >> 8);
bool ret = true;
int32_t sendBytes = 0;
int32_t flags = 0;
int32_t retry = 0;
flags = MSG_DONTWAIT; // 2 ?
do
{
int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), flags);
if(b <= 0)
{
int32_t errnum;
if(errnum == EWOULDBLOCK)
{
b = 0;
OTSYS_SLEEP(10);
retry++;
if(retry == 10)
{
ret = false;
break;
}
}
else
{
ret = false;
break;
}
}
sendBytes += b;
}while(sendBytes < m_MsgSize+2);
return ret;
}
==930== Thread 3:
==930== Conditional jump or move depends on uninitialised value(s)
==930== at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930== by 0x208340: ConnectionHandler(void*) (otserv.cpp:427)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930==
==930== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==930== at 0x51442B4: __libc_send (send.c:28)
==930== by 0x51442B4: send (send.c:23)
==930== by 0x1FCFD9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:100)
==930== by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930== by 0x22ED20: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==930== by 0x214E0D: Player::onThingAppear(Thing const*) (player.cpp:2165)
==930== by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==930== by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==930== by 0x2239C1: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==930== by 0x208C6F: ConnectionHandler(void*) (otserv.cpp:575)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930== Address 0x111198d1 is 289 bytes inside a block of size 16,912 alloc'd
==930== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==930== by 0x208719: ConnectionHandler(void*) (otserv.cpp:510)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930==
==930== Conditional jump or move depends on uninitialised value(s)
==930== at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930== by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930== by 0x22ED20: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==930== by 0x214E0D: Player::onThingAppear(Thing const*) (player.cpp:2165)
==930== by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==930== by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==930== by 0x2239C1: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==930== by 0x208C6F: ConnectionHandler(void*) (otserv.cpp:575)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930== Thread 2:
==930== Conditional jump or move depends on uninitialised value(s)
==930== at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930== by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930== by 0x214089: Player::flushMsg() (player.cpp:1867)
==930== by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==930== by 0x17AAB2: Game::checkCreature(unsigned int) (game.cpp:5461)
==930== by 0x1A4B67: std::mem_fun1_t<void, Game, unsigned int>::operator()(Game*, unsigned int) const (stl_function.h:1284)
==930== by 0x1A1668: std::binder2nd<std::mem_fun1_t<void, Game, unsigned int> >::operator()(Game* const&)const (binders.h:158)
==930== by 0x19BCCD: boost::detail::function::void_function_obj_invoker1<std::binder2nd<std::mem_fun1_t<void, Game, unsigned int>>,void, Game*>::invoke(boost::detail::function::function_buffer&, Game*) (function_template.hpp:159)
==930== by 0x23810D: boost::function1<void, Game*>::operator()(Game*) const (function_template.hpp:768)
==930== by 0x237FBC: TSchedulerTask::operator()(Game*) (scheduler.h:63)
==930== by 0x166D2B: Game::eventThread(void*) (game.cpp:1045)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930==
==930== Thread 3:
==930== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==930== at 0x51442B4: __libc_send (send.c:28)
==930== by 0x51442B4: send (send.c:23)
==930== by 0x1FCFD9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:100)
==930== by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930== by 0x214089: Player::flushMsg() (player.cpp:1867)
==930== by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==930== by 0x224573: Protocol76::parsePacket(NetworkMessage&) (protocol76.cpp:405)
==930== by 0x223A3F: Protocol76::ReceiveLoop() (protocol76.cpp:86)
==930== by 0x208E70: ConnectionHandler(void*) (otserv.cpp:611)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930== Address 0x11119f5f is 1,967 bytes inside a block of size 16,912 alloc'd
==930== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==930== by 0x208719: ConnectionHandler(void*) (otserv.cpp:510)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930==
I use code like this:
bool NetworkMessage::WriteToSocket(SOCKET socket)
{
if (m_MsgSize == 0)
return true;
m_MsgBuf[0] = (unsigned char)(m_MsgSize);
m_MsgBuf[1] = (unsigned char)(m_MsgSize >> 8);
bool ret = true;
int32_t sendBytes = 0;
int32_t flags = 0;
int32_t retry = 0;
flags = MSG_DONTWAIT; // 2 ?
while (sendBytes != m_MsgSize)
{ /* != rather than < */
int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), flags);
if(b <= 0)
{
int32_t errnum;
if(errnum == EWOULDBLOCK)
{
b = 0;
OTSYS_SLEEP(10);
retry++;
if(retry == 10)
{
ret = false;
break;
}
}
else
{
ret = false;
break;
}
}
sendBytes += b;
}
return ret;
}
EDIT
the last time when i had similar error I needed to use that code and now everything is working: sigemptyset(&sigh.sa_mask); OR memset(&sigh, 0, sizeof(sigh)); here i found all msgBuf and msg Size in my project files. Do U see something intresting here? m_MsgBuf wklejto.pl/828244 m_MsgSize wklejto.pl/828245
EDIT
so I did this, in file NetworkMessage.cpp I have added under AddString/AddU32/AddU16/AddByte this:
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, stringlen);
#endif
on the top this file I have added:
#include "player.h"
#ifdef CHECKVAL
extern int checkval(unsigned char * buff, int len);
#endif
and to the end added this code to player.cpp
#ifdef CHECKVAL
int checkval(unsigned char * buff, int len)
{
int r = 0;
buff -= len;
while (len--)
r += *buff++;
return r;
}
#endif
and also I have changed char to unsigned char - bcs I got error invalid conversion from ‘unsigned char*’ to ‘char*’
to END I added to compilator this -DCHECKVAL
after that I see same error
==15290== Thread 3:
==15290== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==15290== at 0x51442B4: __libc_send (send.c:28)
==15290== by 0x51442B4: send (send.c:23)
==15290== by 0x1FCFDC: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:105)
==15290== by 0x231728: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==15290== by 0x22EDF8: Protocol76::sendThingAppear(Thing const*) (protocol76. cpp:3039)
==15290== by 0x214E99: Player::onThingAppear(Thing const*) (player.cpp:2165)
==15290== by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==15290== by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==15290== by 0x223A99: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==15290== by 0x208CFB: ConnectionHandler(void*) (otserv.cpp:575)
==15290== by 0x5139F26: start_thread (pthread_create.c:479)
==15290== by 0x55F12AE: clone (clone.S:95)
==15290== Address 0x11116331 is 289 bytes inside a block of size 16,912 alloc'd
==15290== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==15290== by 0x2087A5: ConnectionHandler(void*) (otserv.cpp:510)
==15290== by 0x5139F26: start_thread (pthread_create.c:479)
==15290== by 0x55F12AE: clone (clone.S:95)
==15290==
==15290== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==15290== at 0x51442B4: __libc_send (send.c:28)
==15290== by 0x51442B4: send (send.c:23)
==15290== by 0x1FCFDC: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:105)
==15290== by 0x231728: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==15290== by 0x214115: Player::flushMsg() (player.cpp:1867)
==15290== by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==15290== by 0x22464B: Protocol76::parsePacket(NetworkMessage&) (protocol76.cpp:405)
==15290== by 0x223B17: Protocol76::ReceiveLoop() (protocol76.cpp:86)
==15290== by 0x208EFC: ConnectionHandler(void*) (otserv.cpp:611)
==15290== by 0x5139F26: start_thread (pthread_create.c:479)
==15290== by 0x55F12AE: clone (clone.S:95)
==15290== Address 0x111169bf is 1,967 bytes inside a block of size 16,912 alloc'd
==15290== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==15290== by 0x2087A5: ConnectionHandler(void*) (otserv.cpp:510)
==15290== by 0x5139F26: start_thread (pthread_create.c:479)
==15290== by 0x55F12AE: clone (clone.S:95)
==15290==
hmm.. but this function looks intresting ConnectionHandler in the line 510 is problem?
Protocol76* protocol;
protocol = new Protocol76(s);
and:
Protocol76::Protocol76(SOCKET s)
{
OTSYS_THREAD_LOCKVARINIT(bufferLock);
player = NULL;
pendingLogout = false;
windowTextID = 0;
readItem = NULL;
this->s = s;
}
full ConnectionHandler and password is 123
enter link description here
line 510 in the file is 152
how do u think?
something like this can be enough?
int checkval(unsigned char * buff, int len)
{
buff -= len;
ofstream bufile ("buff.txt");
if (bufile.is_open())
{
while (len--)
{
bufile << "buff: " << *buff << "len: " << len;
}
bufile.close();
}
}
Supposing you initialized m_MsgSize bytes in m_MsgBuf and you want to send them in a loop block by block whose size is
std::min(m_MsgSize-sendBytes+2, 1000)
because of the "+2" depending on the initial value of m_MsgSize you can send 1 or 2 extra bytes after the first m_MsgSize bytes, these extra bytes can be just non initialized or even out of m_MsgBuf with an undefined behavior
Notice also that if you do
int32_t sendBytes = 0
while (sendBytes != m_MsgSize) { /* != rather than < */
int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), ...);
... error management
sendBytes += b;
}
because of the error introduced by the +2 you can have sendBytes greater than m_MsgSize with probable bad effects.
Just remove that "+2"
[edit after you edit you question/you answer]
Your +2 is not a problem in case m_MsgSize do not count the two additional bytes to send the length of the next bytes
valgrind signal few errors and they concern bytes inside the buffer, not the 1 or 2 last ones, for me that means you copy in m_MsgBuf few bytes non initialized. Sometimes valgrind does not signal immediately when a value was not initialized, for instance you can have :
int i; // not initialized
f(i); // nothing signaled by valgrind even i not initialized
...
void f(int i)
{
int j = i + 1; // here valgrind signal a non initialized value
I think you are in that case.
Note this may be a non error, imagine you do that :
// set some elements
char s[20];
...
strcpy(s, "aze");
...
memcpy(m_MsgBuf + 2, /* save 2 bytes for the length */
s, sizeof(s));
m_MsgSize = sizeof(s);
... may be some oher element added from m_MsgSize+2 and updating m_MsgSize
NetworkMessage::WriteToSocket(socket);
only 4 bytes was initialized in s but to have a constant size sent you send (at least) 20 bytes => 16 bytes in the buffer correspond to non initialized values => valgrind will signal them
To know if you are in a 'non error' case or if valgrind signals a real problem you have to analyze the setting of all the values you put in the buffer, but again warning valgrind can take time to signal the use of a non initialized value, that value may be was used by several intermediate location before to reach hte buffer you send
[edit from your remark giving piece of code]
The initialized value probably come from the caller of the methodes NetworkMessage::AddXXX, for instance NetworkMessage::AddByte receive in argument a non initialized byte.
The fact you have that class with dedicated method to add data in the buffer is a chance, you can modify their definitions with additional code to artificially use the bytes from the buffer to allow valgrind to detect a non initialized value. You can put the additional codes protected by #ifdef ... #endif to easily activate/deactivate it
For instance (use the type of m_MsgBuf to type the parameter buff of checkval, I used "char *" because I do not know the type of m_MsgBuf) :
#ifdef CHECKVAL
extern int checkval(char * buff, int len);
#endif
void NetworkMessage::AddByte(unsigned char value)
{
if(!canAdd(1))
return;
m_MsgBuf[m_ReadPos++] = value;
m_MsgSize++;
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, 1);
#endif
}
void NetworkMessage::AddU16(uint16_t value)
{
if(!canAdd(2))
return;
m_MsgBuf[m_ReadPos++] = (unsigned char)(value);
m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 8);
m_MsgSize += 2;
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, 2);
#endif
}
void NetworkMessage::AddU32(uint32_t value)
{
if(!canAdd(4))
return;
m_MsgBuf[m_ReadPos++] = (unsigned char)(value);
m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 8);
m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 16);
m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 24);
m_MsgSize += 4;
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, 4);
#endif
}
void NetworkMessage::AddString(const char* value)
{
uint32_t stringlen = (uint32_t) strlen(value);
if(!canAdd(stringlen+2) || stringlen > 8192)
return;
#ifdef USING_VISUAL_2005
strcpy_s((char*)m_MsgBuf + m_ReadPos, stringlen, value); //VISUAL
#else
AddU16((uint16_t)stringlen);
strcpy((char*)m_MsgBuf + m_ReadPos, value);
#endif //USING_VISUAL_2005
m_ReadPos += stringlen;
m_MsgSize += stringlen;
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, stringlen);
#endif
}
checkval have to access to each byte, for instance :
#ifdef CHECKVAL
int checkval(char * buff, int len)
{
int r = 0;
buff -= len;
while (len--)
r += *buff++;
return r;
}
#endif
and place checkval in an other file than where *NetworkMessage:Addxxx" are defined to be sure the compiler cannot detect it is useless to compute the sum of bytes from the buffer or useless to call checkval because the return value is never used and checkval has no side effect.
If to sum the byte is not enough to force valgrind to check if the bytes are initialized or not, change the definition for instance to save the bytes in a file etc
Of course compile defining CHECKVAL through compiler option, or just adding temporary
#define CHECKVAL
before the definition of checkval and before its declaration
When valgrind will detect a non initialized byte in checkval you will be able to know where the value come from looking at the stack of calls also produced by valgrind
I am testing a class that takes multiple std::unique_ptr in initialisation. Raw pointers of mock objects are allocated with new, and then passed to an injected unique_ptr.
A test without any expectations passes fine. When I add an expectation, I get memory leaks.
The sources:
Tested class:
class TemperatureController : public IController
{
public:
TemperatureController(std::unique_ptr<IOutput> output,
std::unique_ptr<ISensor> sensor,
std::unique_ptr<IRegulator> regulator,
std::unique_ptr<ISetpoint> setpoint,
std::unique_ptr<IEnabler> enabler) :
output(std::move(output)),
sensor(std::move(sensor)),
regulator(std::move(regulator)),
setpoint(std::move(setpoint)),
enabler(std::move(enabler))
{ }
virtual ~TemperatureController(){}
virtual void setup() override;
virtual void controlLoop() override;
private:
std::unique_ptr<IOutput> output;
std::unique_ptr<ISensor> sensor;
std::unique_ptr<IRegulator> regulator;
std::unique_ptr<ISetpoint> setpoint;
std::unique_ptr<IEnabler> enabler;
};
void TemperatureController::controlLoop()
{
cout << "enabler address in sut = " << std::hex << *((int*)(enabler.get())) << endl;
cout << "regulator address in sut = 4" << std::hex << *((int*)(regulator.get())) << endl;
if(enabler->isEnabled())
{
regulator->controllOutput(*output,
*setpoint,
*sensor);
}
}
Test suite:
template <typename T>
auto injectMock(T* ptr)
{
return unique_ptr<T>(ptr);
}
struct TestTemperatureController : public Test
{
MockIEnabler* enabler = new MockIEnabler();
MockIOutput* output = new MockIOutput();
MockIRegulator* regulator = new MockIRegulator();
MockISensor* sensor = new MockISensor();
MockISetpoint* setpoint = new MockISetpoint();
TemperatureController sut{injectMock(output),
injectMock(sensor),
injectMock(regulator),
injectMock(setpoint),
injectMock(enabler)};
TestTemperatureController()
{
cout << "enabler address in test = "
<< std::hex << *((int*)(enabler)) << endl
<< "regulator address in test = "
<< std::hex << *((int*)(regulator)) << endl;
}
};
TEST_F(TestTemperatureController,
WhenEnabled_ShouldAct)
{
EXPECT_CALL(*enabler, isEnabled())
.WillOnce(Return(true));
//EXPECT_CALL(*regulator, controllOutput(_,_,_)) // commented out to make simpler logs
// .Times(AtLeast(1));
sut.controlLoop();
}
I ommited some noise code (includes, namespaces etc.).
When run with valgrind, I get the following output:
==10176== Memcheck, a memory error detector
==10176== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10176== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==10176== Command: ./unit_tests
==10176==
Running main() from gmock_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from TestTemperatureController
[ RUN ] TestTemperatureController.WhenEnabled_ShouldAct
enabler address in test = 54edc8
regulator address in test = 54eb90
enabler address in sut = 54edc8
regulator address in sut = 454eb90
GMOCK WARNING:
Uninteresting mock function call - returning directly.
Function call: controllOutput(#0x5cdf1b0 8-byte object <08-ED 54-00 00-00 00-00>, #0x5cdf430 8-byte object <C0-EA 54-00 00-00 00-00>, #0x5cdf390 8-byte object <D8-EA 54-00 00-00 00-00>)
NOTE: You can safely ignore the above warning unless this call should not happen. Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call. See https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#knowing-when-to-expect for details.
[ OK ] TestTemperatureController.WhenEnabled_ShouldAct (282 ms)
[----------] 1 test from TestTemperatureController (297 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (369 ms total)
[ PASSED ] 1 test.
/home/lukasz/workspace/arduino-thermostat/ut/tests/TestTemperatureController/TestTemperatureController.cpp:52: ERROR: this mock object (used in test TestTemperatureController.WhenEnabled_ShouldAct) should be deleted but never is. Its address is #0x5cdf110.
ERROR: 1 leaked mock object found at program exit.
==10176==
==10176== HEAP SUMMARY:
==10176== in use at exit: 74,863 bytes in 37 blocks
==10176== total heap usage: 231 allocs, 194 frees, 124,341 bytes allocated
==10176==
==10176== 403 (16 direct, 387 indirect) bytes in 1 blocks are definitely lost in loss record 35 of 37
==10176== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10176== by 0x4DE485: __gnu_cxx::new_allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> >::allocate(unsigned long, void const*) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DE0F3: std::allocator_traits<std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> > >::allocate(std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> >&, unsigned long) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DDA47: std::_Vector_base<testing::internal::linked_ptr<testing::internal::ExpectationBase>, std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> > >::_M_allocate(unsigned long) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DD077: void std::vector<testing::internal::linked_ptr<testing::internal::ExpectationBase>, std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> > >::_M_emplace_back_aux<testing::internal::linked_ptr<testing::internal::ExpectationBase> const&>(testing::internal::linked_ptr<testing::internal::ExpectationBase> const&) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DC562: std::vector<testing::internal::linked_ptr<testing::internal::ExpectationBase>, std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> > >::push_back(testing::internal::linked_ptr<testing::internal::ExpectationBase> const&) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DB252: testing::internal::FunctionMockerBase<bool ()>::AddNewExpectation(char const*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::tuple<> const&) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4D9459: testing::internal::MockSpec<bool ()>::InternalExpectedAt(char const*, int, char const*, char const*) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4D4862: TestTemperatureController_WhenEnabled_ShouldAct_Test::TestBody() (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x52DF4D: void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x5281B6: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x50C9A9: testing::Test::Run() (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176==
==10176== LEAK SUMMARY:
==10176== definitely lost: 16 bytes in 1 blocks
==10176== indirectly lost: 387 bytes in 7 blocks
==10176== possibly lost: 0 bytes in 0 blocks
==10176== still reachable: 74,460 bytes in 29 blocks
==10176== suppressed: 0 bytes in 0 blocks
==10176== Reachable blocks (those to which a pointer was found) are not shown.
==10176== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==10176==
==10176== For counts of detected and suppressed errors, rerun with: -v
==10176== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
I'm not really good at googlemock implementation, but for me i seems like there are some expectations allocated, which are not released later. Or is it a false positive?
The question is: How do I deal with that? I want to inject mocks with unique_ptr's. I don't want to change the tested object's interface, of course.
I have a x86_64 multithreaded application where I try to emulate avr interrupts: when interrupt occurs application and all threads are suspended while interrupt handler execute defined actions.
I thought signals were the solution to do this so I'm trying to catch SIGUSR1 signal, but when I raise SIGUSR1 program exit with a segmentation fault error before executing apply function. (I have tried mutex in isr and signals but removed as actually they run in the main thread)
The code is within 5 files.
isr.h
#ifndef __ISR_H__
#define __ISR_H__
typedef void (*routine_t)(void);
class InterruptServiceRoutine
{
routine_t routine;
bool locked = true;
public:
InterruptServiceRoutine(routine_t isr);
void apply();
void unlock(){locked = false;};
};
typedef InterruptServiceRoutine ISR_t;
#endif // __ISR_H__
isr.cpp:
#include <ISR.h>
InterruptServiceRoutine::InterruptServiceRoutine(routine_t isr): routine(isr){}
void InterruptServiceRoutine::apply()
{
if (!locked) routine();
}
Signals.h:
#ifndef __SIGNALS_H__
#define __SIGNALS_H__
#include <vector>
#include <ISR.h>
#include <signal.h>
class Logger;
class Signals
{
private:
Logger& log;
std::vector<ISR_t*> isr_table;
public:
Signals(Logger&);
~Signals();
unsigned int count(void);
void clear(void);
void connect(ISR_t &isr);
void apply(int);
};
#endif // __SIGNALS_H__
Signals.cpp:
#include <signal.h>
#include <pthread.h>
#include <functional>
#include <ISR.h>
#include <Signals.h>
#include <Logger.h>
using namespace std;
void Signals::apply(int)
{
sigset_t sigs_to_block;
sigfillset(&sigs_to_block);
pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
unsigned int num_interrupts = count();
for (unsigned int i=0; i < num_interrupts; ++i)
{
isr_table[i]->apply();
}
pthread_sigmask(SIG_SETMASK, NULL, NULL);
}
Signals::Signals(Logger& _log): log(_log)
{
clear();
auto _apply = bind1st(mem_fun(&Signals::apply), this);
struct sigaction new_action;
new_action.sa_handler = (__sighandler_t) &_apply;
new_action.sa_flags = 0;
sigfillset(&new_action.sa_mask);
sigaction(SIGUSR1, &new_action, NULL);
pthread_sigmask(SIG_SETMASK, NULL, NULL);
}
Signals::~Signals() {
struct sigaction new_action;
new_action.sa_handler = SIG_DFL;
new_action.sa_flags = 0;
sigemptyset(&new_action.sa_mask);
sigaddset(&new_action.sa_mask, SIGUSR1);
sigaction(SIGUSR1, &new_action, NULL);
clear();
}
void Signals::clear(void)
{
isr_table.clear();
isr_table.reserve(20);
}
unsigned int Signals::count(void)
{
return isr_table.size();
}
void Signals::connect(ISR_t &isr)
{
isr_table.push_back(&isr);
}
SignalsTest.test:
#include <signal.h>
#include <pthread.h>
#include <cxxtest/TestSuite.h>
#include <ISR.h>
#include <Signals.h>
#include <Logger.h>
volatile sig_atomic_t isr_called_count;
void isr(void)
{
++isr_called_count;
}
class SignalsTestSuite: public CxxTest::TestSuite
{
Logger log;
Signals handler;
public:
SignalsTestSuite(void): handler(log){}
void setUp()
{
handler.clear();
isr_called_count = 0;
}
/* ... truncated for more visibility ... */
void testWhenRaiseSIGUSRItCallsAvailableRoutine(void)
{
ISR_t routine(&isr);
routine.unlock();
handler.connect(routine);
handler.connect(routine);
raise(SIGUSR1);
TS_ASSERT_EQUALS(isr_called_count, 2);
}
};
Debug informations:
GNU gdb (Gentoo 7.7.1 p1) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://bugs.gentoo.org/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./out/signals...done.
(gdb) r
Starting program: test/out/signals
warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Running 3 tests..
Program received signal SIGUSR1, User defined signal 1.
0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
36 return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid),
(gdb) bt
#0 0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
#1 0x0000000000403f38 in SignalsTestSuite::testWhenRaiseSIGUSRItCallsAvailableRoutine (this=this#entry=0x631cc0 <suite_SignalsTestSuite>)
at test/SignalsTest.test:62
#2 0x0000000000403f92 in TestDescription_suite_SignalsTestSuite_testWhenRaiseSIGUSRItCallsAvailableRoutine::runTest (this=<optimized out>) at out/signals.cpp:38
#3 0x000000000040424e in CxxTest::RealTestDescription::run (this=<optimized out>) at /opt/cxxtest/cxxtest/RealDescriptions.cpp:109
#4 0x0000000000409afb in CxxTest::TestRunner::runTest (this=this#entry=0x7fffffffd29f, td=...) at /opt/cxxtest/cxxtest/TestRunner.h:85
#5 0x0000000000409c76 in CxxTest::TestRunner::runSuite (this=this#entry=0x7fffffffd29f, sd=...) at /opt/cxxtest/cxxtest/TestRunner.h:72
#6 0x0000000000409e15 in CxxTest::TestRunner::runWorld (this=this#entry=0x7fffffffd29f) at /opt/cxxtest/cxxtest/TestRunner.h:57
#7 0x0000000000409f52 in CxxTest::TestRunner::runAllTests (listener=...) at /opt/cxxtest/cxxtest/TestRunner.h:34
#8 0x0000000000409f93 in CxxTest::ErrorFormatter::run (this=this#entry=0x7fffffffd320) at /opt/cxxtest/cxxtest/ErrorFormatter.h:59
#9 0x000000000040aa89 in CxxTest::Main<CxxTest::ErrorPrinter> (tmp=..., argc=argc#entry=1, argv=argv#entry=0x7fffffffd448) at /opt/cxxtest/cxxtest/TestMain.h:109
#10 0x0000000000407f62 in main (argc=1, argv=0x7fffffffd448) at out/runner.cpp:18
(gdb) l
31 that. */
32 pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
33 if (__glibc_unlikely (pid < 0))
34 pid = -pid;
35
36 return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid),
37 sig);
38 }
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffd210 in ?? ()
(gdb) bt
#0 0x00007fffffffd210 in ?? ()
#1 <signal handler called>
#2 0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
#3 0x0000000000403f38 in SignalsTestSuite::testWhenRaiseSIGUSRItCallsAvailableRoutine (this=this#entry=0x631cc0 <suite_SignalsTestSuite>)
at test/SignalsTest.test:62
#4 0x0000000000403f92 in TestDescription_suite_SignalsTestSuite_testWhenRaiseSIGUSRItCallsAvailableRoutine::runTest (this=<optimized out>) at out/signals.cpp:38
#5 0x000000000040424e in CxxTest::RealTestDescription::run (this=<optimized out>) at /opt/cxxtest/cxxtest/RealDescriptions.cpp:109
#6 0x0000000000409afb in CxxTest::TestRunner::runTest (this=this#entry=0x7fffffffd29f, td=...) at /opt/cxxtest/cxxtest/TestRunner.h:85
#7 0x0000000000409c76 in CxxTest::TestRunner::runSuite (this=this#entry=0x7fffffffd29f, sd=...) at /opt/cxxtest/cxxtest/TestRunner.h:72
#8 0x0000000000409e15 in CxxTest::TestRunner::runWorld (this=this#entry=0x7fffffffd29f) at /opt/cxxtest/cxxtest/TestRunner.h:57
#9 0x0000000000409f52 in CxxTest::TestRunner::runAllTests (listener=...) at /opt/cxxtest/cxxtest/TestRunner.h:34
#10 0x0000000000409f93 in CxxTest::ErrorFormatter::run (this=this#entry=0x7fffffffd320) at /opt/cxxtest/cxxtest/ErrorFormatter.h:59
#11 0x000000000040aa89 in CxxTest::Main<CxxTest::ErrorPrinter> (tmp=..., argc=argc#entry=1, argv=argv#entry=0x7fffffffd448) at /opt/cxxtest/cxxtest/TestMain.h:109
#12 0x0000000000407f62 in main (argc=1, argv=0x7fffffffd448) at out/runner.cpp:18
(gdb) l
Line number 39 out of range; ../sysdeps/unix/sysv/linux/pt-raise.c has 38 lines.
(gdb) s
Cannot find bounds of current function
(gdb) c
Continuing.
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
Memory informations:
$ valgrind --leak-check=full --show-leak-kinds=all ./out/signals
==31715== Memcheck, a memory error detector
==31715== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==31715== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==31715== Command: ./out/signals
==31715==
Running 3 tests..==31715==
==31715== Process terminating with default action of signal 11 (SIGSEGV)
==31715== Bad permissions for mapped region at address 0xFFEFFF1F0
==31715== at 0xFFEFFF1F0: ???
==31715== by 0x409F92FF: ???
==31715== by 0xFFF: ???
==31715== by 0x40AA88FF: ???
==31715==
==31715== HEAP SUMMARY:
==31715== in use at exit: 176 bytes in 2 blocks
==31715== total heap usage: 2 allocs, 0 frees, 176 bytes allocated
==31715==
==31715== 16 bytes in 1 blocks are still reachable in loss record 1 of 2
==31715== at 0x4C294C0: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==31715== by 0x408AB1: CxxTest::ErrorPrinter::ErrorPrinter(std::ostream&, char const*, char const*) (ErrorPrinter.h:43)
==31715== by 0x407F4C: main (runner.cpp:17)
==31715==
==31715== 160 bytes in 1 blocks are still reachable in loss record 2 of 2
==31715== at 0x4C294C0: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==31715== by 0x40B2E3: __gnu_cxx::new_allocator<InterruptServiceRoutine*>::allocate(unsigned long, void const*) (new_allocator.h:104)
==31715== by 0x40B315: std::_Vector_base<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::_M_allocate(unsigned long) (in test/out/signals)
==31715== by 0x40B941: InterruptServiceRoutine** std::vector<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::_M_allocate_and_copy<std::move_iterator<InterruptServiceRoutine**> >(unsigned long, std::move_iterator<InterruptServiceRoutine**>, std::move_iterator<InterruptServiceRoutine**>) (stl_vector.h:1138)
==31715== by 0x40BA28: std::vector<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::reserve(unsigned long) (vector.tcc:75)
==31715== by 0x40AE7D: Signals::clear() (Signals.cpp:57)
==31715== by 0x40AF50: Signals::Signals(Logger&) (Signals.cpp:32)
==31715== by 0x403531: SignalsTestSuite::SignalsTestSuite() (in test/out/signals)
==31715== by 0x40302D: __static_initialization_and_destruction_0(int, int) (signals.cpp:18)
==31715== by 0x403144: _GLOBAL__sub_I_suite_SignalsTestSuite_init (signals.cpp:39)
==31715== by 0x4147EC: __libc_csu_init (elf-init.c:88)
==31715== by 0x5A8DA34: (below main) (libc-start.c:245)
==31715==
==31715== LEAK SUMMARY:
==31715== definitely lost: 0 bytes in 0 blocks
==31715== indirectly lost: 0 bytes in 0 blocks
==31715== possibly lost: 0 bytes in 0 blocks
==31715== still reachable: 176 bytes in 2 blocks
==31715== suppressed: 0 bytes in 0 blocks
==31715==
==31715== For counts of detected and suppressed errors, rerun with: -v
==31715== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Erreur de segmentation
I've tried to figure out why there are missing symbols (0x00007fffffffd210 in ?? () and at 0xFFEFFF1F0: ??? ...):
(gdb) info share
From To Syms Read Shared Object Library
0x00007ffff7ddca80 0x00007ffff7df5960 Yes /lib64/ld-linux-x86-64.so.2
No linux-vdso.so.1
0x00007ffff7bc6a40 0x00007ffff7bd2781 Yes /lib64/libpthread.so.0
0x00007ffff79bb360 0x00007ffff79be0dc Yes /lib64/librt.so.1
0x00007ffff770f5f0 0x00007ffff77733c3 Yes /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/libstdc++.so.6
0x00007ffff73c04f0 0x00007ffff7425266 Yes /lib64/libm.so.6
0x00007ffff71a7ac0 0x00007ffff71b6e45 Yes /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/libgcc_s.so.1
0x00007ffff6e2c430 0x00007ffff6f53b44 Yes /lib64/libc.so.6
But can't find a way to get "linux-vdso.so.1" on gentoo.
I'm a beginner in C++ what I'm doing wrong with memory ?
Have you a tip to fix this ?
Edit1:
routine_t and __sighandler_t types are aliases for: void (*)(void)
I believe that you can safely ignore the error. A StackOverflow member with a reputation in the top 0.25% of members (!) says that this warning "Could not load shared library symbols for linux-vdso.so.1." is something you can safely ignore. To see the post, go here:
Could not load shared library symbols for linux-vdso.so.1. while debugging
Problem solved thanks to Igor Tandetnik.
Finally the following code function.
signals.h:
#ifndef __SIGNALS_H__
#define __SIGNALS_H__
#include <vector>
#include <ISR.h>
#include <signal.h>
using namespace std;
class Logger;
class Signals
{
private:
Logger& log;
static bool action_handled;
void reserve();
public:
static void start();
static void stop();
static std::vector<ISR_t*> isr_table;
Signals(Logger& _log);
~Signals();
unsigned int count(void);
void clear(void);
void connect(ISR_t&);
static void apply(int);
static void unmask_pthread_signals();
static void mask_pthread_signals();
};
#endif // __SIGNALS_H__
signals.cpp:
#include <functional>
#include <signal.h>
#include <pthread.h>
#include <ISR.h>
#include <Signals.h>
#include <Logger.h>
using namespace std;
vector<ISR_t*> Signals::isr_table={};
bool Signals::action_handled=false;
void Signals::apply(int)
{
mask_pthread_signals();
for (unsigned int i=0; i < isr_table.size(); ++i)
{
isr_table[i]->apply();
}
unmask_pthread_signals();
}
Signals::Signals(Logger& _log): log(_log){
clear();
start();
}
Signals::~Signals() {
clear();
stop();
}
void Signals::clear(void)
{
isr_table.clear();
isr_table.reserve(0);
}
unsigned int Signals::count(void)
{
return isr_table.size();
}
void Signals::start()
{
if (action_handled) return;
struct sigaction new_action;
new_action.sa_handler = (__sighandler_t) &Signals::apply;
new_action.sa_flags = 0;
sigemptyset(&new_action.sa_mask);
sigaction(SIGUSR1, &new_action, NULL);
unmask_pthread_signals();
action_handled = true;
}
void Signals::stop()
{
if (!action_handled) return;
struct sigaction new_action;
new_action.sa_handler = SIG_DFL;
sigemptyset(&new_action.sa_mask);
sigaction(SIGUSR1, &new_action, NULL);
mask_pthread_signals();
action_handled = false;
}
void Signals::unmask_pthread_signals()
{
sigset_t signals_mask;
sigemptyset(&signals_mask);
pthread_sigmask(SIG_SETMASK, &signals_mask, NULL);
}
void Signals::mask_pthread_signals()
{
sigset_t signals_mask;
sigfillset(&signals_mask);
pthread_sigmask(SIG_SETMASK, &signals_mask, NULL);
}
void Signals::reserve()
{
if (isr_table.capacity() <= isr_table.size()) {
isr_table.reserve(isr_table.capacity() + 20);
}
}
void Signals::connect(ISR_t &isr)
{
start();
reserve();
isr_table.push_back(&isr);
}
When attempting to use getopt multiple times, the error I get in valgrind is Invalid read of size 1. The error only occurs when doing something like this:
ls -a -b
ls -a -b
Therefore I'm assuming the problem is with reusing the getopt functions.
Command.h
class Command {
protected:
// for use in getopt
int c = 0;
// name of command
char* name;
public:
Command(const char* nname) : name((char*)nname) { }
virtual ~Command() { };
virtual void process_args(int argc, char* argv[]) = 0;
virtual char* get_name() const {
return name;
}
};
ls.h is simply this wrapped in a class:
class ls : public Command {
public:
ls() : Command("ls") { }
~ls() { }
void process_args(int input_argc, char* input_argv[]) {
int verbose_flag = 0;
struct option long_options[] =
{
/* These options set a flag. */
{"verbose", no_argument, &verbose_flag, 1},
{"brief", no_argument, &verbose_flag, 0},
/* These options don't set a flag.
We distinguish them by their indices. */
{"add", no_argument, 0, 'a'},
{"append", no_argument, 0, 'b'},
{"delete", required_argument, 0, 'd'},
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 'f'},
{0, 0, 0, 0}
};
while (1) {
// removed static and moved struct outside
// everything else is the same
}
}
};
main.cpp
std::vector<std::unique_ptr<Command>> commands;
commands.push_back(std::unique_ptr<Command>(new ls()));
commands.push_back(std::unique_ptr<Command>(new shibe()));
while (true) {
std::string input;
std::getline(std::cin, input);
if (input == "quit")
break;
std::istringstream iss(input);
std::vector<std::string> args;
std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), std::back_inserter(args));
int input_argc = args.size();
char* input_argv[input_argc];
for (int i = 0; i < args.size(); i++) {
input_argv[i] = (char*)args[i].c_str();
}
for (int i = 0; i < commands.size(); i++) {
if (strcmp(input_argv[0], commands[i]->get_name()) == 0) {
commands[i]->process_args(input_argc, input_argv);
break;
}
}
}
Valgrind output is:
ls -a -b
--30624-- REDIR: 0x375e8812d0 (strlen) redirected to 0x480155c (_vgnU_ifunc_wrap per)
--30624-- REDIR: 0x375e87f810 (__GI_strchr) redirected to 0x4a07b30 (__GI_strchr )
option -a
option -b
ls -a -b
==30624== Invalid read of size 1
==30624== at 0x375E8CDFDC: _getopt_internal_r (in /lib64/libc-2.12.so)
==30624== by 0x375E8CF1EA: _getopt_internal (in /lib64/libc-2.12.so)
==30624== by 0x375E8CF2D2: getopt_long (in /lib64/libc-2.12.so)
==30624== by 0x401E1C: ls::process_args(int, char**) (ls.h:31)
==30624== by 0x4019CB: main (main.cpp:36)
==30624== Address 0x513e5da is 26 bytes inside a block of size 27 free'd
==30624== at 0x4A05FD6: operator delete(void*) (vg_replace_malloc.c:480)
==30624== by 0x4CCADFE: std::basic_string<char, std::char_traits<char>, std:: allocator<char> >::~basic_string() (basic_string.h:538)
==30624== by 0x403AA5: void std::_Destroy<std::string>(std::string*) (stl_con struct.h:93)
==30624== by 0x403855: void std::_Destroy_aux<false>::__destroy<std::string*> (std::string*, std::string*) (stl_construct.h:103)
==30624== by 0x403466: void std::_Destroy<std::string*>(std::string*, std::st ring*) (stl_construct.h:126)
==30624== by 0x402DE6: void std::_Destroy<std::string*, std::string>(std::str ing*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==30624== by 0x402878: std::vector<std::string, std::allocator<std::string> > ::~vector() (stl_vector.h:415)
==30624== by 0x401A03: main (main.cpp:26)
==30624==
--30624-- REDIR: 0x375e8846b0 (mempcpy) redirected to 0x4a09f80 (mempcpy)
non-option input_argv-elements: s b
quit
--30624-- REDIR: 0x375e87b6d0 (free) redirected to 0x4a06369 (free)
==30624==
==30624== HEAP SUMMARY:
==30624== in use at exit: 0 bytes in 0 blocks
==30624== total heap usage: 36 allocs, 36 frees, 916 bytes allocated
==30624==
==30624== All heap blocks were freed -- no leaks are possible
==30624==
==30624== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
==30624==
Linux's manpage on getopt() makes it clear how to reset getopt() (which unfortuantely uses a number of global variables to communicate with the caller and maintain state):
The variable optind is the index of the next element to be processed in argv. The system initializes this value to 1. The caller can reset it to 1 to restart scanning of the same argv, or when scanning a new argument vector.
For a school project, we have to send big files across the network., we must use Poco::XML for our data.
After our files are send over the network, it appears that the memory does not free.
Here is an example for a file of ~9 Mb on the receiving part:
valgrind --leak-check=full --show-reachable=yes -v ourExecutable parms returns:
12,880,736 bytes in 37 blocks are definitely lost in loss record 101 of 101
at 0x4C2747E: operator new(unsigned long) (vg_replace_malloc.c:261)
by 0x5A3AC88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
by 0x5A3BC4A: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
by 0x5A3C1BB: std::string::reserve(unsigned long) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
by 0x5A3C68E: std::string::append(std::string const&) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
by 0x5202359: Poco::XML::Element::innerText() const (in /home/tomwij/IGS/trunk/Project/external/lib/libPocoXML.so.8)
by 0x4145BF: NodeProtocol::getChildNodeStrValue(Poco::XML::Element*, std::string) (NodeProtocol.cpp:82)
by 0x41544F: NodeProtocol::deserialize(std::string const&) (NodeProtocol.cpp:200)
by 0x40B088: Node::handleClientPacket(PriorityElement*) (Node.cpp:760)
by 0x40A04C: Node::handlePackets() (Node.cpp:574)
by 0x4078EA: Node::run() (Node.cpp:162)
by 0x40772D: Node::activate() (Node.cpp:138)
LEAK SUMMARY:
definitely lost: 12,888,036 bytes in 190 blocks
indirectly lost: 644,979 bytes in 1,355 blocks
possibly lost: 10,089 bytes in 27 blocks
still reachable: 306,020 bytes in 43 blocks
suppressed: 0 bytes in 0 blocks
The function which is right before Poco is
const string NodeProtocol::getChildNodeStrValue(Element * elem, string child)
{
Element* tempNode = elem->getChildElement(child);
XMLString result(tempNode->innerText());
string ret = string(fromXMLString(result));
result.clear();
return ret;
}
which calls
XMLString Element::innerText() const
{
XMLString result;
Node* pChild = firstChild();
while (pChild)
{
result.append(pChild->innerText());
pChild = pChild->nextSibling();
}
return result;
}
(Note that XMLString is std::string)
Why is the append of STL string leaking memory?
If I just assign instead of using the copy constructors it gives the same problem.
EDIT:
I'm using the latest stable GNU GCC 4.4.4 on Gentoo x64 (linux-2.6.34-gentoo-r12).
More functions from the call stack (stripped irrelevant big chunks of code / if structures):
Command * NodeProtocol::deserialize(const string & msg)
{
DOMParser xmlParser;
// Get the root node.
AutoPtr<Document> doc = xmlParser.parseString(msg);
AutoPtr<Element> rootElement = doc->documentElement();
string root = fromXMLString(rootElement->nodeName());
string name = getChildNodeStrValue(rootElement, "name");
string data = getChildNodeStrValue(rootElement, "data");
return new PutCommand(name, data);
}
and
void Node::handleClientPacket(PriorityElement * prio)
{
Command * command = NodeProtocol::deserialize(prio->fPacket);
// CUT: Access some properties of command, let the command execute.
delete command;
}
and
void Node::handlePackets()
{
PriorityElement * prio = fQueue->top();
fQueue->pop();
if (prio->fSource == kCLIENT)
handleClientPacket(prio);
else if (prio->fSource == kNODE)
handleNodePacket(prio);
delete prio;
}
where fQueue is:
priority_queue< PriorityElement*, vector<PriorityElement*>, ComparisonFunction >
I would make this a comment, but apparently I don't have the rep. Have you remembered to make the destructor for Command virtual? If name or data are fields of PutCommand rather than Command and the Command destructor is not virtual, they may not be freed properly when you delete command in handleClientPacket.