Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use gsl::narrow in asm files #710

Merged
merged 5 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
elazarg marked this conversation as resolved.
Show resolved Hide resolved
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);
elazarg marked this conversation as resolved.
Show resolved Hide resolved

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;
elazarg marked this conversation as resolved.
Show resolved Hide resolved
};
}

// 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
elazarg marked this conversation as resolved.
Show resolved Hide resolved
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}},
elazarg marked this conversation as resolved.
Show resolved Hide resolved
.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,
elazarg marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Loading