Introduce copy_bytes for writing into bytecode

Protects memcpy from nullptr sources, which triggers failures in GCC's
UB sanitizer.
This commit is contained in:
Justin Viiret 2015-11-12 15:27:11 +11:00 committed by Matthew Barr
parent cf3ddd9e88
commit 2a2576e907
5 changed files with 51 additions and 48 deletions

View File

@ -1136,16 +1136,11 @@ aligned_unique_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
gough_dfa->length = gough_size; gough_dfa->length = gough_size;
/* copy in blocks */ /* copy in blocks */
memcpy((u8 *)gough_dfa.get() + edge_prog_offset, &edge_blocks[0], copy_bytes((u8 *)gough_dfa.get() + edge_prog_offset, edge_blocks);
byte_length(edge_blocks));
if (top_prog_offset) { if (top_prog_offset) {
memcpy((u8 *)gough_dfa.get() + top_prog_offset, &top_blocks[0], copy_bytes((u8 *)gough_dfa.get() + top_prog_offset, top_blocks);
byte_length(top_blocks));
}
if (!temp_blocks.empty()) {
memcpy((u8 *)gough_dfa.get() + prog_base_offset, &temp_blocks[0],
byte_length(temp_blocks));
} }
copy_bytes((u8 *)gough_dfa.get() + prog_base_offset, temp_blocks);
return gough_dfa; return gough_dfa;
} }

View File

