Недопустимо освобождать () / удалять / delete[] / realloc() с помощью std::shared_ptr

#c #c 11 #smart-pointers

#c #c 11 #интеллектуальные указатели

Вопрос:

Я новичок в использовании интеллектуальных указателей C . Я хотел использовать их в одном большом проекте, над которым я работаю, но я получаю следующую ошибку:

 ==21819== Invalid free() / delete / delete[] / realloc()
==21819==    at 0x4838E7B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21819==    by 0x188692: std::_Sp_counted_ptr<std::vector<double, std::allocator<double> >*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:377)
==21819==    by 0x12F1C9: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (shared_ptr_base.h:155)
==21819==    by 0x12E724: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (shared_ptr_base.h:706)
==21819==    by 0x1406D9: std::__shared_ptr<std::vector<double, std::allocator<double> >, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (shared_ptr_base.h:1145)
==21819==    by 0x14071B: std::shared_ptr<std::vector<double, std::allocator<double> > >::~shared_ptr() (shared_ptr.h:103)
==21819==    by 0x1CAB5A: myProg::LearningSequence::optimize(myProg::ErrorFunctionamp;, std::basic_ofstream<char, std::char_traits<char> >*) (LearningSequence.cpp:60)
==21819==    by 0x12DD6A: main (myScript_1_2.cpp:107)
==21819==  Address 0xb2b90d8 is 24 bytes inside a block of size 48 alloc'd
==21819==    at 0x4837DBF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21819==    by 0x1331C8: __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (new_allocator.h:111)
==21819==    by 0x132BA0: std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> >amp;, unsigned long) (alloc_traits.h:436)
==21819==    by 0x1320E9: std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> > >(std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> >amp;) (allocated_ptr.h:97)
==21819==    by 0x131988: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<myProg::RandomSolution, std::allocator<myProg::RandomSolution>>(std::_Sp_make_shared_tag, myProg::RandomSolution*, std::allocator<myProg::RandomSolution> constamp;) (shared_ptr_base.h:654)
==21819==    by 0x131206: std::__shared_ptr<myProg::RandomSolution, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<myProg::RandomSolution>>(std::_Sp_make_shared_tag, std::allocator<myProg::RandomSolution> constamp;) (shared_ptr_base.h:1322)
==21819==    by 0x130784: std::shared_ptr<myProg::RandomSolution>::shared_ptr<std::allocator<myProg::RandomSolution>>(std::_Sp_make_shared_tag, std::allocator<myProg::RandomSolution> constamp;) (shared_ptr.h:360)
==21819==    by 0x12FA99: std::shared_ptr<myProg::RandomSolution> std::allocate_shared<myProg::RandomSolution, std::allocator<myProg::RandomSolution>>(std::allocator<myProg::RandomSolution> constamp;) (shared_ptr.h:707)
==21819==    by 0x12EE24: std::shared_ptr<myProg::RandomSolution> std::make_shared<myProg::RandomSolution>() (shared_ptr.h:723)
==21819==    by 0x12DB48: main (myScript_1_2.cpp:86)
  

Меня это действительно смущает, потому что в строке 86 есть std::shared_ptr созданный.

 86    std::shared_ptr<myProg::LearningMethod> new_learning_method = std::make_shared<myProg::RandomSolution>();
    learning_sequence.add_learning_method( new_learning_method );

    std::shared_ptr<myProg::LearningMethod> new_learning_method2 = std::make_shared<myProg::ParticleSwarm>(myProg::ParticleSwarm(amp;domain_bounds,
                                                                                                     1.711897,
                                                                                                     1.711897,
                                                                                                     0.711897,
                                                                                                     0.5,
                                                                                                     0.3,
                                                                                                     0.7,
                                                                                                     n_particles_swarm,
                                                                                                     max_n_iters_swarm) );
//        learning_sequence.add_learning_method( new_learning_method2 );

    std::shared_ptr<myProg::LearningMethod> new_learning_method3 = std::make_shared<myProg::LevenbergMarquardt>(l4n::LevenbergMarquardt(max_n_iters_gradient_lm, batch_size, prec_lm ) );
    learning_sequence.add_learning_method( new_learning_method3 );


    /* Complex Optimization */
107    learning_sequence.optimize(mse1);  // Network training
  

