From af080f739e5b61376bbbeefbf58fe554ea6b1508 Mon Sep 17 00:00:00 2001 From: Serge Lamikhov-Center Date: Sat, 27 Aug 2022 15:57:14 +0300 Subject: [PATCH] Use unique_ptr instead of raw pointers --- .vscode/launch.json | 3 +- elfio/elfio.hpp | 319 ++++++++++++++--------------- elfio/elfio_section.hpp | 4 +- examples/anonymizer/anonymizer.cpp | 11 +- tests/ELFIOTest.cpp | 6 + 5 files changed, 173 insertions(+), 170 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 47bcd11..ab335fe 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,8 +10,7 @@ "request": "launch", "program": "${workspaceFolder}/build/tests/ELFIOTest", "args": [ - "-r", - "short" + "--gtest_filter=ELFIOTest.load32", ], "stopAtEntry": false, "cwd": "${workspaceFolder}/build/tests", diff --git a/elfio/elfio.hpp b/elfio/elfio.hpp index 1be8e08..f80deca 100644 --- a/elfio/elfio.hpp +++ b/elfio/elfio.hpp @@ -30,6 +30,7 @@ THE SOFTWARE. #include #include #include +#include #include #include @@ -63,19 +64,18 @@ class elfio //------------------------------------------------------------------------------ elfio() noexcept : sections( this ), segments( this ) { - header = nullptr; - current_file_pos = 0; create( ELFCLASS32, ELFDATA2LSB ); } - elfio( elfio&& other ) noexcept : sections( this ), segments( this ) + elfio( elfio&& other ) noexcept + : sections( this ), segments( this ), + current_file_pos( other.current_file_pos ) { - header = std::move( other.header ); - sections_ = std::move( other.sections_ ); - segments_ = std::move( other.segments_ ); - convertor = std::move( other.convertor ); - addr_translator = std::move( other.addr_translator ); - current_file_pos = std::move( other.current_file_pos ); + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); other.header = nullptr; other.sections_.clear(); @@ -85,16 +85,15 @@ class elfio elfio& operator=( elfio&& other ) noexcept { if ( this != &other ) { - clean(); - header = std::move( other.header ); sections_ = std::move( other.sections_ ); segments_ = std::move( other.segments_ ); convertor = std::move( other.convertor ); addr_translator = std::move( other.addr_translator ); - current_file_pos = std::move( other.current_file_pos ); + current_file_pos = other.current_file_pos; - other.header = nullptr; + other.current_file_pos = 0; + other.header = nullptr; other.sections_.clear(); other.segments_.clear(); } @@ -105,15 +104,14 @@ class elfio // clang-format off elfio( const elfio& ) = delete; elfio& operator=( const elfio& ) = delete; + ~elfio() = default; // clang-format on - //------------------------------------------------------------------------------ - ~elfio() { clean(); } - //------------------------------------------------------------------------------ void create( unsigned char file_class, unsigned char encoding ) { - clean(); + sections_.clear(); + segments_.clear(); convertor.setup( encoding ); header = create_header( file_class, encoding ); create_mandatory_sections(); @@ -139,7 +137,8 @@ class elfio //------------------------------------------------------------------------------ bool load( std::istream& stream ) { - clean(); + sections_.clear(); + segments_.clear(); unsigned char e_ident[EI_NIDENT] = { 0 }; // Read ELF file signature @@ -361,45 +360,30 @@ class elfio //------------------------------------------------------------------------------ const section* find_prog_section_for_offset( Elf64_Off offset ) const { - for ( auto* sec : sections ) { + for ( const auto& sec : sections ) { if ( sec->get_type() == SHT_PROGBITS && - is_offset_in_section( offset, sec ) ) { - return sec; + is_offset_in_section( offset, sec.get() ) ) { + return sec.get(); } } return nullptr; } //------------------------------------------------------------------------------ - void clean() + std::unique_ptr create_header( unsigned char file_class, + unsigned char encoding ) { - delete header; - header = nullptr; - - for ( auto* it : sections_ ) { - delete it; - } - sections_.clear(); - - for ( auto* it : segments_ ) { - delete it; - } - segments_.clear(); - } - - //------------------------------------------------------------------------------ - elf_header* create_header( unsigned char file_class, - unsigned char encoding ) - { - elf_header* new_header = nullptr; + std::unique_ptr new_header; if ( file_class == ELFCLASS64 ) { - new_header = new elf_header_impl( &convertor, encoding, - &addr_translator ); + new_header = + std::unique_ptr( new elf_header_impl( + &convertor, encoding, &addr_translator ) ); } else if ( file_class == ELFCLASS32 ) { - new_header = new elf_header_impl( &convertor, encoding, - &addr_translator ); + new_header = + std::unique_ptr( new elf_header_impl( + &convertor, encoding, &addr_translator ) ); } else { return nullptr; @@ -492,7 +476,6 @@ class elfio sec->load( stream, static_cast( offset ) + static_cast( i ) * entry_size ); - sec->set_index( i ); // To mark that the section is not permitted to reassign address // during layout calculation sec->set_address( sec->get_address() ); @@ -548,7 +531,6 @@ class elfio for ( Elf_Half i = 0; i < num; ++i ) { segment* seg = nullptr; - unsigned char file_class = header->get_class(); if ( file_class == ELFCLASS64 ) { seg = new segment_impl( &convertor, @@ -578,7 +560,7 @@ class elfio Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); Elf64_Off segVBaseAddr = seg->get_virtual_address(); Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); - for ( auto* psec : sections ) { + for ( const auto& psec : sections ) { // SHF_ALLOC sections are matched based on the virtual address // otherwise the file offset is matched if ( ( ( psec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) @@ -606,7 +588,7 @@ class elfio //------------------------------------------------------------------------------ bool save_sections( std::ostream& stream ) { - for ( auto* sec : sections_ ) { + for ( const auto& sec : sections_ ) { std::streampos headerPosition = static_cast( header->get_sections_offset() ) + static_cast( @@ -621,7 +603,7 @@ class elfio //------------------------------------------------------------------------------ bool save_segments( std::ostream& stream ) { - for ( auto* seg : segments_ ) { + for ( const auto& seg : segments_ ) { std::streampos headerPosition = static_cast( header->get_segments_offset() ) + static_cast( @@ -639,7 +621,7 @@ class elfio bool found = false; for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { - for ( unsigned int k = 0; + for ( Elf_Half k = 0; !found && ( k < segments[j]->get_sections_num() ); ++k ) { found = segments[j]->get_section_index_at( k ) == section_index; } @@ -649,7 +631,7 @@ class elfio } //------------------------------------------------------------------------------ - static bool is_subsequence_of( segment* seg1, segment* seg2 ) + static bool is_subsequence_of( const segment* seg1, const segment* seg2 ) { // Return 'true' if sections of seg1 are a subset of sections in seg2 const std::vector& sections1 = seg1->get_sections(); @@ -671,8 +653,9 @@ class elfio std::deque worklist; res.reserve( segments.size() ); - std::copy( segments_.begin(), segments_.end(), - std::back_inserter( worklist ) ); + for ( const auto& seg : segments ) { + worklist.emplace_back( seg.get() ); + } // Bring the segments which start at address 0 to the front size_t nextSlot = 0; @@ -714,7 +697,7 @@ class elfio { for ( unsigned int i = 0; i < sections_.size(); ++i ) { if ( is_section_without_segment( i ) ) { - section* sec = sections_[i]; + const auto& sec = sections_[i]; Elf_Xword section_align = sec->get_addr_align(); if ( section_align > 1 && @@ -740,9 +723,9 @@ class elfio //------------------------------------------------------------------------------ void calc_segment_alignment() { - for ( auto* seg : segments_ ) { - for ( int i = 0; i < seg->get_sections_num(); ++i ) { - section* sect = sections_[seg->get_section_index_at( i )]; + for ( const auto& seg : segments_ ) { + for ( Elf_Half i = 0; i < seg->get_sections_num(); ++i ) { + const auto& sect = sections_[seg->get_section_index_at( i )]; if ( sect->get_addr_align() > seg->get_align() ) { seg->set_align( sect->get_addr_align() ); } @@ -798,87 +781,9 @@ class elfio } // Write segment's data - for ( auto j = 0; j < seg->get_sections_num(); ++j ) { - Elf_Half index = seg->get_section_index_at( j ); - - section* sec = sections[index]; - - // The NULL section is always generated - if ( SHT_NULL == sec->get_type() ) { - section_generated[index] = true; - continue; - } - - Elf_Xword section_align = 0; - // Fix up the alignment - if ( !section_generated[index] && - sec->is_address_initialized() && - SHT_NOBITS != sec->get_type() && - SHT_NULL != sec->get_type() && 0 != sec->get_size() ) { - // Align the sections based on the virtual addresses - // when possible (this is what matters for execution) - Elf64_Off req_offset = - sec->get_address() - seg->get_virtual_address(); - Elf64_Off cur_offset = current_file_pos - seg_start_pos; - if ( req_offset < cur_offset ) { - // something has gone awfully wrong, abort! - // section_align would turn out negative, seeking backwards and overwriting previous data - return false; - } - section_align = req_offset - cur_offset; - } - else if ( !section_generated[index] && - !sec->is_address_initialized() ) { - // If no address has been specified then only the section - // alignment constraint has to be matched - Elf_Xword align = sec->get_addr_align(); - if ( align == 0 ) { - align = 1; - } - Elf64_Off error = current_file_pos % align; - section_align = ( align - error ) % align; - } - else if ( section_generated[index] ) { - // Alignment for already generated sections - section_align = - sec->get_offset() - seg_start_pos - segment_filesize; - } - - // Determine the segment file and memory sizes - // Special case .tbss section (NOBITS) in non TLS segment - if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) && - !( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) && - ( seg->get_type() != PT_TLS ) && - ( SHT_NOBITS == sec->get_type() ) ) ) { - segment_memory += sec->get_size() + section_align; - } - - if ( SHT_NOBITS != sec->get_type() ) { - segment_filesize += sec->get_size() + section_align; - } - - // Nothing to be done when generating nested segments - if ( section_generated[index] ) { - continue; - } - - current_file_pos += section_align; - - // Set the section addresses when missing - if ( !sec->is_address_initialized() ) { - sec->set_address( seg->get_virtual_address() + - current_file_pos - seg_start_pos ); - } - - if ( 0 != sec->get_index() ) { - sec->set_offset( current_file_pos ); - } - - if ( SHT_NOBITS != sec->get_type() ) { - current_file_pos += sec->get_size(); - } - - section_generated[index] = true; + if ( !write_segment_data( seg, section_generated, segment_memory, + segment_filesize, seg_start_pos ) ) { + return false; } seg->set_file_size( segment_filesize ); @@ -907,6 +812,98 @@ class elfio return true; } + //------------------------------------------------------------------------------ + bool write_segment_data( const segment* seg, + std::vector& section_generated, + Elf_Xword& segment_memory, + Elf_Xword& segment_filesize, + const Elf_Xword& seg_start_pos ) + { + for ( Elf_Half j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[index]; + + // The NULL section is always generated + if ( SHT_NULL == sec->get_type() ) { + section_generated[index] = true; + continue; + } + + Elf_Xword section_align = 0; + // Fix up the alignment + if ( !section_generated[index] && sec->is_address_initialized() && + SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() && + 0 != sec->get_size() ) { + // Align the sections based on the virtual addresses + // when possible (this is what matters for execution) + Elf64_Off req_offset = + sec->get_address() - seg->get_virtual_address(); + Elf64_Off cur_offset = current_file_pos - seg_start_pos; + if ( req_offset < cur_offset ) { + // something has gone awfully wrong, abort! + // section_align would turn out negative, seeking backwards and overwriting previous data + return false; + } + section_align = req_offset - cur_offset; + } + else if ( !section_generated[index] && + !sec->is_address_initialized() ) { + // If no address has been specified then only the section + // alignment constraint has to be matched + Elf_Xword align = sec->get_addr_align(); + if ( align == 0 ) { + align = 1; + } + Elf64_Off error = current_file_pos % align; + section_align = ( align - error ) % align; + } + else if ( section_generated[index] ) { + // Alignment for already generated sections + section_align = + sec->get_offset() - seg_start_pos - segment_filesize; + } + + // Determine the segment file and memory sizes + // Special case .tbss section (NOBITS) in non TLS segment + if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) && + !( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) && + ( seg->get_type() != PT_TLS ) && + ( SHT_NOBITS == sec->get_type() ) ) ) { + segment_memory += sec->get_size() + section_align; + } + + if ( SHT_NOBITS != sec->get_type() ) { + segment_filesize += sec->get_size() + section_align; + } + + // Nothing to be done when generating nested segments + if ( section_generated[index] ) { + continue; + } + + current_file_pos += section_align; + + // Set the section addresses when missing + if ( !sec->is_address_initialized() ) { + sec->set_address( seg->get_virtual_address() + + current_file_pos - seg_start_pos ); + } + + if ( 0 != sec->get_index() ) { + sec->set_offset( current_file_pos ); + } + + if ( SHT_NOBITS != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + + section_generated[index] = true; + } + + return true; + } + //------------------------------------------------------------------------------ public: friend class Sections; @@ -928,7 +925,7 @@ class elfio section* sec = nullptr; if ( index < parent->sections_.size() ) { - sec = parent->sections_[index]; + sec = parent->sections_[index].get(); } return sec; @@ -939,9 +936,9 @@ class elfio { section* sec = nullptr; - for ( auto* it : parent->sections_ ) { + for ( const auto& it : parent->sections_ ) { if ( it->get_name() == name ) { - sec = it; + sec = it.get(); break; } } @@ -956,7 +953,7 @@ class elfio new_section->set_name( name ); Elf_Half str_index = parent->get_section_name_str_index(); - section* string_table( parent->sections_[str_index] ); + section* string_table( parent->sections_[str_index].get() ); string_section_accessor str_writer( string_table ); Elf_Word pos = str_writer.add_string( name ); new_section->set_name_string_offset( pos ); @@ -965,25 +962,25 @@ class elfio } //------------------------------------------------------------------------------ - std::vector::iterator begin() + std::vector>::iterator begin() { return parent->sections_.begin(); } //------------------------------------------------------------------------------ - std::vector::iterator end() + std::vector>::iterator end() { return parent->sections_.end(); } //------------------------------------------------------------------------------ - std::vector::const_iterator begin() const + std::vector>::const_iterator begin() const { return parent->sections_.cbegin(); } //------------------------------------------------------------------------------ - std::vector::const_iterator end() const + std::vector>::const_iterator end() const { return parent->sections_.cend(); } @@ -991,7 +988,8 @@ class elfio //------------------------------------------------------------------------------ private: elfio* parent; - } sections; + }; + Sections sections; //------------------------------------------------------------------------------ friend class Segments; @@ -1010,32 +1008,32 @@ class elfio //------------------------------------------------------------------------------ segment* operator[]( unsigned int index ) const { - return parent->segments_[index]; + return parent->segments_[index].get(); } //------------------------------------------------------------------------------ segment* add() { return parent->create_segment(); } //------------------------------------------------------------------------------ - std::vector::iterator begin() + std::vector>::iterator begin() { return parent->segments_.begin(); } //------------------------------------------------------------------------------ - std::vector::iterator end() + std::vector>::iterator end() { return parent->segments_.end(); } //------------------------------------------------------------------------------ - std::vector::const_iterator begin() const + std::vector>::const_iterator begin() const { return parent->segments_.cbegin(); } //------------------------------------------------------------------------------ - std::vector::const_iterator end() const + std::vector>::const_iterator end() const { return parent->segments_.cend(); } @@ -1043,17 +1041,18 @@ class elfio //------------------------------------------------------------------------------ private: elfio* parent; - } segments; + }; + Segments segments; //------------------------------------------------------------------------------ private: - elf_header* header; - std::vector sections_; - std::vector segments_; - endianess_convertor convertor; - address_translator addr_translator; + std::unique_ptr header = nullptr; + std::vector> sections_; + std::vector> segments_; + endianess_convertor convertor; + address_translator addr_translator; - Elf_Xword current_file_pos; + Elf_Xword current_file_pos = 0; }; } // namespace ELFIO diff --git a/elfio/elfio_section.hpp b/elfio/elfio_section.hpp index 397500e..a653356 100644 --- a/elfio/elfio_section.hpp +++ b/elfio/elfio_section.hpp @@ -108,7 +108,7 @@ template class section_impl : public section std::string get_name() const override { return name; } //------------------------------------------------------------------------------ - void set_name( std::string name ) override { this->name = name; } + void set_name( std::string name_prm ) override { this->name = name_prm; } //------------------------------------------------------------------------------ void set_address( Elf64_Addr value ) override @@ -207,7 +207,7 @@ template class section_impl : public section '\0' ); if ( translator->empty() ) { - stream.seekg( 0, stream.end ); + stream.seekg( 0, std::istream::end ); set_stream_size( size_t( stream.tellg() ) ); } else { diff --git a/examples/anonymizer/anonymizer.cpp b/examples/anonymizer/anonymizer.cpp index 24e95a5..09f3635 100644 --- a/examples/anonymizer/anonymizer.cpp +++ b/examples/anonymizer/anonymizer.cpp @@ -51,7 +51,7 @@ using namespace ELFIO; void overwrite_data( const std::string& filename, Elf64_Off offset, - std::string& str ) + const std::string& str ) { std::ofstream file( filename, std::ios::in | std::ios::out | std::ios::binary ); @@ -92,12 +92,11 @@ int main( int argc, char** argv ) return 1; } - for ( auto section = reader.sections.begin(); - section != reader.sections.end(); ++section ) { - if ( ( *section )->get_type() == SHT_STRTAB && - std::string( ( *section )->get_name() ) == + for ( const auto& section : reader.sections ) { + if ( section->get_type() == SHT_STRTAB && + std::string( section->get_name() ) == std::string( ".strtab" ) ) { - process_string_table( *section, filename ); + process_string_table( section.get(), filename ); } } return 0; diff --git a/tests/ELFIOTest.cpp b/tests/ELFIOTest.cpp index 1ae037a..89aec65 100644 --- a/tests/ELFIOTest.cpp +++ b/tests/ELFIOTest.cpp @@ -224,6 +224,12 @@ TEST( ELFIOTest, load32 ) sec = reader.sections[27]; checkSection( sec, 27, ".strtab", SHT_STRTAB, 0, 0x0, 0x259, 0, 0, 1, 0 ); + for ( Elf_Half i = 0; i < reader.sections.size(); ++i ) + { + sec = reader.sections[i]; + EXPECT_EQ( sec->get_index(), i ); + } + const section* sec1 = reader.sections[".strtab"]; EXPECT_EQ( sec->get_index(), sec1->get_index() );