Skip to content

Commit

Permalink
use gsl::narrow in asm files (#710)
Browse files Browse the repository at this point in the history
* gsl::narrow in asm_files.cpp, asm_unmarshal.cpp, asm_ostream.hpp, ebpf_yaml.cpp and test_marshal.cpp
---------
Signed-off-by: Elazar Gershuni <[email protected]>
  • Loading branch information
elazarg authored Oct 1, 2024
1 parent 1ef02eb commit 6d84933
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 54 deletions.
15 changes: 8 additions & 7 deletions src/asm_files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "libbtf/btf_parse.h"

#include "asm_files.hpp"
#include "crab_utils/num_safety.hpp"
#include "platform.hpp"

using std::string;
Expand All @@ -33,11 +34,11 @@ static vector<T> vector_of(const ELFIO::section& sec) {
}

int create_map_crab(const EbpfMapType& map_type, uint32_t key_size, uint32_t value_size, uint32_t max_entries,
ebpf_verifier_options_t options) {
ebpf_verifier_options_t) {
const EquivalenceKey equiv{map_type.value_type, key_size, value_size, map_type.is_array ? max_entries : 0};
if (!global_program_info->cache.contains(equiv)) {
// +1 so 0 is the null FD
global_program_info->cache[equiv] = static_cast<int>(global_program_info->cache.size()) + 1;
global_program_info->cache[equiv] = gsl::narrow<int>(global_program_info->cache.size()) + 1;
}
return global_program_info->cache.at(equiv);
}
Expand Down Expand Up @@ -249,13 +250,13 @@ static void append_subprograms(raw_program& prog, const vector<raw_program>& pro
}

// Fill in the PC offset into the imm field of the CallLocal instruction.
const ELFIO::Elf_Xword target_offset = subprogram_offsets[reloc.target_function_name];
const auto offset_diff = static_cast<int64_t>(target_offset - reloc.source_offset - 1);
const int64_t target_offset = gsl::narrow_cast<int64_t>(subprogram_offsets[reloc.target_function_name]);
const auto offset_diff = target_offset - gsl::narrow<int64_t>(reloc.source_offset) - 1;
if (offset_diff < std::numeric_limits<int32_t>::min() || offset_diff > std::numeric_limits<int32_t>::max()) {
throw std::runtime_error("Offset difference out of int32_t range for instruction at source offset " +
std::to_string(reloc.source_offset));
}
prog.prog[reloc.source_offset].imm = static_cast<int32_t>(offset_diff);
prog.prog[reloc.source_offset].imm = gsl::narrow_cast<int32_t>(offset_diff);
}
}