Функция optimize() выглядит следующим образом:

    void LearningSequence::optimize(myProg::ErrorFunction amp;ef, std::ofstream *ofs) {

    double error = ef.eval();

    double the_best_error = error;
    int mcycles = this->max_number_of_cycles, cycle_idx = 0;

    std::shared_ptr<std::vector<double>> best_params = std::make_shared<std::vector<double>>(this->best_parameters);
    while( error > this->tol amp;amp; mcycles != 0){
        mcycles--;
        cycle_idx  ;

        for( auto m: this->learning_sequence ){
            m->optimize( ef, ofs );
            error = ef.eval(m->get_parameters());

            ef.get_network_instance()->copy_parameter_space(m->get_parameters());



            if( error < the_best_error ){
                the_best_error = error;
                this->best_parameters = *ef.get_parameters();
            }

            if( error <= this->tol ){
                ef.get_network_instance()->copy_parameter_space( best_params );
                return;
            }
        }
        COUT_DEBUG("Cycle: " << cycle_idx << ", the lowest error: " << the_best_error << std::endl );
    }
    ef.get_network_instance()->copy_parameter_space( best_params );
}
  

Ошибка далее возникает в функции eval() :

 double MSE::eval(std::shared_ptr<std::vector<double>> weights,
                 bool denormalize_data,
                 bool verbose) {
    return this->eval_on_data_set(this->ds,
                                  nullptr,
                                  weights,
                                  denormalize_data,
                                  verbose);
    puts("END OF EVAL()");
}
  

which calls eval_on_data_set() :

    double MSE::eval_on_data_set(myProg::DataSet* data_set,
                                 std::ofstream* results_file_path,
                                 std::shared_ptr<std::vector<double>> weights,
                                 bool denormalize_data,
                                 bool verbose) {
        size_t dim_in = data_set->get_input_dim();
        size_t dim_out = data_set->get_output_dim();
        double error = 0.0, val, output_norm = 0;

        std::vector<std::pair<std::vector<double>, std::vector<double>>>* data = data_set->get_data();
        size_t n_elements = data->size();

        std::vector<std::vector<double>> outputs(data->size());
        std::vector<double> output(dim_out);

        if (verbose) {
            COUT_DEBUG("Evaluation of the error function MSE on the given data-set" << std::endl);
            COUT_DEBUG(R_ALIGN << "[Element index]" << " "
                               << R_ALIGN << "[Input]" << " "
                               << R_ALIGN << "[Real output]" << " "
                               << R_ALIGN << "[Predicted output]" << " "
                               << R_ALIGN << "[Absolute error]" << " "
                               << R_ALIGN << "[Relative error %]"
                               << std::endl);
        }

        if (results_file_path) {
            *results_file_path << R_ALIGN << "[Element index]" << " "
                               << R_ALIGN << "[Input]" << " "
                               << R_ALIGN << "[Real output]" << " "
                               << R_ALIGN << "[Predicted output]" << " "
                               << R_ALIGN << "[Abs. error]" << " "
                               << R_ALIGN << "[Rel. error %]"
                               << std::endl;
        }

        for (auto i = 0; i < data->size(); i  ) {  // Iterate through every element in the test set
            /* Compute the net output and store it into 'output' variable */
            this->net->eval_single(data->at(i).first,
                                   output,
                                   weights);

            outputs.at(i) = output;
        }

        double denormalized_output;
        double denormalized_real_input;
        double denormalized_real_output;

        for (auto i = 0; i < data->size(); i  ) {

            /* Compute difference for every element of the output vector */
#ifdef DEBUG
            std::stringstream ss_input;
            std::string separator = "";
            for (auto j = 0; j < dim_in; j  ) {
                if(denormalize_data) {
                    denormalized_real_input = data_set->get_normalization_strategy()->de_normalize(data->at(i).first.at(j));
                } else {
                    denormalized_real_input = data->at(i).first.at(j);
                }
                ss_input << separator << denormalized_real_input;
                separator = ",";
            }
            if(denormalize_data) {
                denormalized_real_input = data_set->get_normalization_strategy()->de_normalize(data->at(i).first.back());
            } else {
                denormalized_real_input = data->at(i).first.back();
            }

            std::stringstream ss_real_output;
            std::stringstream ss_predicted_output;
#endif

            double loc_error = 0;
            output_norm = 0;
            separator = "";
            for (size_t j = 0; j < dim_out;   j) {
                if (denormalize_data) {
                    denormalized_real_output = data_set->get_normalization_strategy()->de_normalize(data->at(i).second.at(j));
                    denormalized_output = data_set->get_normalization_strategy()->de_normalize(outputs.at(i).at(j));
                } else {
                    denormalized_real_output = data->at(i).second.at(j);
                    denormalized_output = outputs.at(i).at(j);
                }

#ifdef DEBUG
                ss_real_output << separator << denormalized_real_output;
                ss_predicted_output << separator << denormalized_output;
                separator = ",";
#endif

                val = denormalized_output - denormalized_real_output;
                loc_error  = val * val;
                error  = loc_error;

                output_norm  = denormalized_output * denormalized_output;
            }

#ifdef DEBUG
            std::stringstream ss_ind;
            ss_ind << "[" << i << "]";

            if (verbose) {
                COUT_DEBUG(R_ALIGN << ss_ind.str() << " "
                                   << R_ALIGN << ss_input.str() << " "
                                   << R_ALIGN << ss_real_output.str() << " "
                                   << R_ALIGN << ss_predicted_output.str() << " "
                                   << R_ALIGN << std::sqrt(loc_error) << " "
                                   << R_ALIGN
                                   << 200.0 * std::sqrt(loc_error) / (std::sqrt(loc_error)   std::sqrt(output_norm))
                                   << std::endl);
            }

            if (results_file_path) {
                *results_file_path << R_ALIGN << ss_ind.str() << " "
                                   << R_ALIGN << ss_input.str() << " "
                                   << R_ALIGN << ss_real_output.str() << " "
                                   << R_ALIGN << ss_predicted_output.str() << " "
                                   << R_ALIGN << std::sqrt(loc_error) << " "
                                   << R_ALIGN
                                   << 200.0 * std::sqrt(loc_error) / (std::sqrt(loc_error)   std::sqrt(output_norm))
                                   << std::endl;
            }
#endif
        }

        double result = std::sqrt(error) / n_elements;

        if (verbose) {
            COUT_DEBUG("MSE = " << result << std::endl);
        }

        if (results_file_path) {
            *results_file_path << "MSE = " << result << std::endl;
        }

        puts("END OF EVAL_ON_DATA_SET");
        return resu<
    }
  

