Skip to content

Commit 5178cce

Browse files
Implementing hook_BYTES_updateMInt codegen with support to MInt{256} and MInt{64}
Implementing `hook_BYTES_update256` in LLVM IR Implementing `hook_BYTES_update64` in bytes.cpp Adding `bytes-update` unit test
1 parent 6535b5c commit 5178cce

File tree

7 files changed

+3203
-4
lines changed

7 files changed

+3203
-4
lines changed

config/llvm_header.inc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ declare void @error_on_start_substr(i64, i64)
8888
declare void @error_on_end_substr(ptr, i64)
8989
declare void @interger_overflow(i64)
9090
declare void @buffer_overflow_replace_at(i64, i64, i64)
91+
declare void @buffer_overflow_update(i64, i64)
92+
declare void @error_on_update(i64)
9193
declare i1 @hook_BYTES_mutableBytesEnabled()
9294
9395
define ptr @copy_if_needed_in_llvm(ptr %b) {
@@ -522,6 +524,43 @@ entry:
522524
ret i256 %result
523525
}
524526
527+
define ptr @hook_BYTES_update256(ptr %b, i256 %index, i256 %value) {
528+
entry:
529+
call ptr @copy_if_needed_in_llvm(ptr %b)
530+
531+
%hdr = load i64, ptr %b
532+
%len = and i64 %hdr, 1099511627775 ; @LENGTH_MASK@
533+
%len_256 = zext i64 %len to i256
534+
535+
%index_uge_len = icmp uge i256 %index, %len_256
536+
br i1 %index_uge_len, label %error, label %update_value
537+
538+
error:
539+
%index_trunc = trunc i256 %index to i64
540+
%len_trunc = trunc i256 %len_256 to i64
541+
call void @buffer_overflow_update(i64 %index_trunc, i64 %len_trunc)
542+
unreachable
543+
544+
update_value:
545+
%value_ge_255 = icmp ugt i256 %value, 255
546+
br i1 %value_ge_255, label %error_value, label %set_value
547+
548+
error_value:
549+
%value_trunc = trunc i256 %value to i64
550+
call void @error_on_update(i64 %value_trunc)
551+
unreachable
552+
553+
set_value:
554+
%data_ptr = getelementptr i8, ptr %b, i64 8
555+
%index_i64 = trunc i256 %index to i64
556+
%byte_ptr = getelementptr i8, ptr %data_ptr, i64 %index_i64
557+
%value_i8 = trunc i256 %value to i8
558+
store i8 %value_i8, ptr %byte_ptr
559+
560+
; Return the modified buffer
561+
ret ptr %b
562+
}
563+
525564
526565
define i256 @hook_MINT_pow256(i256 %base, i256 %exp) {
527566
entry:

lib/codegen/CreateTerm.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,47 @@ llvm::Value *create_term::create_hardcoded_hook(
446446
current_block_ = merge_block;
447447
return phi;
448448
}
449+
if (name == "BYTES.updateMInt") {
450+
assert(pattern->get_arguments().size() == 3);
451+
llvm::Value *bytes = alloc_arg(pattern, 0, location_stack);
452+
args.push_back(bytes);
453+
llvm::Value *index = alloc_arg(pattern, 1, location_stack);
454+
args.push_back(index);
455+
llvm::Value *value = alloc_arg(pattern, 2, location_stack);
456+
args.push_back(value);
457+
auto *index_type = llvm::dyn_cast<llvm::IntegerType>(index->getType());
458+
auto *value_type = llvm::dyn_cast<llvm::IntegerType>(value->getType());
459+
if (!index_type || !value_type) {
460+
throw std::invalid_argument("BYTES.updateMInt: index and/or value "
461+
"argument is not a machine integer type");
462+
}
463+
unsigned index_bits = index_type->getBitWidth();
464+
llvm::CallInst *result = nullptr;
465+
switch (index_bits) {
466+
case 64: {
467+
result = llvm::CallInst::Create(
468+
get_or_insert_function(
469+
module_, "hook_BYTES_update64", ptr_ty, bytes->getType(),
470+
index_type, value_type),
471+
{bytes, index, value}, "hook_BYTES_update64", current_block_);
472+
break;
473+
}
474+
case 256: {
475+
result = llvm::CallInst::Create(
476+
get_or_insert_function(
477+
module_, "hook_BYTES_update256", ptr_ty, bytes->getType(),
478+
index_type, value_type),
479+
{bytes, index, value}, "hook_BYTES_update256", current_block_);
480+
break;
481+
}
482+
default: {
483+
throw std::invalid_argument(
484+
fmt::format("BYTES.updateMInt: unsupported size {}", index_bits));
485+
}
486+
}
487+
set_debug_loc(result);
488+
return result;
489+
}
449490
if (name == "BYTES.replaceAtMInt") {
450491
llvm::Value *bytes = alloc_arg(pattern, 0, location_stack);
451492
args.push_back(bytes);

runtime/strings/bytes.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ void buffer_overflow_replace_at(
7474
dest_len, src_len);
7575
}
7676

77+
void buffer_overflow_update(uint64_t len, uint64_t off) {
78+
KLLVM_HOOK_INVALID_ARGUMENT(
79+
"Buffer overflow on update: off={}, len={}", off, len);
80+
}
81+
82+
void error_on_update(uint64_t val) {
83+
KLLVM_HOOK_INVALID_ARGUMENT(
84+
"Not a valid value for a byte in update: {}", val);
85+
}
7786

7887
// syntax Int ::= Bytes2Int(Bytes, Endianness, Signedness)
7988
SortInt hook_BYTES_bytes2int(
@@ -205,19 +214,31 @@ uint64_t hook_BYTES_get64(SortBytes b, uint64_t off) {
205214
return (unsigned char)b->data[off];
206215
}
207216

217+
SortBytes hook_BYTES_update64(SortBytes b, uint64_t off, uint64_t val) {
218+
copy_if_needed(b);
219+
220+
if (off >= len(b)) {
221+
KLLVM_HOOK_INVALID_ARGUMENT(
222+
"Buffer overflow on update: off={}, len={}", off, len(b));
223+
}
224+
if (val >= 256) {
225+
KLLVM_HOOK_INVALID_ARGUMENT(
226+
"Not a valid value for a byte in update: {}", val);
227+
}
228+
b->data[off] = (unsigned char)val;
229+
return b;
230+
}
208231

209232
SortBytes hook_BYTES_update(SortBytes b, SortInt off, SortInt val) {
210233
copy_if_needed(b);
211234

212235
unsigned long off_long = GET_UI(off);
213236
if (off_long >= len(b)) {
214-
KLLVM_HOOK_INVALID_ARGUMENT(
215-
"Buffer overflow on update: off={}, len={}", off_long, len(b));
237+
buffer_overflow_update(off_long, len(b));
216238
}
217239
unsigned long val_long = GET_UI(val);
218240
if (val_long >= 256) {
219-
KLLVM_HOOK_INVALID_ARGUMENT(
220-
"Not a valid value for a byte in update: {}", val_long);
241+
error_on_update(val_long);
221242
}
222243
b->data[off_long] = (unsigned char)val_long;
223244
return b;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module BYTES-UPDATE
2+
3+
imports INT
4+
imports MINT
5+
imports BYTES
6+
imports BOOL
7+
imports K-EQUAL
8+
9+
syntax MInt{64}
10+
syntax MInt{256}
11+
12+
syntax Bytes ::= "bytesString" [macro]
13+
rule bytesString =>
14+
b"a\x00\x1b`\x00\x81`\x0b\x829\xf3`\x01`\x01Us\x8a\n\x19X\x951iBP\xd5p\x04"
15+
16+
syntax Bool ::= "testBytesUpdate" [function]
17+
rule testBytesUpdate =>
18+
bytesString[2p64 <- 10p64] ==K bytesString[2 <- 10] andBool
19+
bytesString[2p256 <- 10p256] ==K bytesString[2 <- 10]
20+
21+
endmodule

0 commit comments

Comments
 (0)