Wycieki pamięci

0

Chciałem zapytać, czy możliwe są wycieki pamięci gdy nie używamy ani malloca, ani new .... Tworzę tablicę char tab[1000]. wskaźnik do tablicy (tab) przekazuje do funkcji, która przekazuje ją do jeszcze innej funkcji. Po drodze nic z nim specjalnego nie robie - odczytuje, kopiuje itp.
Korzystam ze klas string, vector, map ...
Valgrind pokazuje, że mam wycieki pamięci.

==7664== 9,445 (964 direct, 8,481 indirect) bytes in 1 blocks are definitely lost in loss record 22 of 27
==7664==    at 0x4025BD3: malloc (vg_replace_malloc.c:236)
==7664==    by 0x407A40E: my_malloc (in /usr/lib/libmysqlclient.so.16.0.0)
==7664==    by 0x40A64EB: mysql_init (in /usr/lib/libmysqlclient.so.16.0.0)
==7664==    by 0x804BCD1: user_mysql_authorization(mysql_log_data_struct const&, std::string const&, std::string const&, bool&, std::string&, std::string&, std::string&, std::string&, std::string&, std::string&, std::string&, std::string&, bool) (main.cpp:562)
==7664==    by 0x804C79C: getuserinfo_command(mysql_log_data_struct const&, cmd_t const&, std::string const&, std::string&, bool&) (main.cpp:702)
==7664==    by 0x804A784: thread_proc(void*) (main.cpp:279)
==7664==    by 0x435ECC8: start_thread (pthread_create.c:304)
==7664==    by 0x444369D: clone (clone.S:130)

==7664== 28,616 bytes in 7 blocks are possibly lost in loss record 27 of 27
==7664==    at 0x4025BD3: malloc (vg_replace_malloc.c:236)
==7664==    by 0x408253D: my_once_alloc (in /usr/lib/libmysqlclient.so.16.0.0)
==7664==    by 0x4082D99: ??? (in /usr/lib/libmysqlclient.so.16.0.0)
==7664==    by 0x4083889: ??? (in /usr/lib/libmysqlclient.so.16.0.0)
==7664==    by 0x4083ADB: get_charset_by_csname (in /usr/lib/libmysqlclient.so.16.0.0)
==7664==    by 0x40A6211: mysql_init_character_set (in /usr/lib/libmysqlclient.so.16.0.0)
==7664==    by 0x40A82DB: mysql_real_connect (in /usr/lib/libmysqlclient.so.16.0.0)
==7664==    by 0x804BD4C: user_mysql_authorization(mysql_log_data_struct const&, std::string const&, std::string const&, bool&, std::string&, std::string&, std::string&, std::string&, std::string&, std::string&, std::string&, std::string&, bool) (main.cpp:566)
==7664==    by 0x804D258: join_command(mysql_log_data_struct const&, cmd_t const&, std::string&, bool&) (main.cpp:773)
==7664==    by 0x804A4A3: thread_proc(void*) (main.cpp:237)
==7664==    by 0x435ECC8: start_thread (pthread_create.c:304)
==7664==    by 0x444369D: clone (clone.S:130)

Wiem, że słabo opisałem problem, ale nie wiem za bardzo co wkleić. Dla przykładu mogę wkleić funkcję join ...