Expand All @@ -265,7 +266,7 @@ std::map<std::string, size_t> parse_map_section(const libbtf::btf_type_data& btf
for (auto& map : parse_btf_map_section(btf_data)) {
map_offsets.emplace(map.name, map_descriptors.size());
map_descriptors.push_back({
.original_fd = static_cast<int>(map.type_id),
.original_fd = gsl::narrow_cast<int>(map.type_id),
.type = map.map_type,
.key_size = map.key_size,
.value_size = map.value_size,
Expand Down Expand Up @@ -379,7 +380,7 @@ vector<raw_program> read_elf(std::istream& input_stream, const std::string& path
auto [program_name, program_size] = get_program_name_and_size(*section, program_offset, symbols);
raw_program prog{path,
name,
static_cast<uint32_t>(program_offset),
gsl::narrow_cast<uint32_t>(program_offset),
program_name,
vector_of<ebpf_inst>(section_data + program_offset, program_size),
info};
Expand Down
7 changes: 4 additions & 3 deletions src/asm_files.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
#include "platform.hpp"

std::vector<raw_program> read_raw(std::string path, program_info info);
std::vector<raw_program> read_elf(const std::string& path, const std::string& section,
const ebpf_verifier_options_t* options, const ebpf_platform_t* platform);
std::vector<raw_program> read_elf(std::istream& input_stream, const std::string& path, const std::string& section,
std::vector<raw_program> read_elf(const std::string& path, const std::string& desired_section,
const ebpf_verifier_options_t* options, const ebpf_platform_t* platform);
std::vector<raw_program> read_elf(std::istream& input_stream, const std::string& path,
const std::string& desired_section, const ebpf_verifier_options_t* options,
const ebpf_platform_t* platform);

void write_binary_file(std::string path, const char* data, size_t size);

Expand Down
51 changes: 26 additions & 25 deletions src/asm_ostream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,26 @@
#include <boost/lexical_cast.hpp>

#include "asm_syntax.hpp"
#include "crab_utils/num_safety.hpp"

// We use a 16-bit offset whenever it fits in 16 bits.
inline std::function<int16_t(label_t)> label_to_offset16(pc_t pc) {
return [=](const label_t& label) {
const int64_t offset = label.from - static_cast<int64_t>(pc) - 1;
return std::numeric_limits<int16_t>::min() <= offset && offset <= std::numeric_limits<int16_t>::max()
? static_cast<int16_t>(offset)
: 0;
const int64_t offset = label.from - gsl::narrow<int64_t>(pc) - 1;
const bool is16 =
std::numeric_limits<int16_t>::min() <= offset && offset <= std::numeric_limits<int16_t>::max();
return is16 ? gsl::narrow<int16_t>(offset) : 0;
};
}

// We use the JA32 opcode with the offset in 'imm' when the offset
// of an unconditional jump doesn't fit in a int16_t.
inline std::function<int32_t(label_t)> label_to_offset32(const pc_t pc) {
return [=](const label_t& label) {
int64_t offset = label.from - static_cast<int64_t>(pc) - 1;
return (offset >= INT16_MIN && offset <= INT16_MAX) ? 0 : static_cast<int32_t>(offset);
const int64_t offset = label.from - gsl::narrow<int64_t>(pc) - 1;
const bool is16 =
std::numeric_limits<int16_t>::min() <= offset && offset <= std::numeric_limits<int16_t>::max();
return is16 ? 0 : gsl::narrow<int32_t>(offset);
};
}

Expand All @@ -42,30 +45,28 @@ std::string to_string(Instruction const& ins);
std::ostream& operator<<(std::ostream& os, Bin::Op op);
std::ostream& operator<<(std::ostream& os, Condition::Op op);

inline std::ostream& operator<<(std::ostream& os, const Imm imm) { return os << static_cast<int64_t>(imm.v); }
inline std::ostream& operator<<(std::ostream& os, Reg const& a) { return os << "r" << static_cast<int>(a.v); }
inline std::ostream& operator<<(std::ostream& os, const Imm imm) { return os << crab::to_signed(imm.v); }
inline std::ostream& operator<<(std::ostream& os, Reg const& a) { return os << "r" << gsl::narrow<int>(a.v); }
inline std::ostream& operator<<(std::ostream& os, Value const& a) {
if (auto pa = std::get_if<Imm>(&a)) {
if (const auto pa = std::get_if<Imm>(&a)) {
return os << *pa;
}
return os << std::get<Reg>(a);
}

inline std::ostream& operator<<(std::ostream& os, Undefined const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, LoadMapFd const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Bin const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Un const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Call const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Callx const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Exit const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Jmp const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Packet const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Mem const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Atomic const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Assume const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, Assert const& a) { return os << static_cast<Instruction>(a); }
inline std::ostream& operator<<(std::ostream& os, IncrementLoopCounter const& a) {
return os << static_cast<Instruction>(a);
}
inline std::ostream& operator<<(std::ostream& os, Undefined const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, LoadMapFd const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Bin const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Un const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Call const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Callx const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Exit const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Jmp const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Packet const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Mem const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Atomic const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Assume const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, Assert const& a) { return os << Instruction{a}; }
inline std::ostream& operator<<(std::ostream& os, IncrementLoopCounter const& a) { return os << Instruction{a}; }
std::ostream& operator<<(std::ostream& os, AssertionConstraint const& a);
std::string to_string(AssertionConstraint const& constraint);
35 changes: 19 additions & 16 deletions src/asm_unmarshal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vector>

#include "asm_unmarshal.hpp"
#include "crab_utils/num_safety.hpp"
#include "ebpf_vm_isa.hpp"

using std::string;
Expand Down Expand Up @@ -84,7 +85,9 @@ static Instruction shift32(const Reg dst, const Bin::Op op) {
struct Unmarshaller {
vector<vector<string>>& notes;
const program_info& info;
// ReSharper disable once CppMemberFunctionMayBeConst
void note(const string& what) { notes.back().emplace_back(what); }
// ReSharper disable once CppMemberFunctionMayBeConst
void note_next_pc() { notes.emplace_back(); }
explicit Unmarshaller(vector<vector<string>>& notes, const program_info& info) : notes{notes}, info{info} {
note_next_pc();
Expand Down Expand Up @@ -216,7 +219,7 @@ struct Unmarshaller {
}

static auto getAtomicOp(const size_t pc, const ebpf_inst inst) -> Atomic::Op {
switch (const auto op = static_cast<Atomic::Op>(inst.imm & ~INST_FETCH)) {
switch (const auto op = gsl::narrow<Atomic::Op>(inst.imm & ~INST_FETCH)) {
case Atomic::Op::XCHG:
case Atomic::Op::CMPXCHG:
if ((inst.imm & INST_FETCH) == 0) {
Expand All @@ -230,9 +233,9 @@ struct Unmarshaller {
throw InvalidInstruction(pc, "unsupported immediate");
}

static uint64_t sign_extend(const int32_t imm) { return static_cast<uint64_t>(static_cast<int64_t>(imm)); }
static uint64_t sign_extend(const int32_t imm) { return crab::to_unsigned(int64_t{imm}); }

static uint64_t zero_extend(const int32_t imm) { return static_cast<uint64_t>(static_cast<uint32_t>(imm)); }
static uint64_t zero_extend(const int32_t imm) { return uint64_t{crab::to_unsigned(imm)}; }

static auto getBinValue(const pc_t pc, const ebpf_inst inst) -> Value {
if (inst.opcode & INST_SRC_REG) {
Expand Down Expand Up @@ -345,9 +348,9 @@ struct Unmarshaller {
.basereg = Reg{basereg},
.offset = inst.offset,
},
.value = isLoad ? static_cast<Value>(Reg{inst.dst})
: (isImm ? static_cast<Value>(Imm{zero_extend(inst.imm)})
: static_cast<Value>(Reg{inst.src})),
.value = isLoad ? Value{Reg{inst.dst}}
: isImm ? Value{Imm{zero_extend(inst.imm)}}
: Value{Reg{inst.src}},
.is_load = isLoad,
};
return res;
Expand Down Expand Up @@ -502,7 +505,7 @@ struct Unmarshaller {
case EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY:
case EBPF_ARGUMENT_TYPE_PTR_TO_MAP_VALUE:
case EBPF_ARGUMENT_TYPE_PTR_TO_CTX:
res.singles.push_back({toArgSingleKind(args[i]), Reg{static_cast<uint8_t>(i)}});
res.singles.push_back({toArgSingleKind(args[i]), Reg{gsl::narrow<uint8_t>(i)}});
break;
case EBPF_ARGUMENT_TYPE_CONST_SIZE: {
// Sanity check: This argument should never be seen in isolation.
Expand Down Expand Up @@ -535,8 +538,8 @@ struct Unmarshaller {
proto.name);
}
const bool can_be_zero = (args[i + 1] == EBPF_ARGUMENT_TYPE_CONST_SIZE_OR_ZERO);
res.pairs.push_back({toArgPairKind(args[i]), Reg{static_cast<uint8_t>(i)},
Reg{static_cast<uint8_t>(i + 1)}, can_be_zero});
res.pairs.push_back({toArgPairKind(args[i]), Reg{gsl::narrow<uint8_t>(i)},
Reg{gsl::narrow<uint8_t>(i + 1)}, can_be_zero});
i++;
break;
}
Expand All @@ -553,7 +556,7 @@ struct Unmarshaller {
if (insts[new_pc].opcode == 0) {
throw InvalidInstruction(pc, "jump to middle of lddw");
}
return label_t{static_cast<int>(new_pc)};
return label_t{gsl::narrow<int>(new_pc)};
}

static auto makeCallLocal(const ebpf_inst inst, const vector<ebpf_inst>& insts, const pc_t pc) -> CallLocal {
Expand All @@ -579,7 +582,7 @@ struct Unmarshaller {
if (inst.imm < 0 || inst.imm > R10_STACK_POINTER) {
throw InvalidInstruction(pc, "bad register");
}
return Callx{static_cast<uint8_t>(inst.imm)};
return Callx{gsl::narrow<uint8_t>(inst.imm)};
}
return Callx{inst.dst};
}
Expand Down Expand Up @@ -685,9 +688,9 @@ struct Unmarshaller {
? std::optional<Condition>{}
: Condition{.op = op,
.left = Reg{inst.dst},
.right = (inst.opcode & INST_SRC_REG) ? static_cast<Value>(Reg{inst.src})
: Imm{sign_extend(inst.imm)},
.is64 = ((inst.opcode & INST_CLS_MASK) == INST_CLS_JMP)};
.right = (inst.opcode & INST_SRC_REG) ? Value{Reg{inst.src}}
: Value{Imm{sign_extend(inst.imm)}},
.is64 = (inst.opcode & INST_CLS_MASK) == INST_CLS_JMP};
return Jmp{.cond = cond, .target = target};
}
}
Expand All @@ -708,7 +711,7 @@ struct Unmarshaller {
case INST_CLS_LD:
if (inst.opcode == INST_OP_LDDW_IMM) {
const int32_t next_imm = pc < insts.size() - 1 ? insts[pc + 1].imm : 0;
new_ins = makeLddw(inst, next_imm, insts, static_cast<pc_t>(pc));
new_ins = makeLddw(inst, next_imm, insts, pc);
skip_instruction = true;
break;
}
Expand Down Expand Up @@ -774,7 +777,7 @@ struct Unmarshaller {
current_line_info = line_info[pc];
}

prog.emplace_back(label_t(static_cast<int>(pc)), new_ins, current_line_info);
prog.emplace_back(label_t(gsl::narrow<int>(pc)), new_ins, current_line_info);

pc++;
note_next_pc();
Expand Down
4 changes: 2 additions & 2 deletions src/ebpf_yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ static InstructionSeq raw_cfg_to_instruction_seq(const vector<std::tuple<string,
for (const auto& [label_name, raw_block] : raw_blocks) {
label_name_to_label.emplace(label_name, label_index);
// don't count large instructions as 2
label_index += static_cast<int>(raw_block.size());
label_index += gsl::narrow<int>(raw_block.size());
}

InstructionSeq res;
Expand Down Expand Up @@ -296,7 +296,7 @@ string_invariant stack_contents_invariant(const std::vector<uint8_t>& memory_byt
"s[" + std::to_string(EBPF_STACK_SIZE - memory_bytes.size()) + "..." +
std::to_string(EBPF_STACK_SIZE - 1) + "].type=number"};

int offset = EBPF_STACK_SIZE - static_cast<int>(memory_bytes.size());
int offset = EBPF_STACK_SIZE - gsl::narrow<int>(memory_bytes.size());
if (offset % 2 != 0) {
add_stack_variable<int8_t>(more, offset, memory_bytes);
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/test_marshal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ TEST_CASE("marshal", "[disasm][marshal]") {
Mem m{.access = access, .value = Reg{3}, .is_load = true};
auto ins = marshal(m, 0).at(0);
ebpf_inst expect{
.opcode = static_cast<uint8_t>(INST_CLS_LD | INST_MODE_MEM | width_to_opcode(1) | 0x1),
.opcode = gsl::narrow<uint8_t>(INST_CLS_LD | INST_MODE_MEM | width_to_opcode(1) | 0x1),
.dst = 3,
.src = 4,
.offset = 6,
Expand Down

0 comments on commit 6d84933

Please sign in to comment.