XProtoman
(usa Fedora)
Enviado em 04/12/2015 - 19:27h
Boa noite, queria mostrar para vocês um erro interessante, segue o código(por enquanto não descomentem aquela linha):
#include <iostream>
#include <mutex>
//#define RESOLVER_PROBLEMA 1
class Teste
{
private:
std::mutex *mutex;
public:
Teste();
Teste(const Teste &teste);
~Teste();
#ifdef RESOLVER_PROBLEMA
void operator = (const Teste &teste);
#endif
};
Teste::Teste()
{
this->mutex = new std::mutex();
}
Teste::Teste(const Teste &teste): Teste()
{
teste.mutex->lock();
teste.mutex->unlock();
}
Teste::~Teste()
{
delete this->mutex;
this->mutex = NULL;
}
#ifdef RESOLVER_PROBLEMA
void Teste::operator = (const Teste &teste)
{
teste.mutex->lock();
teste.mutex->unlock();
}
#endif
int main()
{
Teste teste;
for ( size_t posicao = 0, posicao_maximo = 1000000;
posicao_maximo > posicao;
posicao++ )
{
teste = Teste();
}
return 0;
}
Note que aparentemente não existe nada de errado com o código(alocações e desalocações sendo realizadas ondem devem), porém produz o erro:
$ ./teste_generico.run
*** Error in `./teste_generico.run': double free or corruption (fasttop): 0x0000000001ee1c50 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x77e15)[0x7f3b4ba5fe15]
/lib64/libc.so.6(+0x804fa)[0x7f3b4ba684fa]
/lib64/libc.so.6(cfree+0x4c)[0x7f3b4ba6bcac]
./teste_generico.run[0x400b82]
./teste_generico.run[0x400bf7]
/lib64/libc.so.6(__libc_start_main+0xf0)[0x7f3b4ba08580]
./teste_generico.run[0x400959]
======= Memory map: ========
00400000-00402000 r-xp 00000000 09:7b 39 /tmp/teste_generico.run
00601000-00602000 r--p 00001000 09:7b 39 /tmp/teste_generico.run
00602000-00603000 rw-p 00002000 09:7b 39 /tmp/teste_generico.run
01ed0000-01f02000 rw-p 00000000 00:00 0 [heap]
7f3b44000000-7f3b44021000 rw-p 00000000 00:00 0
7f3b44021000-7f3b48000000 ---p 00000000 00:00 0
7f3b4b9e8000-7f3b4bb9f000 r-xp 00000000 09:7f 1050566 /usr/lib64/libc-2.22.so
7f3b4bb9f000-7f3b4bd9f000 ---p 001b7000 09:7f 1050566 /usr/lib64/libc-2.22.so
7f3b4bd9f000-7f3b4bda3000 r--p 001b7000 09:7f 1050566 /usr/lib64/libc-2.22.so
7f3b4bda3000-7f3b4bda5000 rw-p 001bb000 09:7f 1050566 /usr/lib64/libc-2.22.so
7f3b4bda5000-7f3b4bda9000 rw-p 00000000 00:00 0
7f3b4bdb0000-7f3b4bdc6000 r-xp 00000000 09:7f 1048596 /usr/lib64/libgcc_s-5.1.1-20150618.so.1
7f3b4bdc6000-7f3b4bfc5000 ---p 00016000 09:7f 1048596 /usr/lib64/libgcc_s-5.1.1-20150618.so.1
7f3b4bfc5000-7f3b4bfc6000 r--p 00015000 09:7f 1048596 /usr/lib64/libgcc_s-5.1.1-20150618.so.1
7f3b4bfc6000-7f3b4bfc7000 rw-p 00016000 09:7f 1048596 /usr/lib64/libgcc_s-5.1.1-20150618.so.1
7f3b4bfc8000-7f3b4c0c9000 r-xp 00000000 09:7f 1050574 /usr/lib64/libm-2.22.so
7f3b4c0c9000-7f3b4c2c8000 ---p 00101000 09:7f 1050574 /usr/lib64/libm-2.22.so
7f3b4c2c8000-7f3b4c2c9000 r--p 00100000 09:7f 1050574 /usr/lib64/libm-2.22.so
7f3b4c2c9000-7f3b4c2ca000 rw-p 00101000 09:7f 1050574 /usr/lib64/libm-2.22.so
7f3b4c2d0000-7f3b4c442000 r-xp 00000000 09:7f 1050874 /usr/lib64/libstdc++.so.6.0.21
7f3b4c442000-7f3b4c642000 ---p 00172000 09:7f 1050874 /usr/lib64/libstdc++.so.6.0.21
7f3b4c642000-7f3b4c64c000 r--p 00172000 09:7f 1050874 /usr/lib64/libstdc++.so.6.0.21
7f3b4c64c000-7f3b4c64e000 rw-p 0017c000 09:7f 1050874 /usr/lib64/libstdc++.so.6.0.21
7f3b4c64e000-7f3b4c652000 rw-p 00000000 00:00 0
7f3b4c658000-7f3b4c679000 r-xp 00000000 09:7f 1050557 /usr/lib64/ld-2.22.so
7f3b4c84c000-7f3b4c850000 rw-p 00000000 00:00 0
7f3b4c877000-7f3b4c878000 rw-p 00000000 00:00 0
7f3b4c878000-7f3b4c879000 r--p 00020000 09:7f 1050557 /usr/lib64/ld-2.22.so
7f3b4c879000-7f3b4c87a000 rw-p 00021000 09:7f 1050557 /usr/lib64/ld-2.22.so
7f3b4c87a000-7f3b4c87c000 rw-p 00000000 00:00 0
7f3b4c87c000-7f3b4c87d000 rw-p 00000000 00:00 0
7fffa12a4000-7fffa12c5000 rw-p 00000000 00:00 0 [stack]
7fffa1398000-7fffa139a000 r--p 00000000 00:00 0 [vvar]
7fffa139a000-7fffa139c000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Abortado (imagem do núcleo gravada)
Como a mensagem mesmo diz, é como se ocorresse uma dupla liberação de memória, o valgrind detecta isso(como a mensagem é muito grande nem vou passar, mas basta saber que ele detecta).
Descomentando a linha 4 do código vai sobrecarregar o operador de atribuição e o problema estará resolvido. Primeira vez que me deparo com uma situação desses e por causa disso vou ter que mudar algumas coisas dentro das minhas classes. Tem alguma explicação?
Achei que numa situação como esse seria apenas necessário e bastaria o construtor o Teste(const Teste &teste), mas pelo visto é necessário também sobrecarregar o operador de atribuição(=).
Obrigado. (Está sendo muito produtivo)