EXPORT_C void exception_safety_tester::report_error() { activity_guard ag( m_internal_activity ); unit_test_log << unit_test::log::begin( m_execution_path.back().m_file_name, m_execution_path.back().m_line_num ) << log_all_errors; wrap_stringstream formatter; if( m_invairant_failed ) formatter << "Failed invariant"; if( m_memory_in_use.size() != 0 ) { if( m_invairant_failed ) formatter << " and "; formatter << m_memory_in_use.size() << " memory leak"; if( m_memory_in_use.size() > 1 ) formatter << 's'; } formatter << " detected in the execution path " << m_exec_path_counter << ":\n"; format_execution_path( formatter, m_execution_path.begin(), m_execution_path.end() ); unit_test_log << const_string( formatter.str() ) << unit_test::log::end(); }
u32 get_integer(const registry& psf, const std::string& key, u32 def) { const auto found = psf.find(key); if (found == psf.end() || found->second.type() != format::integer) { return def; } return found->second.as_integer(); }
std::string get_string(const registry& psf, const std::string& key, const std::string& def) { const auto found = psf.find(key); if (found == psf.end() || (found->second.type() != format::string && found->second.type() != format::array)) { return def; } return found->second.as_string(); }
EXPORT_C void exception_safety_tester::freed( void* p ) { if( m_internal_activity ) return; activity_guard ag( m_internal_activity ); registry::iterator it = m_memory_in_use.find( p ); if( it != m_memory_in_use.end() ) { m_execution_path[it->second].m_alloc.ptr = 0; m_memory_in_use.erase( it ); } }
EXPORT_C bool exception_safety_tester::next_execution_path() { activity_guard ag( m_internal_activity ); // check memory usage if( m_execution_path.size() > 0 ) { bool errors_detected = m_invairant_failed || (m_memory_in_use.size() != 0); framework::assertion_result( !errors_detected ); if( errors_detected ) report_error(); m_memory_in_use.clear(); } m_exec_path_point = 0; m_exception_point_counter = 0; m_invairant_failed = false; ++m_exec_path_counter; while( m_execution_path.size() > 0 ) { switch( m_execution_path.back().m_type ) { case EPP_SCOPE: case EPP_ALLOC: m_execution_path.pop_back(); break; case EPP_DECISION: if( !m_execution_path.back().m_decision.value ) { m_execution_path.pop_back(); break; } m_execution_path.back().m_decision.value = false; m_forced_exception_point = m_execution_path.back().m_decision.forced_exception_point; return true; case EPP_EXCEPT: m_execution_path.pop_back(); ++m_forced_exception_point; return true; } } BOOST_TEST_MESSAGE( "Total tested " << --m_exec_path_counter << " execution path" ); return false; }
EXPORT_C void exception_safety_tester::allocated( const_string file, std::size_t line_num, void* p, std::size_t s ) { if( m_internal_activity ) return; activity_guard ag( m_internal_activity ); if( m_exec_path_point < m_execution_path.size() ) BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_ALLOC, "Function under test exibit non-deterministic behavior" ); else m_execution_path.push_back( execution_path_point( EPP_ALLOC, file, line_num ) ); m_execution_path[m_exec_path_point].m_alloc.ptr = p; m_execution_path[m_exec_path_point].m_alloc.size = s; m_memory_in_use.insert( std::make_pair( p, m_exec_path_point++ ) ); }
std::vector<char> save_object(const registry& psf) { std::vector<def_table_t> indices; indices.reserve(psf.size()); // Generate indices and calculate key table length std::size_t key_offset = 0, data_offset = 0; for (const auto& entry : psf) { def_table_t index; index.key_off = gsl::narrow<u32>(key_offset); index.param_fmt = entry.second.type(); index.param_len = entry.second.size(); index.param_max = entry.second.max(); index.data_off = gsl::narrow<u32>(data_offset); // Update offsets: key_offset += gsl::narrow<u32>(entry.first.size() + 1); // key size data_offset += index.param_max; indices.push_back(index); } // Align next section (data) offset key_offset = ::align(key_offset, 4); // Generate header header_t header; header.magic = "\0PSF"_u32; header.version = 0x101; header.off_key_table = gsl::narrow<u32>(sizeof(header_t) + sizeof(def_table_t) * psf.size()); header.off_data_table = gsl::narrow<u32>(header.off_key_table + key_offset); header.entries_num = gsl::narrow<u32>(psf.size()); // Save header and indices std::vector<char> result; result.reserve(header.off_data_table + data_offset); result.insert(result.end(), (char*)&header, (char*)&header + sizeof(header_t)); result.insert(result.end(), (char*)indices.data(), (char*)indices.data() + sizeof(def_table_t) * psf.size()); // Save key table for (const auto& entry : psf) { result.insert(result.end(), entry.first.begin(), entry.first.end()); result.push_back('\0'); } // Insert zero padding result.insert(result.end(), header.off_data_table - result.size(), '\0'); // Save data for (const auto& entry : psf) { const auto fmt = entry.second.type(); const u32 max = entry.second.max(); if (fmt == format::integer && max == sizeof(u32)) { const le_t<u32> value = entry.second.as_integer(); result.insert(result.end(), (char*)&value, (char*)&value + sizeof(u32)); } else if (fmt == format::string || fmt == format::array) { const std::string& value = entry.second.as_string(); const std::size_t size = std::min<std::size_t>(max, value.size()); if (value.size() + (fmt == format::string) > max) { // TODO: check real limitations of PSF format log.error("Entry value shrinkage (key='%s', value='%s', size=0x%zx, max=0x%x)", entry.first, value, size, max); } result.insert(result.end(), value.begin(), value.begin() + size); result.insert(result.end(), max - size, '\0'); // Write zeros up to max_size } else { throw EXCEPTION("Invalid entry format (key='%s', fmt=0x%x)", entry.first, fmt); } } return result; }
void register_float_ops( registry &r ) { r.add( op( "d.castto", [](float v) -> double { return static_cast<double>( v ); }, op::simple ) ); r.add( op( "d.castfrom", [](double v) -> float { return static_cast<float>( v ); }, op::simple ) ); r.add( op( "f.negate", [](float v) -> float { return -v; }, op::simple ) ); r.add( op( "d.negate", [](double v) -> double { return -v; }, op::simple ) ); r.add( op( "f.add", [](float a, float b) -> float { return a + b; }, op::simple ) ); r.add( op( "d.add", [](double a, double b) -> double { return a + b; }, op::simple ) ); r.add( op( "f.sub", [](float a, float b) -> float { return a - b; }, op::simple ) ); r.add( op( "d.sub", [](double a, double b) -> double { return a - b; }, op::simple ) ); r.add( op( "f.mul", [](float a, float b) -> float { return a * b; }, op::simple ) ); r.add( op( "d.mul", [](double a, double b) -> double { return a * b; }, op::simple ) ); r.add( op( "f.div", [](float a, float b) -> float { return a / b; }, op::simple ) ); r.add( op( "d.div", [](double a, double b) -> double { return a / b; }, op::simple ) ); }