@ -1397,8 +1397,7 @@ struct Factory {
repeat->horizon = rsi.horizon; repeat->horizon = rsi.horizon;
repeat->packedCtrlSize = rsi.packedCtrlSize; repeat->packedCtrlSize = rsi.packedCtrlSize;
repeat->stateSize = rsi.stateSize; repeat->stateSize = rsi.stateSize;
memcpy(repeat->packedFieldSizes, rsi.packedFieldSizes.data(), copy_bytes(repeat->packedFieldSizes, rsi.packedFieldSizes);
byte_length(rsi.packedFieldSizes));
repeat->patchCount = rsi.patchCount; repeat->patchCount = rsi.patchCount;
repeat->patchSize = rsi.patchSize; repeat->patchSize = rsi.patchSize;
repeat->encodingSize = rsi.encodingSize; repeat->encodingSize = rsi.encodingSize;
@ -1413,8 +1412,7 @@ struct Factory {
// Copy in the sparse lookup table. // Copy in the sparse lookup table.
if (br.type == REPEAT_SPARSE_OPTIMAL_P) { if (br.type == REPEAT_SPARSE_OPTIMAL_P) {
assert(!rsi.table.empty()); assert(!rsi.table.empty());
memcpy(info_ptr + tableOffset, rsi.table.data(), copy_bytes(info_ptr + tableOffset, rsi.table);
byte_length(rsi.table));
} }
// Fill the tug mask. // Fill the tug mask.
@ -1702,6 +1700,7 @@ struct Factory {
for (u32 i = 0; i < num_repeats; i++) { for (u32 i = 0; i < num_repeats; i++) {
repeatOffsets[i] = offset; repeatOffsets[i] = offset;
assert(repeats[i].first);
memcpy((char *)limex + offset, repeats[i].first.get(), memcpy((char *)limex + offset, repeats[i].first.get(),
repeats[i].second); repeats[i].second);
offset += repeats[i].second; offset += repeats[i].second;
@ -1709,8 +1708,7 @@ struct Factory {
// Write repeat offset lookup table. // Write repeat offset lookup table.
assert(ISALIGNED_N((char *)limex + repeatOffsetsOffset, alignof(u32))); assert(ISALIGNED_N((char *)limex + repeatOffsetsOffset, alignof(u32)));
memcpy((char *)limex + repeatOffsetsOffset, repeatOffsets.data(), copy_bytes((char *)limex + repeatOffsetsOffset, repeatOffsets);
byte_length(repeatOffsets));
limex->repeatOffset = repeatOffsetsOffset; limex->repeatOffset = repeatOffsetsOffset;
limex->repeatCount = num_repeats; limex->repeatCount = num_repeats;
@ -1725,8 +1723,7 @@ struct Factory {
limex->exReportOffset = exceptionReportsOffset; limex->exReportOffset = exceptionReportsOffset;
assert(ISALIGNED_N((char *)limex + exceptionReportsOffset, assert(ISALIGNED_N((char *)limex + exceptionReportsOffset,
alignof(ReportID))); alignof(ReportID)));
memcpy((char *)limex + exceptionReportsOffset, reports.data(), copy_bytes((char *)limex + exceptionReportsOffset, reports);
byte_length(reports));
} }
static static

View File

@ -98,8 +98,7 @@ void fillNfa(NFA *nfa, lbr_common *c, ReportID report, const depth &repeatMin,
info->packedCtrlSize = rsi.packedCtrlSize; info->packedCtrlSize = rsi.packedCtrlSize;
info->horizon = rsi.horizon; info->horizon = rsi.horizon;
info->minPeriod = minPeriod; info->minPeriod = minPeriod;
memcpy(&info->packedFieldSizes, rsi.packedFieldSizes.data(), copy_bytes(&info->packedFieldSizes, rsi.packedFieldSizes);
byte_length(rsi.packedFieldSizes));
info->patchCount = rsi.patchCount; info->patchCount = rsi.patchCount;
info->patchSize = rsi.patchSize; info->patchSize = rsi.patchSize;
info->encodingSize = rsi.encodingSize; info->encodingSize = rsi.encodingSize;
@ -122,7 +121,7 @@ void fillNfa(NFA *nfa, lbr_common *c, ReportID report, const depth &repeatMin,
nfa->length = verify_u32(len); nfa->length = verify_u32(len);
info->length = verify_u32(sizeof(RepeatInfo) info->length = verify_u32(sizeof(RepeatInfo)
+ sizeof(u64a) * (rsi.patchSize + 1)); + sizeof(u64a) * (rsi.patchSize + 1));
memcpy(table, rsi.table.data(), byte_length(rsi.table)); copy_bytes(table, rsi.table);
} }
} }

View File

@ -2687,12 +2687,6 @@ void fillInReportInfo(RoseEngine *engine, u32 reportOffset,
sizeof(internal_report)); sizeof(internal_report));
} }
static
void populateInvDkeyTable(char *ptr, const ReportManager &rm) {
vector<ReportID> table = rm.getDkeyToReportTable();
memcpy(ptr, table.data(), byte_length(table));
}
static static
bool hasSimpleReports(const vector<Report> &reports) { bool hasSimpleReports(const vector<Report> &reports) {
auto it = find_if(reports.begin(), reports.end(), isComplexReport); auto it = find_if(reports.begin(), reports.end(), isComplexReport);
@ -4154,7 +4148,7 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
engine->ekeyCount = rm.numEkeys(); engine->ekeyCount = rm.numEkeys();
engine->dkeyCount = rm.numDkeys(); engine->dkeyCount = rm.numDkeys();
engine->invDkeyOffset = dkeyOffset; engine->invDkeyOffset = dkeyOffset;
populateInvDkeyTable(ptr + dkeyOffset, rm); copy_bytes(ptr + dkeyOffset, rm.getDkeyToReportTable());
engine->somHorizon = ssm.somPrecision(); engine->somHorizon = ssm.somPrecision();
engine->somLocationCount = ssm.numSomSlots(); engine->somLocationCount = ssm.numSomSlots();
@ -4314,33 +4308,22 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
buildLitBenefits(*this, engine.get(), base_lits_benefits_offset); buildLitBenefits(*this, engine.get(), base_lits_benefits_offset);
// Copy in other tables // Copy in other tables
memcpy(ptr + bc.engine_blob_base, bc.engine_blob.data(), copy_bytes(ptr + bc.engine_blob_base, bc.engine_blob);
byte_length(bc.engine_blob)); copy_bytes(ptr + engine->literalOffset, literalTable);
copy_bytes(ptr + engine->roleOffset, bc.roleTable);
memcpy(ptr + engine->literalOffset, literalTable.data(), copy_bytes(ptr + engine->leftOffset, leftInfoTable);
byte_length(literalTable));
memcpy(ptr + engine->roleOffset, bc.roleTable.data(),
byte_length(bc.roleTable));
copy(leftInfoTable.begin(), leftInfoTable.end(),
(LeftNfaInfo *)(ptr + engine->leftOffset));
fillLookaroundTables(ptr + lookaroundTableOffset, fillLookaroundTables(ptr + lookaroundTableOffset,
ptr + lookaroundReachOffset, bc.lookaround); ptr + lookaroundReachOffset, bc.lookaround);
fillInSomRevNfas(engine.get(), ssm, rev_nfa_table_offset, rev_nfa_offsets); fillInSomRevNfas(engine.get(), ssm, rev_nfa_table_offset, rev_nfa_offsets);
memcpy(ptr + engine->predOffset, predTable.data(), byte_length(predTable)); copy_bytes(ptr + engine->predOffset, predTable);
memcpy(ptr + engine->rootRoleOffset, rootRoleTable.data(), copy_bytes(ptr + engine->rootRoleOffset, rootRoleTable);
byte_length(rootRoleTable)); copy_bytes(ptr + engine->anchoredReportMapOffset, art);
memcpy(ptr + engine->anchoredReportMapOffset, art.data(), byte_length(art)); copy_bytes(ptr + engine->anchoredReportInverseMapOffset, arit);
memcpy(ptr + engine->anchoredReportInverseMapOffset, arit.data(), copy_bytes(ptr + engine->multidirectOffset, mdr_reports);
byte_length(arit)); copy_bytes(ptr + engine->activeLeftIterOffset, activeLeftIter);
memcpy(ptr + engine->multidirectOffset, mdr_reports.data(), copy_bytes(ptr + engine->sideOffset, sideTable);
byte_length(mdr_reports));
copy(activeLeftIter.begin(), activeLeftIter.end(),
(mmbit_sparse_iter *)(ptr + engine->activeLeftIterOffset));
memcpy(ptr + engine->sideOffset, sideTable.data(), byte_length(sideTable));
DEBUG_PRINTF("rose done %p\n", engine.get()); DEBUG_PRINTF("rose done %p\n", engine.get());
return engine; return engine;

View File

@ -33,8 +33,13 @@
#ifndef UTIL_CONTAINER_H #ifndef UTIL_CONTAINER_H
#define UTIL_CONTAINER_H #define UTIL_CONTAINER_H
#include "ue2common.h"
#include <algorithm> #include <algorithm>
#include <cassert>
#include <cstring>
#include <set> #include <set>
#include <type_traits>
#include <utility> #include <utility>
namespace ue2 { namespace ue2 {
@ -92,11 +97,35 @@ std::set<typename C::key_type> assoc_keys(const C &container) {
return keys; return keys;
} }
/**
* \brief Return the length in bytes of the given vector of (POD) objects.
*/
template<typename T> template<typename T>
typename std::vector<T>::size_type byte_length(const std::vector<T> &vec) { typename std::vector<T>::size_type byte_length(const std::vector<T> &vec) {
static_assert(std::is_pod<T>::value, "should be pod");
return vec.size() * sizeof(T); return vec.size() * sizeof(T);
} }
/**
* \brief Copy the given vector of POD objects to the given location in memory.
* It is safe to give this function an empty vector.
*/
template<typename T>
void *copy_bytes(void *dest, const std::vector<T> &vec) {
static_assert(std::is_pod<T>::value, "should be pod");
assert(dest);
// Since we're generally using this function to write into the bytecode,
// dest should be appropriately aligned for T.
assert(ISALIGNED_N(dest, alignof(T)));
if (vec.empty()) {
return dest; // Protect memcpy against null pointers.
}
assert(vec.data() != nullptr);
return std::memcpy(dest, vec.data(), byte_length(vec));
}
template<typename OrderedContainer1, typename OrderedContainer2> template<typename OrderedContainer1, typename OrderedContainer2>
bool is_subset_of(const OrderedContainer1 &small, const OrderedContainer2 &big) { bool is_subset_of(const OrderedContainer1 &small, const OrderedContainer2 &big) {
static_assert(std::is_same<typename OrderedContainer1::value_type, static_assert(std::is_same<typename OrderedContainer1::value_type,