int join_command(const mysql_log_data_struct &mysql_log_data, const cmd_t &cmd, string &msg, bool &isAdmin)
{
    int retval = 0;
    map<string, client_t>::iterator client_iter;
    map<string, clientAdmin_t>::iterator admin_iter;

    string nieprzeczytane = "";
    clientAdmin_t klientTemp;
    klientTemp.pin = cmd.op1;

    if(cmd.op1.length() == 0 || cmd.op2.length() == 0)
    {
      msg = "201 INVALID ID / PIN";
      retval = 0;
    }
    else
    {
      if(user_mysql_authorization(mysql_log_data, cmd.op1, cmd.op2, isAdmin, klientTemp.imie, klientTemp.nazwisko,
         klientTemp.miejscowosc, klientTemp.ulica, klientTemp.nr,
         klientTemp.stanowisko, klientTemp.status, nieprzeczytane) == true)
      {
        if(isAdmin == false) //Zwykły klient.
        {
          //Czy nick jest już na liście ?
          pthread_mutex_lock(&client_list_mutex);
          client_iter = client_list.find(cmd.op1);
          if(client_iter == client_list.end()) //nie ma na liście
          {
            //dodajemy klienta do listy
            client_list[cmd.op1].pin = cmd.op1;
            client_list[cmd.op1].imie = klientTemp.imie;
            client_list[cmd.op1].nazwisko = klientTemp.nazwisko;
            client_list[cmd.op1].miejscowosc = klientTemp.miejscowosc;
            client_list[cmd.op1].ulica = klientTemp.ulica;
            client_list[cmd.op1].nr = klientTemp.nr;
            //zapis daty logowania ...
            user_mysql_log_date(mysql_log_data, cmd.op1);
            //wysyłamy dane do świeżo zalogowanego usera ... 
            client_list[cmd.op1].wychodzace.push_back(make_info_command(klientTemp, "MYINFO"));
            //powiadamiamy adminów o przyłączeniu się usera i wysyłamy info o nim
            client_list[cmd.op1].wychodzace.push_back("UNREAD " + (string)nieprzeczytane);
            pthread_mutex_lock(&admin_list_mutex);
            for (admin_iter = admin_list.begin() ; admin_iter != admin_list.end(); ++admin_iter)
            {
              //każdy admin dostaje info o przyłączeniu się nowego usera.
              //(*admin_iter).second.wychodzace.push_back("JOINUSER " + cmd.op1);
              //i wszelkie informacje o nim samym - imie, nazwisko itd;
              (*admin_iter).second.wychodzace.push_back(make_info_command(klientTemp, "JOINUSER"));
              //wysyłamy userowi dane na temat każdego z adminów ...
              if((*admin_iter).second.status == "hide" || (*admin_iter).second.status == "userhide") continue;
              client_list[cmd.op1].wychodzace.push_back(make_info_command( (*admin_iter).second , "ADMININFO"));
            }
            pthread_mutex_unlock(&admin_list_mutex);
            msg = "100 OK";
            retval = 1;
          }
          else //jest na liście
          {
            msg = "200 PIN ALREADY IN USE";
            retval = 0;
          }
          pthread_mutex_unlock(&client_list_mutex);
        }
        else //admin...
        {
          pthread_mutex_lock(&admin_list_mutex);
          admin_iter = admin_list.find(cmd.op1);
          if(admin_iter == admin_list.end()) //takiego admina nie ma na liście
          {
            //dodajemy admina do listy
            admin_list[cmd.op1].pin = cmd.op1;
            admin_list[cmd.op1].imie = klientTemp.imie;
            admin_list[cmd.op1].nazwisko = klientTemp.nazwisko;
            admin_list[cmd.op1].miejscowosc = klientTemp.miejscowosc;
            admin_list[cmd.op1].ulica = klientTemp.ulica;
            admin_list[cmd.op1].nr = klientTemp.nr;
            admin_list[cmd.op1].stanowisko = klientTemp.stanowisko;
            admin_list[cmd.op1].status = klientTemp.status;
            user_mysql_log_date(mysql_log_data, cmd.op1);
            for (admin_iter = admin_list.begin() ; admin_iter != admin_list.end(); ++admin_iter)
            {
              if((*admin_iter).first == cmd.op1)
              {
                //wysyłamy świeżo zalogowanemy adminowi info o sobie ...
                 (*admin_iter).second.wychodzace.push_back(make_info_command(klientTemp, "MYADMININFO"));

                //wysłanie liczby nieprzeczytanych wiadomości zostawionych na serwerze ...
                (*admin_iter).second.wychodzace.push_back("UNREAD " + nieprzeczytane);
                 continue;
              }
              //każdy admin dostaje info o przyłączeniu się nowego admina, jeśli ten nie jest ukryty ...
              if(admin_list[cmd.op1].status != "hide")
              (*admin_iter).second.wychodzace.push_back(make_info_command(klientTemp, "ADMININFO"));
              if( (*admin_iter).second.status == "hide" ) continue;
              //nowy admin dostaje info o dostępnych(zalogowanych) adminach ...
              admin_list[cmd.op1].wychodzace.push_back( make_info_command((*admin_iter).second, "ADMININFO" ));
            }
            pthread_mutex_lock(&client_list_mutex); //informowanie userów o nowym adminie ...
            for (client_iter = client_list.begin() ; client_iter != client_list.end() ; ++client_iter)
            {
                //każdy user dostaje info o dostępności admina ( zaświeci się np. sprawy techniczne ).
                //(*client_iter).second.wychodzace.push_back("JOINADMIN " + cmd.op1);
                admin_list[cmd.op1].wychodzace.push_back( make_info_command(reinterpret_cast<clientAdmin_t &>((*client_iter).second), "JOINUSER" ));   
                if(klientTemp.status == "hide" || klientTemp.status == "userhide") continue;
                (*client_iter).second.wychodzace.push_back(make_info_command(klientTemp, "ADMININFO"));
            }
            pthread_mutex_unlock(&client_list_mutex);
            msg = "100 OK";
            retval = 1;
          }
          else
          {
            msg = "200 PIN ALREADY IN USE";
            retval = 0;
          }
          pthread_mutex_unlock(&admin_list_mutex);
        }
      }
      else 
      {
          msg = "300 ERROR_MYSQL_AUTH";
          retval = 0; //blad w funkcji user_mysql_authorization.
      }
    }
    return retval;
}

