Dziwny problem z std::map

0

Mam sobie klasę, która jest singletonem:

//plik h:
#ifndef _MAC_ADDRESS_H
#define _MAC_ADDRESS_H

#include "popenrr.h"

#include <iostream>
#include <map>

class MACAddress
{
	private:
		static MACAddress *instance;
		
		std::map<std::string, std::string> mapOfMACs;
	protected:
		MACAddress() ;
		virtual ~MACAddress(){};
		
		inline std::string getStringIfconfig() 
		{
			return POpenRR::getResultOfPopen("ifconfig -a | grep HWaddr") ;	
		}
	public:
		static MACAddress *Instance() ;
		static void Release() ;
		
		void RefreshMapOfMACs() ;
		std::string GetMAC(std::string interface) ;
};

#endif
//plik.cpp:
#include "macaddress.h"

#include <utility>

MACAddress *MACAddress::instance = NULL;

MACAddress::MACAddress()
{
}

MACAddress *MACAddress::Instance()
{
	if(!instance)
	{
		instance = new MACAddress ;
	}
	return instance;
}

void MACAddress::Release()
{
	if(instance)
	{
		delete instance;
		instance = NULL ;
	}
}


void MACAddress::RefreshMapOfMACs() 
{
	std::string ifconfig = getStringIfconfig() ;
	std::string interface ;
	std::string MAC ;
	
	mapOfMACs.clear() ;
	std::istringstream iss(ifconfig) ;
	std::string tempString;
	int i=0;
	while(iss>>tempString)
	{		
		switch(i)
		{
			case 0:
			{
				interface=tempString;
			}break;
			case 4:
			{
				MAC=tempString;
				std::cout<<interface<<" : "<<MAC<<"\n";
				mapOfMACs[interface] = MAC ;
			}break;
			default:
			{
				
			}
		}
		i++;
		i%=5;
	}
}

std::string MACAddress::GetMAC(std::string interface) 
{
	std::cout<<"rozm = "<<(mapOfMACs.size())<<"\n";
	if(mapOfMACs.empty())
	{
		RefreshMapOfMACs();
	}
	return mapOfMACs[interface] ;
}

O co chodzi? Ano o to, że coś dziwnego dzieje się z mapą

std::map<std::string, std::string> mapOfMACs;

. Nigdy nie jest empty(), próba sprawdzenia jej rozmiaru daje za każdym razem inne dziwne rezultaty: rozm = 3075230046
Można tylko raz na niej wywołać clear(). Każde dodatkowe clear() jak również każda próba dostania się do jej elementów lub jej zmiana zawartości powoduje segfault.

Przykładowe wykorzystanie tej klasy:

MACAddress::Instance()->GetMAC("eth0");

Gdy pozmieniam funkcję GetMAC() tak, aby nie sprawdzała rozmiaru mapy, tylko za każdym razem robiła RefreshMapOfMACs wywala mi na pierwszej próbie zapisu do mapy:

rozm = 3075230046
eth0 : 00:1b:fc:dc:14:7f
Naruszenie ochrony pamięci

Kod pisany po nocach, to nie jest dobry pomysł. Kto mi powie, co jest źle z tą mapą?

0

musisz gdzieś źle operować na pamięci, niekoniecznie w kodzie, który podałeś. Masz pecha, że problem objawia się późno, w miejscu w którym nie ma błędu, ale wcześniejszy błąd przynosi tragiczne skutki.
Zapewne zaraz po konstrukcji obiektu wszystko jest tak jak należy.
Nie masz wyjścia musisz sam wszystko przedebugować (spróbuj użyć jakiś narzędzi np valgrind).

0
MarekR22 napisał(a)

musisz gdzieś źle operować na pamięci, niekoniecznie w kodzie, który podałeś. Masz pecha, że problem objawia się późno, w miejscu w którym nie ma błędu, ale wcześniejszy błąd przynosi tragiczne skutki.
Zapewne zaraz po konstrukcji obiektu wszystko jest tak jak należy.
Nie masz wyjścia musisz sam wszystko przedebugować (spróbuj użyć jakiś narzędzi np valgrind).

ale ja na razie robiłem tylko prosty (pseudo) test jednostkowy dla tej klasy, bez żadnej dodatkowej biblioteki, tylko na assertach. kod unit_testu:

#include <assert.h>
#include <iostream>
#include <sstream>
#include "macaddress.h"
#include "popenrr.h"


void SetUp(MACAddress *macAddress) ;
void RunTests(MACAddress *macAddress) ;
void TearDown(MACAddress *macAddress) ;

void RunTestForPOpen() ;


int main(int argc,char**argv)
{
	MACAddress *macAddress;
	
	std::cout<<"RunTest for MACAddress is starting.\n" ;
	SetUp(macAddress);
	RunTests(macAddress);
	TearDown(macAddress);	
	std::cout<<"Done.\n\n";
	
	std::cout<<"RunTest for RunTestForPOpen() is starting.\n" ;
	RunTestForPOpen() ;
	std::cout<<"Done.\n\n";
	
	return 0;
}