Самое странное, что перед завершением работы программы выводится КОНЕЦ EVAL_ON_DATA_SET, а КОНЕЦ EVAL() — нет, т.е. программа завершает работу с завершением eval_on_data_set() функции.

Есть ли какой-либо способ выяснить, что происходит?

Большое вам спасибо за любой совет.


Редактировать

Я попытался использовать средство очистки памяти в соответствии с советом xaxxon, и вот результат:

 =================================================================
==6515==ERROR: AddressSanitizer: alloc-dealloc-mismatch (INVALID vs operator delete) on 0x604000001ee8
    #0 0x7f2ad3a55118 in operator delete(void*, unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.5 0xf1118)                                                                              
    #1 0x5589562f445b in std::_Sp_counted_ptr<std::vector<double, std::allocator<double> >*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c  /8/bits/shared_ptr_base.h:377
    #2 0x558956239de2 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c  /8/bits/shared_ptr_base.h:155
    #3 0x5589562386dd in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c  /8/bits/shared_ptr_base.h:706
    #4 0x5589562383f1 in std::__shared_ptr<std::vector<double, std::allocator<double> >, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c  /8/bits/shared_ptr_base.h:1145
    #5 0x55895623840d in std::shared_ptr<std::vector<double, std::allocator<double> > >::~shared_ptr() /usr/include/c  /8/bits/shared_ptr.h:103
    #6 0x558956393484 in myProg::LearningSequence::optimize(myProg::ErrorFunctionamp;, std::basic_ofstream<char, std::char_traits<char> >*) /home/martin/myProg/src/LearningMethods/LearningSequence.cpp:60
    #7 0x55895623685e in main /home/martin/myProg/src/examples/simulator_1_2.cpp:108
    #8 0x7f2ad31cf09a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6 0x2409a)
    #9 0x558956235669 in _start (/home/martin/myProg/build/bin/examples/simulator_1_2 0x4c669)