Mniej więcej cała aplikacja wygląda w podobny sposób jak funkcja powyżej... Być może gdzieś popełniam jakiś prosty błąd ?

0

nie chce mi się przeglądać calego kodu, ale:

  1. dlaczego zakładasz, że biblioteki z których korzystasz są idealne?
  2. sprawdzales czy z zadna z funkcji tej biblioteki nie zwraca obiektow, ktore nalezy pozniej zwolnic? np:
    aaa = load_xxx();
    free_xxx(aaa);
    jeśli nie używasz żadnych new/delete i malloc/free to nie znaczy ze nie przydzielasz pamieci
0

Używam tylko libmysql i pthread. Przy czym z mysql korzystam mniej więcej tak:

int getuserlist_command(const mysql_log_data_struct &mysql_log_data, const cmd_t &cmd, const string &nickname, string &msg, bool &isAdmin)
{
  if(isAdmin == false)
  {
    msg = "210 ACCESS_DANIED";
    return 0;
  }

  MYSQL *mysql = 0;
  MYSQL_RES *mysql_res = 0;
  MYSQL_ROW row = 0;
  unsigned int num_fields, i;
  bool retval = 0;
  ostringstream stream;
  stream << "USERLISTBEGIN ";
  mysql = mysql_init(0);
  if(mysql)
  {
    if(mysql_real_connect(mysql, mysql_log_data.serwer_ip.c_str(), mysql_log_data.username.c_str(), mysql_log_data.pass.c_str(), mysql_log_data.database.c_str(), 0, 0, 0 ) != 0)
    {
      ostringstream query;
      query << "SELECT id_klienta FROM klienci;";
      if(mysql_real_query(mysql, query.str().c_str(), query.str().length()) == 0)
      {
        mysql_res = mysql_use_result(mysql);
        if(mysql_res)
        {
          num_fields = mysql_num_fields(mysql_res);
          while ((row = mysql_fetch_row(mysql_res)))
          {
            unsigned long *lengths;
            lengths = mysql_fetch_lengths(mysql_res);
            for(i = 0 ; i < num_fields ; i++)
            {
              stream << row[i] ? row[i] : "0";
              stream << ",";
              stream.flush();
            }
          }
          mysql_free_result(mysql_res);
        }
      }
    }
  }
  stream << "USERLISTEND";

  msg = stream.str();
  mysql_close(0);
  return retval;
}

Mniej więcej każda funkcja korzystająca z mysql ma taki szkielet ...

0

a cóż takiego zamyka ten mysql_close(0) ???

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