-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
llvm_points_to_bitfield
and enable_lax_loads_and_stores
This adds support for writing specifications that talk about bitfields in LLVM code by way of the new `llvm_points_to_bitfield` command. Broadly speaking, `llvm_points_to_bitfield ptr fieldName rhs` is like `llvm_points_to (llvm_field ptr fieldName) rhs`, except that `fieldName` is required to be the name of a field within a bitfield. The salient details are: * LLVM bitcode itself does not a built-in concept of bitfields, but LLVM's debug metadata does. Support for retrieving bitfield-related metadata was added to `llvm-pretty` in GaloisInc/llvm-pretty#90, so this patch bumps the `llvm-pretty` submodule to incorporate it. This patch also updates the `crucible` submodule to incorporate corresponding changes in GaloisInc/crucible#936. * The `LLVMPointsTo` data type now has a new `LLVMPointsToBitfield` data constructor that stores all of the necessary information related to the `llvm_points_to_bitfield` command. As a result, the changes in this patch are fairly insulated from the rest of SAW, as most of the new code involves adding additional cases to handle `LLVMPointsToBitfield`. * Two of the key new functions are `storePointsToBitfieldValue` and `matchPointsToBitfieldValue`, which implement the behavior of `llvm_points_to_bitfield` in pre- and post-conditions. These functions implement the necessary bit-twiddling to store values in and retrieve values out of bitfield. I have left extensive comments in each function describing how all of this works. * Accompanying `llvm_points_to_bitfield` is a new set of `{enable,disable}_lax_loads_and_stores` command, which toggles the Crucible-side option of the same name. When `enable_lax_loads_and_stores` is on, reading from uninitialized memory will return a symbolic value rather than failing outright. This is essential to be able to deal with LLVM bitcode involving bitfields, as reading a field from a bitfield involves reading the entire bitfield at once, which may include parts of the struct that have not been initialized yet. * There are various `test_bitfield_*` test cases under `intTests` to test examples of bitfield-related specifications that should and should not verify. * I have also updated `saw-remote-api` and `saw-client` to handle bitfields as well, along with a Python-specific test case. Fixes #1461.
- Loading branch information
1 parent
a07c01c
commit 86dd256
Showing
51 changed files
with
1,586 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule crucible
updated
4 files
+17 −0 | crucible-llvm/doc/limitations.md | |
+1 −0 | crucible-llvm/src/Lang/Crucible/LLVM/Translation/BlockInfo.hs | |
+1 −1 | dependencies/llvm-pretty | |
+1 −1 | dependencies/llvm-pretty-bc-parser |
Submodule llvm-pretty
updated
from 15bc00 to ed904c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CC = clang | ||
CFLAGS = -g -emit-llvm -frecord-command-line -O0 | ||
|
||
all: test.bc | ||
|
||
test.bc: test.c | ||
$(CC) $(CFLAGS) -c $< -o $@ | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -f test.bc |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
struct s { | ||
int32_t w; | ||
uint8_t x1:1; | ||
uint8_t x2:2; | ||
uint8_t y:1; | ||
int32_t z; | ||
}; | ||
|
||
uint8_t get_x2(struct s *ss) { | ||
return ss->x2; | ||
} | ||
|
||
bool get_y(struct s *ss) { | ||
return ss->y; | ||
} | ||
|
||
void set_x2(struct s *ss, uint8_t x2) { | ||
ss->x2 = x2; | ||
} | ||
|
||
void set_y(struct s *ss, bool y) { | ||
ss->y = y; | ||
} | ||
|
||
void set_x2_alt(struct s *ss, uint8_t x2) { | ||
set_x2(ss, x2); | ||
} | ||
|
||
void set_y_alt(struct s *ss, bool y) { | ||
set_y(ss, y); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
enable_experimental; | ||
enable_lax_loads_and_stores; | ||
|
||
let get_x2_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 2); | ||
llvm_points_to_bitfield ss "x2" (llvm_term z); | ||
llvm_execute_func [ss]; | ||
llvm_return (llvm_term {{ zext z : [8] }}); | ||
}; | ||
|
||
let get_y_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 1); | ||
llvm_points_to_bitfield ss "y" (llvm_term z); | ||
llvm_execute_func [ss]; | ||
llvm_return (llvm_term z); | ||
}; | ||
|
||
let set_x2_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 8); | ||
llvm_execute_func [ss, llvm_term z]; | ||
llvm_points_to_bitfield ss "x2" (llvm_term {{ drop z : [2] }}); | ||
}; | ||
|
||
let set_x2_alt_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 2); | ||
llvm_execute_func [ss, llvm_term {{ zext z : [8] }}]; | ||
llvm_points_to_bitfield ss "x2" (llvm_term z); | ||
}; | ||
|
||
let set_y_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 1); | ||
llvm_execute_func [ss, llvm_term z]; | ||
llvm_points_to_bitfield ss "y" (llvm_term z); | ||
}; | ||
|
||
let set_y_alt_spec = set_y_spec; | ||
|
||
m <- llvm_load_module "test.bc"; | ||
|
||
llvm_verify m "get_x2" [] false get_x2_spec (w4_unint_z3 []); | ||
llvm_verify m "get_y" [] false get_y_spec (w4_unint_z3 []); | ||
llvm_verify m "set_x2" [] false set_x2_spec (w4_unint_z3 []); | ||
llvm_verify m "set_x2_alt" [] false set_x2_alt_spec (w4_unint_z3 []); | ||
llvm_verify m "set_y" [] false set_y_spec (w4_unint_z3 []); | ||
llvm_verify m "set_y_alt" [] false set_y_alt_spec (w4_unint_z3 []); | ||
|
||
set_x2_ov <- llvm_unsafe_assume_spec m "set_x2" set_x2_spec; | ||
llvm_verify m "set_x2_alt" [set_x2_ov] false set_x2_alt_spec (w4_unint_z3 []); | ||
set_y_ov <- llvm_unsafe_assume_spec m "set_y" set_y_spec; | ||
llvm_verify m "set_y_alt" [set_y_ov] false set_y_alt_spec (w4_unint_z3 []); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -e | ||
|
||
$SAW test.saw |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CC = clang | ||
CFLAGS = -g -emit-llvm -frecord-command-line -O0 | ||
|
||
all: test.bc | ||
|
||
test.bc: test.c | ||
$(CC) $(CFLAGS) -c $< -o $@ | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -f test.bc |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
struct s { | ||
int32_t w; | ||
uint8_t x1:1; | ||
uint8_t x2:2; | ||
uint8_t y:1; | ||
int32_t z; | ||
}; | ||
|
||
bool get_y(struct s *ss) { | ||
return ss->y; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
enable_experimental; | ||
enable_lax_loads_and_stores; | ||
|
||
let get_y_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 1); | ||
// Duplicate llvm_points_to_bitfield statements involving `y` | ||
llvm_points_to_bitfield ss "y" (llvm_term z); | ||
llvm_points_to_bitfield ss "y" (llvm_term z); | ||
llvm_execute_func [ss]; | ||
llvm_return (llvm_term z); | ||
}; | ||
|
||
m <- llvm_load_module "test.bc"; | ||
fails (llvm_verify m "get_y" [] false get_y_spec (w4_unint_z3 [])); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -e | ||
|
||
$SAW test.saw |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CC = clang | ||
CFLAGS = -g -emit-llvm -frecord-command-line -O0 | ||
|
||
all: test.bc | ||
|
||
test.bc: test.c | ||
$(CC) $(CFLAGS) -c $< -o $@ | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -f test.bc |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
struct s { | ||
int32_t w; | ||
uint8_t x1:1; | ||
uint8_t x2:2; | ||
uint8_t y:1; | ||
int32_t z; | ||
}; | ||
|
||
uint8_t get_x2(struct s *ss) { | ||
return ss->x2; | ||
} | ||
|
||
bool get_y(struct s *ss) { | ||
return ss->y; | ||
} | ||
|
||
void set_x2(struct s *ss, uint8_t x2) { | ||
ss->x2 = x2; | ||
} | ||
|
||
void set_y(struct s *ss, bool y) { | ||
ss->y = y; | ||
} | ||
|
||
void set_x2_alt(struct s *ss, uint8_t x2) { | ||
set_x2(ss, x2); | ||
} | ||
|
||
void set_y_alt(struct s *ss, bool y) { | ||
set_y(ss, y); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
enable_experimental; | ||
enable_lax_loads_and_stores; | ||
enable_smt_array_memory_model; | ||
|
||
let get_x2_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 2); | ||
llvm_points_to_bitfield ss "x2" (llvm_term z); | ||
llvm_execute_func [ss]; | ||
llvm_return (llvm_term {{ zext z : [8] }}); | ||
}; | ||
|
||
let get_y_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 1); | ||
llvm_points_to_bitfield ss "y" (llvm_term z); | ||
llvm_execute_func [ss]; | ||
llvm_return (llvm_term z); | ||
}; | ||
|
||
let set_x2_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 8); | ||
llvm_execute_func [ss, llvm_term z]; | ||
llvm_points_to_bitfield ss "x2" (llvm_term {{ drop z : [2] }}); | ||
}; | ||
|
||
let set_x2_alt_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 2); | ||
llvm_execute_func [ss, llvm_term {{ zext z : [8] }}]; | ||
llvm_points_to_bitfield ss "x2" (llvm_term z); | ||
}; | ||
|
||
let set_y_spec = do { | ||
ss <- llvm_alloc (llvm_alias "struct.s"); | ||
z <- llvm_fresh_var "z" (llvm_int 1); | ||
llvm_execute_func [ss, llvm_term z]; | ||
llvm_points_to_bitfield ss "y" (llvm_term z); | ||
}; | ||
|
||
let set_y_alt_spec = set_y_spec; | ||
|
||
m <- llvm_load_module "test.bc"; | ||
|
||
llvm_verify m "get_x2" [] false get_x2_spec (w4_unint_z3 []); | ||
llvm_verify m "get_y" [] false get_y_spec (w4_unint_z3 []); | ||
llvm_verify m "set_x2" [] false set_x2_spec (w4_unint_z3 []); | ||
llvm_verify m "set_x2_alt" [] false set_x2_alt_spec (w4_unint_z3 []); | ||
llvm_verify m "set_y" [] false set_y_spec (w4_unint_z3 []); | ||
|
||
set_x2_ov <- llvm_unsafe_assume_spec m "set_x2" set_x2_spec; | ||
llvm_verify m "set_x2_alt" [set_x2_ov] false set_x2_alt_spec (w4_unint_z3 []); | ||
set_y_ov <- llvm_unsafe_assume_spec m "set_y" set_y_spec; | ||
llvm_verify m "set_y_alt" [set_y_ov] false set_y_alt_spec (w4_unint_z3 []); |
Oops, something went wrong.