0x604000001ee8 is located 24 bytes inside of 48-byte region [0x604000001ed0,0x604000001f00)
allocated by thread T0 here:                                                                                                                                                                 
    #0 0x7f2ad3a53b60 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.5 0xefb60)
    #1 0x558956241b31 in __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (/home/martin/myProg/build/bin/examples/simulator_1_2 0x58b31)
    #2 0x55895624128e in std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> >amp;, unsigned long) (/home/martin/myProg/build/bin/examples/simulator_1_2 0x5828e)
    #3 0x558956240065 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> > >(std::allocator<std::_Sp_counted_ptr_inplace<myProg::RandomSolution, std::allocator<myProg::RandomSolution>, (__gnu_cxx::_Lock_policy)2> >amp;) (/home/martin/myProg/build/bin/examples/simulator_1_2 0x57065)
    #4 0x55895623f2ac in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<myProg::RandomSolution, std::allocator<myProg::RandomSolution>>(std::_Sp_make_shared_tag, myProg::RandomSolution*, std::allocator<myProg::RandomSolution> constamp;) (/home/martin/myProg/build/bin/examples/simulator_1_2 0x562ac)
    #5 0x55895623e4d8 in std::__shared_ptr<myProg::RandomSolution, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<myProg::RandomSolution>>(std::_Sp_make_shared_tag, std::allocator<myProg::RandomSolution> constamp;) (/home/martin/myProg/build/bin/examples/simulator_1_2 0x554d8)
    #6 0x55895623cb90 in std::shared_ptr<myProg::RandomSolution>::shared_ptr<std::allocator<myProg::RandomSolution>>(std::_Sp_make_shared_tag, std::allocator<myProg::RandomSolution> constamp;) (/home/martin/myProg/build/bin/examples/simulator_1_2 0x53b90)
    #7 0x55895623ade5 in std::shared_ptr<myProg::RandomSolution> std::allocate_shared<myProg::RandomSolution, std::allocator<myProg::RandomSolution>>(std::allocator<myProg::RandomSolution> constamp;) (/home/martin/myProg/build/bin/examples/simulator_1_2 0x51de5)
    #8 0x5589562394a5 in std::shared_ptr<myProg::RandomSolution> std::make_shared<myProg::RandomSolution>() (/home/martin/myProg/build/bin/examples/simulator_1_2 0x504a5)
    #9 0x558956236538 in main /home/martin/myProg/src/examples/simulator_1_2.cpp:86
    #10 0x7f2ad31cf09a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6 0x2409a)

SUMMARY: AddressSanitizer: alloc-dealloc-mismatch (/usr/lib/x86_64-linux-gnu/libasan.so.5 0xf1118) in operator delete(void*, unsigned long)
==6515==HINT: if you don't care about these errors you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0
==6515==ABORTING
  

Строку 86 с объявлением общего указателя можно увидеть выше, а также функцию оптимизации… Итак, я не уверен, смогу ли я получить больше информации таким образом.

Комментарии:

1. Вам действительно нужно показать все строки между тем местом, где вы создаете shared_ptr и где происходит сбой вашей программы. И точно укажите, что происходит внутри любых функций, которые вы вызываете. Скорее всего, в процессе преобразования вы могли вызвать delete необработанный указатель shared_ptr. Или у вас может быть неопределенное поведение / повреждение кучи из-за переполнения буфера где-нибудь. Это очень трудно определить, основываясь на скудной информации, которую вы предоставили до сих пор.

2. @paddy Что ж, я попытался предоставить больше кода — если вам нужна дополнительная информация, я ее дополню.

3. Сообщения об ошибках пахнут как ошибка повреждения памяти, которую, как известно, трудно отследить. Вам нужно выполнить поиск доступа за пределы в части кода, не связанной с частью, которая выдает вам ошибки.

4. Я настоятельно рекомендую добавить флаг компилятора -fsanitize=address и запустить его снова

5. Кажется, что что-то перезаписывает память, которая принадлежит best_params . Моим следующим шагом было бы запустить под gdb. Сразу после best_params инициализации ставится точка останова. Когда вы доберетесь туда, установите аппаратные контрольные точки ( watch команда) для best_params себя, а также для памяти, на которую она указывает. continue затем каждый раз, когда запускается аппаратная контрольная точка, смотрите, имеет ли смысл изменять вызывающий код best_params или его общий блок.