Dziwny problem z std::map

Odpowiedz Nowy wątek
2011-05-09 07:22
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ą?

Pozostało 580 znaków

2011-05-09 09:16
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).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2011-05-09 10:36
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() ;
}

Pozostało 580 znaków

2011-05-09 11:24
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...

Pozostało 580 znaków

2011-05-09 11:26
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

Pozostało 580 znaków

2011-05-09 11:55

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()?


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22, 2011-05-09 11:58

Pozostało 580 znaków

2011-05-09 12:03
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

najśmieszniejsz jet to, że na 100% kompilator ostrzegał cię, że coś jest nie tak, na pewno miałeś ostrzeżenia w stylu: value set but never used, use of unset variable, itp. - MarekR22 2011-05-09 12:14
nie. gcc, mnie nie ostrzegł... - rafal__ 2011-05-09 22:14

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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