void SetUp(MACAddress *macAddress)
{	
	macAddress = MACAddress::Instance() ;
}


inline void MACIsNotZero(MACAddress *macAddress)
{
	assert(macAddress);
}

inline void AssertEqualInterface(MACAddress *macAddress, std::string interface, std::string MAC)
{
	assert(macAddress->GetMAC(interface)==MAC) ;
}

void RunTests(MACAddress *macAddress) 
{
	MACIsNotZero(macAddress) ;
	
	const std::string eth0("eth0");
	const std::string wlan0("wlan0");
	const std::string vboxnet0("vboxnet0");
	const std::string eth0MAC("00:1b:fc:dc:14:7f");
	const std::string wlan0MAC("00:1b:fc:b3:e3:a5");
	const std::string vboxnet0MAC("0a:00:27:00:00:00");
	
	AssertEqualInterface(macAddress,eth0,eth0MAC) ;
	AssertEqualInterface(macAddress,wlan0,wlan0MAC) ;
	AssertEqualInterface(macAddress,vboxnet0,vboxnet0MAC) ;
}

void TearDown(MACAddress *macAddress) 
{
	MACAddress::Release() ;
}





void assertIfconfigEth0()
{
	std::string result = POpenRR::getResultOfPopen("ifconfig -a | grep HWaddr") ;
	std::cout<<"result:\n"<<result<<"\n";
	std::istringstream iss(result) ;
	std::string strTemp ;
	iss>>strTemp;
	std::cout<<"strTemp:\n"<<strTemp<<"\n";
	assert(strTemp=="eth0") ;
}

void RunTestForPOpen() 
{
	assertIfconfigEth0() ;
}

ostatni brakujący pliki, jakimi operowałem:

#ifndef _POPEN_RR_H
#define _POPEN_RR_H

#include <sstream>

#include <stdio.h>

namespace POpenRR
{
	std::string getResultOfPopen(std::string command) ;

}


#endif

#include "popenrr.h"

std::string POpenRR::getResultOfPopen(std::string command) 
{
	std::ostringstream oss;
	
	FILE *fp = popen(command.c_str(), "r") ;
	char buffer[1024] ;
	while ( fgets(buffer, 1024, fp) != NULL )
	{
		oss<<buffer;
	}
	pclose(fp);
	
	return oss.str() ;
}
0

debugowałem najgłębiej jak się da, feralna linijka to zwracanie size() pliku stl_tree.h :

      size_type
      size() const
      { return _M_impl._M_node_count; }

właśnie _M_impl._M_node_count ma tą złą wartość... a konstruktor mapy wyglądał na ok...

0

backtrace sigsegv wygląda tak:

0  0xb7f66db2  std::string::compare(std::string const&) const    
1  0x0804a6ba  std::operator< <char, std::char_traits<char>, std::allocator<char> >  /usr/include/c++/4.4/bits/basic_string.h  2320
2  0x0804a444  std::less<std::string>::operator()  /usr/include/c++/4.4/bits/stl_function.h  230
3  0x0804abab  std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::_M_lower_bound  /usr/include/c++/4.4/bits/stl_tree.h  986
4  0x0804a687  std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::lower_bound  /usr/include/c++/4.4/bits/stl_tree.h  745
5  0x0804a3ec  std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::lower_bound  /usr/include/c++/4.4/bits/stl_map.h  701
6  0x0804a177  std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::operator[]  /usr/include/c++/4.4/bits/stl_map.h  447
7  0x08049eeb  MACAddress::GetMAC  /d/cpp/get_mac_addr/macaddress.cpp  71
8  0x08049a47  AssertEqualInterface  /d/cpp/get_mac_addr/macaddress_cl/main.cpp  45
9  0x0804952c  RunTests  /d/cpp/get_mac_addr/macaddress_cl/main.cpp  59
10  0x080492b9  main  /d/cpp/get_mac_addr/macaddress_cl/main.cpp  21
1

Np tu masz DUZY błąd:

rafal__ napisał(a)
void SetUp(MACAddress *macAddress)
{	
	macAddress = MACAddress::Instance() ;
}

to nic nie robi!!!
macAddress (to z main) nie ma ustawionej wartości!
Po co ci ta funkcja skoro masz już bardzo eleganckie MACAddress::Instance()?

0
MarekR22 napisał(a)

Np tu masz DUZY błąd:

rafal__ napisał(a)
void SetUp(MACAddress *macAddress)
{	
	macAddress = MACAddress::Instance() ;
}

to nic nie robi!!!
macAddress (to z main) nie ma ustawionej wartości!
Po co ci ta funkcja skoro masz już bardzo eleganckie MACAddress::Instance()?

o k***wa... jaki dziecinny błąd...

no to po sprawie ;) dzięki.

muszę więcej spać chyba, programowanie po nocach nie jest dobre

1 użytkowników online, w tym zalogowanych: 0, gości: 1