mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-14 22:38:46 +00:00
Update skeleton
This commit is contained in:
20
Cargo.lock
generated
20
Cargo.lock
generated
@@ -13,7 +13,7 @@ name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -39,7 +39,7 @@ name = "backtrace-sys"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.50"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -94,7 +94,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -110,7 +110,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.11"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -325,7 +325,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.17"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -348,7 +348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -437,14 +437,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
|
||||
"checksum backtrace-sys 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "78848718ee1255a2485d1309ad9cdecfc2e7d0362dd11c6829364c6b35ae1bc7"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
|
||||
"checksum cc 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)" = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b"
|
||||
"checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231"
|
||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
"checksum hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8a0d737e0f947a1864e93d33fdef4af8445a00d1ed8dc0c8ddb73139ea6abf15"
|
||||
"checksum hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
|
||||
"checksum hexf 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e54653cc32d838771a36532647afad59c4bf7155745eeeec406f71fd5d7e7538"
|
||||
"checksum hexf-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22eadcfadba76a730b2764eaa577d045f35e0ef5174b9c5b46adf1ee42b85e12"
|
||||
"checksum hexf-parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79296f72d53a89096cbc9a88c9547ee8dfe793388674620e2207593d370550ac"
|
||||
@@ -471,7 +471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
"checksum syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
|
||||
30
README.md
30
README.md
@@ -98,5 +98,31 @@ reduces the program; check if the reduced program still fails on the test, and i
|
||||
given program with the reduced one; repeat until you get a small enough buggy program. For more
|
||||
information, we refer to the [Creduce](https://embed.cs.utah.edu/creduce/) homepage.
|
||||
|
||||
**[NOTICE]** The fuzzer supports Ubuntu 18.04 only. It may work for other platforms, but if it
|
||||
doesn't, please run the fuzzer in Ubuntu 18.04.
|
||||
**[NOTICE]** The fuzzer supports Ubuntu 18.04 or 20.04 only. It may work for other platforms, but if it
|
||||
doesn't, please run the fuzzer in Ubuntu 18.04 or 20.04.
|
||||
|
||||
|
||||
## Running RISC-V Binaries
|
||||
|
||||
### Install
|
||||
|
||||
```sh
|
||||
# Ubuntu 20.04 or higher
|
||||
apt install gcc-10-riscv64-linux-gnu qemu-user-static
|
||||
```
|
||||
|
||||
### Cross-Compilation and Architecture-Emulation
|
||||
|
||||
```sh
|
||||
# Compile C source code into RISC-V assembly
|
||||
riscv64-linux-gnu-gcc-10 hello.c -S -o hello.S
|
||||
|
||||
# Link to an RISC-V executable
|
||||
riscv64-linux-gnu-gcc-10 -static hello.S -o hello
|
||||
|
||||
# Emulate the executable
|
||||
qemu-riscv64-static ./hello
|
||||
|
||||
# Check the return value
|
||||
echo $?
|
||||
```
|
||||
|
||||
35
examples/c/float.c
Normal file
35
examples/c/float.c
Normal file
@@ -0,0 +1,35 @@
|
||||
double custom_abs(double a) {
|
||||
return a < 0 ? -a : a;
|
||||
}
|
||||
|
||||
double custom_max(double a, double b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
int is_close(double a, double b, double rel_tol, double abs_tol) {
|
||||
return custom_abs(a - b) <= custom_max(rel_tol * custom_max(custom_abs(a), custom_abs(b)), abs_tol);
|
||||
}
|
||||
|
||||
double average(int len, int a[10]) {
|
||||
int sum = 0;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
sum += a[i];
|
||||
}
|
||||
|
||||
return (double) sum / len;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int a[10];
|
||||
int len = 10;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
a[i] = i;
|
||||
}
|
||||
|
||||
float avg = average(len, a);
|
||||
|
||||
return is_close(avg, 4.5, 1e-09, 0.1);
|
||||
}
|
||||
3205
examples/c/float2.c
Normal file
3205
examples/c/float2.c
Normal file
File diff suppressed because it is too large
Load Diff
59
examples/c/float2_gen.py
Normal file
59
examples/c/float2_gen.py
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Make c program which uses floating point variables
|
||||
|
||||
To make c program, execute `python3 float_gen.py > file_name.c`
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
def random_operator():
|
||||
ops = ["+", "-", "*", "/"]
|
||||
return ops[random.randint(0, len(ops) - 1)]
|
||||
|
||||
def random_dtype():
|
||||
dtypes = ["float", "double"]
|
||||
return dtypes[random.randint(0, len(dtypes) - 1)]
|
||||
|
||||
def random_suffix():
|
||||
suffixes = ["f", ""]
|
||||
return suffixes[random.randint(0, len(suffixes) - 1)]
|
||||
|
||||
def make_expr(vars):
|
||||
if len(vars) == 1:
|
||||
return vars[0]
|
||||
else:
|
||||
var = vars.pop()
|
||||
return "(" + var + " " + random_operator() + " " + make_expr(vars) + ")"
|
||||
|
||||
def make_func(i):
|
||||
"""Make a function that contains a conditional expression
|
||||
"""
|
||||
func_signature = random_dtype() + " func_" + str(i) + "()"
|
||||
variables = "abcdefghijklmnopqrstuvwxyzA"
|
||||
func_inner = []
|
||||
val_bitmap = []
|
||||
|
||||
# Variable initializiation
|
||||
for var in variables:
|
||||
val = random.gauss(0, 1)
|
||||
val_bitmap.append(val)
|
||||
decl = "\t" + random_dtype() + " " + var + " = " + str(val) + random_suffix() + ";"
|
||||
func_inner.append(decl)
|
||||
|
||||
func_inner.append("\treturn " + make_expr(list(variables)) + ";")
|
||||
|
||||
return "\n".join([func_signature, "{"] + func_inner + ["}"])
|
||||
|
||||
if __name__ == "__main__":
|
||||
src = ""
|
||||
return_stmt = "\treturn (int)("
|
||||
NUM_FUNC = 100
|
||||
for i in range(NUM_FUNC):
|
||||
src += make_func(i)
|
||||
src += "\n\n"
|
||||
return_stmt += "func_" + str(i) + "()"
|
||||
return_stmt += " " + random_operator() + " " if i != (NUM_FUNC - 1) else ");"
|
||||
src += "int main()\n{\n" + return_stmt + "\n}\n"
|
||||
|
||||
print(src)
|
||||
@@ -1,22 +1,23 @@
|
||||
struct color { int number; char name; };
|
||||
|
||||
int f(int i, int const a[i]) {
|
||||
int main() {
|
||||
int temp = 0;
|
||||
const float temp2 = 0.f, temp3 = 0.f;
|
||||
temp = sizeof(unsigned char);
|
||||
temp = _Alignof(unsigned char);
|
||||
temp += sizeof(unsigned char);
|
||||
temp += _Alignof(unsigned char);
|
||||
|
||||
struct color c;
|
||||
c.name;
|
||||
struct color c = {1, 2};
|
||||
temp += c.name;
|
||||
struct color *cp = &c;
|
||||
cp->name;
|
||||
temp += cp->name;
|
||||
|
||||
for(int i = 0, j = 0; i < 10; ++i) {
|
||||
break;
|
||||
if ( i == 2 && j == 0) break;
|
||||
temp += i;
|
||||
}
|
||||
|
||||
switch(temp) {
|
||||
case 1: {
|
||||
temp = 0;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
@@ -45,3 +45,9 @@ impl WriteLine for TranslationUnit {
|
||||
todo!("homework 1")
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteString for Initializer {
|
||||
fn write_string(&self) -> String {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,9 +721,22 @@ impl Dtype {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_const(&self) -> bool {
|
||||
match self {
|
||||
Self::Unit { is_const } => *is_const,
|
||||
Self::Int { is_const, .. } => *is_const,
|
||||
Self::Float { is_const, .. } => *is_const,
|
||||
Self::Pointer { is_const, .. } => *is_const,
|
||||
Self::Array { .. } => true,
|
||||
Self::Struct { is_const, .. } => *is_const,
|
||||
Self::Function { .. } => true,
|
||||
Self::Typedef { is_const, .. } => *is_const,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Check if `Dtype` is constant. if it is constant, the variable of `Dtype` is not assignable.
|
||||
pub fn is_const(&self, structs: &HashMap<String, Option<Dtype>>) -> bool {
|
||||
pub fn is_immutable(&self, structs: &HashMap<String, Option<Dtype>>) -> bool {
|
||||
match self {
|
||||
Self::Unit { is_const } => *is_const,
|
||||
Self::Int { is_const, .. } => *is_const,
|
||||
@@ -751,9 +764,9 @@ impl Dtype {
|
||||
// If an array is wrapped in a struct and the array's inner type is not
|
||||
// constant, it is assignable to another object of the same struct type.
|
||||
if let Self::Array { inner, .. } = f.deref() {
|
||||
inner.is_const_for_array_struct_field_inner(structs)
|
||||
inner.is_immutable_for_array_struct_field_inner(structs)
|
||||
} else {
|
||||
f.deref().is_const(structs)
|
||||
f.deref().is_immutable(structs)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -762,14 +775,14 @@ impl Dtype {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_const_for_array_struct_field_inner(
|
||||
fn is_immutable_for_array_struct_field_inner(
|
||||
&self,
|
||||
structs: &HashMap<String, Option<Dtype>>,
|
||||
) -> bool {
|
||||
if let Self::Array { inner, .. } = self {
|
||||
inner.is_const_for_array_struct_field_inner(structs)
|
||||
inner.is_immutable_for_array_struct_field_inner(structs)
|
||||
} else {
|
||||
self.is_const(structs)
|
||||
self.is_immutable(structs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,16 +863,23 @@ impl Dtype {
|
||||
field_name: &str,
|
||||
structs: &HashMap<String, Option<Dtype>>,
|
||||
) -> Option<(usize, Self)> {
|
||||
if let Self::Struct {
|
||||
fields,
|
||||
size_align_offsets,
|
||||
..
|
||||
} = self
|
||||
{
|
||||
let fields = fields.as_ref().expect("struct should have its definition");
|
||||
let (_, _, offsets) = size_align_offsets
|
||||
if let Self::Struct { name, .. } = self {
|
||||
let struct_name = name.as_ref().expect("`self` must have its name");
|
||||
let struct_type = structs
|
||||
.get(struct_name)
|
||||
.expect("`structs` must have value matched with `struct_name`")
|
||||
.as_ref()
|
||||
.expect("struct should have `offsets` as `Some`");
|
||||
.expect("`struct_type` must have its definition");
|
||||
let fields = struct_type
|
||||
.get_struct_fields()
|
||||
.expect("`struct_type` must be struct type")
|
||||
.as_ref()
|
||||
.expect("`fields` must be `Some`");
|
||||
let (_, _, offsets) = struct_type
|
||||
.get_struct_size_align_offsets()
|
||||
.expect("`struct_type` must be struct type")
|
||||
.as_ref()
|
||||
.expect("`offsets` must be `Some`");
|
||||
|
||||
assert_eq!(fields.len(), offsets.len());
|
||||
for (field, offset) in izip!(fields, offsets) {
|
||||
@@ -869,19 +889,8 @@ impl Dtype {
|
||||
}
|
||||
} else {
|
||||
let field_dtype = field.deref();
|
||||
let struct_name = field_dtype
|
||||
.get_struct_name()
|
||||
.expect("`field_dtype` must be struct type")
|
||||
.as_ref()
|
||||
.expect("structure type must have its name");
|
||||
let struct_type = structs
|
||||
.get(struct_name)
|
||||
.expect("`structs` must have value matched with `struct_name`")
|
||||
.as_ref()
|
||||
.expect("`struct_type` must have its definition");
|
||||
|
||||
let (offset_inner, dtype) = some_or!(
|
||||
struct_type.get_offset_struct_field(field_name, structs),
|
||||
field_dtype.get_offset_struct_field(field_name, structs),
|
||||
continue
|
||||
);
|
||||
return Some((*offset + offset_inner, dtype));
|
||||
@@ -1115,7 +1124,7 @@ impl Dtype {
|
||||
message: format!("unknown type name `{}`", name),
|
||||
})?
|
||||
.clone();
|
||||
let is_const = dtype.is_const(structs) || *is_const;
|
||||
let is_const = dtype.is_const() || *is_const;
|
||||
|
||||
dtype.set_const(is_const)
|
||||
}
|
||||
|
||||
460
src/ir/interp.rs
460
src/ir/interp.rs
@@ -2,6 +2,7 @@ use core::fmt;
|
||||
use core::iter;
|
||||
use core::mem;
|
||||
use failure::Fail;
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use itertools::izip;
|
||||
@@ -33,7 +34,7 @@ pub enum Value {
|
||||
/// * Casting from an f32 to an f64 is perfect and lossless (f32 -> f64)
|
||||
/// * Casting from an f64 to an f32 will produce the closest possible value (f64 -> f32)
|
||||
/// https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions
|
||||
value: f64,
|
||||
value: OrderedFloat<f64>,
|
||||
width: usize,
|
||||
},
|
||||
Pointer {
|
||||
@@ -67,10 +68,7 @@ impl TryFrom<Constant> for Value {
|
||||
width,
|
||||
is_signed,
|
||||
},
|
||||
Constant::Float { value, width } => Self::Float {
|
||||
value: value.into_inner(),
|
||||
width,
|
||||
},
|
||||
Constant::Float { value, width } => Self::Float { value, width },
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
@@ -125,7 +123,10 @@ impl Value {
|
||||
|
||||
#[inline]
|
||||
fn float(value: f64, width: usize) -> Self {
|
||||
Self::Float { value, width }
|
||||
Self::Float {
|
||||
value: value.into(),
|
||||
width,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -421,6 +422,187 @@ mod calculator {
|
||||
use super::Value;
|
||||
use crate::ir::*;
|
||||
use lang_c::ast;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn calculate_integer_binary_operator_expression(
|
||||
op: &ast::BinaryOperator,
|
||||
lhs: u128,
|
||||
rhs: u128,
|
||||
width: usize,
|
||||
is_signed: bool,
|
||||
) -> Result<Value, ()> {
|
||||
let result = match op {
|
||||
// TODO: explain why plus & minus do not need to consider `is_signed'
|
||||
ast::BinaryOperator::Plus => (lhs as i128 + rhs as i128) as u128,
|
||||
ast::BinaryOperator::Minus => (lhs as i128 - rhs as i128) as u128,
|
||||
ast::BinaryOperator::Multiply => {
|
||||
if is_signed {
|
||||
(lhs as i128 * rhs as i128) as u128
|
||||
} else {
|
||||
lhs * rhs
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::Divide => {
|
||||
assert!(rhs != 0);
|
||||
if is_signed {
|
||||
(lhs as i128 / rhs as i128) as u128
|
||||
} else {
|
||||
lhs / rhs
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::Modulo => {
|
||||
assert!(rhs != 0);
|
||||
if is_signed {
|
||||
(lhs as i128 % rhs as i128) as u128
|
||||
} else {
|
||||
lhs % rhs
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::ShiftLeft => {
|
||||
let rhs = if is_signed {
|
||||
let rhs = rhs as i128;
|
||||
assert!(rhs >= 0);
|
||||
assert!(rhs < (width as i128));
|
||||
rhs as u128
|
||||
} else {
|
||||
assert!(rhs < (width as u128));
|
||||
rhs
|
||||
};
|
||||
|
||||
lhs << rhs
|
||||
}
|
||||
ast::BinaryOperator::ShiftRight => {
|
||||
if is_signed {
|
||||
// arithmetic shift right
|
||||
let rhs = rhs as i128;
|
||||
assert!(rhs >= 0);
|
||||
assert!(rhs < (width as i128));
|
||||
((lhs as i128) >> rhs) as u128
|
||||
} else {
|
||||
// logical shift right
|
||||
assert!(rhs < (width as u128));
|
||||
let bit_mask = (1u128 << width as u128) - 1;
|
||||
let lhs = lhs & bit_mask;
|
||||
lhs >> rhs
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::BitwiseAnd => lhs & rhs,
|
||||
ast::BinaryOperator::BitwiseXor => lhs ^ rhs,
|
||||
ast::BinaryOperator::BitwiseOr => lhs | rhs,
|
||||
ast::BinaryOperator::Equals => {
|
||||
let result = if lhs == rhs { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::NotEquals => {
|
||||
let result = if lhs != rhs { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::Less => {
|
||||
let condition = if is_signed {
|
||||
(lhs as i128) < (rhs as i128)
|
||||
} else {
|
||||
lhs < rhs
|
||||
};
|
||||
let result = if condition { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::Greater => {
|
||||
let condition = if is_signed {
|
||||
(lhs as i128) > (rhs as i128)
|
||||
} else {
|
||||
lhs > rhs
|
||||
};
|
||||
let result = if condition { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::LessOrEqual => {
|
||||
let condition = if is_signed {
|
||||
(lhs as i128) <= (rhs as i128)
|
||||
} else {
|
||||
lhs <= rhs
|
||||
};
|
||||
let result = if condition { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::GreaterOrEqual => {
|
||||
let condition = if is_signed {
|
||||
(lhs as i128) >= (rhs as i128)
|
||||
} else {
|
||||
lhs >= rhs
|
||||
};
|
||||
let result = if condition { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
_ => todo!(
|
||||
"calculate_binary_operator_expression: not supported operator {:?}",
|
||||
op
|
||||
),
|
||||
};
|
||||
|
||||
let result = if is_signed {
|
||||
sign_extension(result, width as u128)
|
||||
} else {
|
||||
trim_unnecessary_bits(result, width as u128)
|
||||
};
|
||||
|
||||
Ok(Value::int(result, width, is_signed))
|
||||
}
|
||||
|
||||
fn calculate_float_binary_operator_expression(
|
||||
op: &ast::BinaryOperator,
|
||||
lhs: OrderedFloat<f64>,
|
||||
rhs: OrderedFloat<f64>,
|
||||
width: usize,
|
||||
) -> Result<Value, ()> {
|
||||
let result = match op {
|
||||
ast::BinaryOperator::Plus => lhs.into_inner() + rhs.into_inner(),
|
||||
ast::BinaryOperator::Minus => lhs.into_inner() - rhs.into_inner(),
|
||||
ast::BinaryOperator::Multiply => lhs.into_inner() * rhs.into_inner(),
|
||||
ast::BinaryOperator::Divide => {
|
||||
assert!(rhs.into_inner() != 0.0);
|
||||
lhs.into_inner() / rhs.into_inner()
|
||||
}
|
||||
ast::BinaryOperator::Equals => {
|
||||
let order = lhs
|
||||
.partial_cmp(&rhs)
|
||||
.expect("`lhs` and `rhs` must be not NAN");
|
||||
let result = if Ordering::Equal == order { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::NotEquals => {
|
||||
let order = lhs
|
||||
.partial_cmp(&rhs)
|
||||
.expect("`lhs` and `rhs` must be not NAN");
|
||||
let result = if Ordering::Equal != order { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::Less => {
|
||||
let result = if lhs.lt(&rhs) { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::Greater => {
|
||||
let result = if lhs.gt(&rhs) { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::LessOrEqual => {
|
||||
let result = if lhs.le(&rhs) { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::GreaterOrEqual => {
|
||||
let result = if lhs.ge(&rhs) { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
_ => todo!(
|
||||
"calculate_binary_operator_expression: not supported case for \
|
||||
{:?} {:?} {:?}",
|
||||
op,
|
||||
lhs,
|
||||
rhs
|
||||
),
|
||||
};
|
||||
|
||||
Ok(Value::float(result, width))
|
||||
}
|
||||
|
||||
// TODO: change to template function in the future
|
||||
pub fn calculate_binary_operator_expression(
|
||||
@@ -428,11 +610,10 @@ mod calculator {
|
||||
lhs: Value,
|
||||
rhs: Value,
|
||||
) -> Result<Value, ()> {
|
||||
match (op, lhs, rhs) {
|
||||
(_, Value::Undef { .. }, _) => Err(()),
|
||||
(_, _, Value::Undef { .. }) => Err(()),
|
||||
match (lhs, rhs) {
|
||||
(Value::Undef { .. }, _) => Err(()),
|
||||
(_, Value::Undef { .. }) => Err(()),
|
||||
(
|
||||
op,
|
||||
Value::Int {
|
||||
value: lhs,
|
||||
width: lhs_w,
|
||||
@@ -447,121 +628,38 @@ mod calculator {
|
||||
assert_eq!(lhs_w, rhs_w);
|
||||
assert_eq!(lhs_s, rhs_s);
|
||||
|
||||
let result = match op {
|
||||
// TODO: explain why plus & minus do not need to consider `is_signed'
|
||||
ast::BinaryOperator::Plus => (lhs as i128 + rhs as i128) as u128,
|
||||
ast::BinaryOperator::Minus => (lhs as i128 - rhs as i128) as u128,
|
||||
ast::BinaryOperator::Multiply => {
|
||||
if lhs_s {
|
||||
(lhs as i128 * rhs as i128) as u128
|
||||
} else {
|
||||
lhs * rhs
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::Divide => {
|
||||
if lhs_s {
|
||||
(lhs as i128 / rhs as i128) as u128
|
||||
} else {
|
||||
lhs / rhs
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::Modulo => {
|
||||
if lhs_s {
|
||||
(lhs as i128 % rhs as i128) as u128
|
||||
} else {
|
||||
lhs % rhs
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::ShiftLeft => {
|
||||
let rhs = if lhs_s {
|
||||
let rhs = rhs as i128;
|
||||
assert!(rhs >= 0);
|
||||
assert!(rhs < (lhs_w as i128));
|
||||
rhs as u128
|
||||
} else {
|
||||
assert!(rhs < (lhs_w as u128));
|
||||
rhs
|
||||
};
|
||||
|
||||
lhs << rhs
|
||||
}
|
||||
ast::BinaryOperator::ShiftRight => {
|
||||
if lhs_s {
|
||||
// arithmetic shift right
|
||||
let rhs = rhs as i128;
|
||||
assert!(rhs >= 0);
|
||||
assert!(rhs < (lhs_w as i128));
|
||||
((lhs as i128) >> rhs) as u128
|
||||
} else {
|
||||
// logical shift right
|
||||
assert!(rhs < (lhs_w as u128));
|
||||
let bit_mask = (1u128 << lhs_w as u128) - 1;
|
||||
let lhs = lhs & bit_mask;
|
||||
lhs >> rhs
|
||||
}
|
||||
}
|
||||
ast::BinaryOperator::BitwiseAnd => lhs & rhs,
|
||||
ast::BinaryOperator::BitwiseXor => lhs ^ rhs,
|
||||
ast::BinaryOperator::BitwiseOr => lhs | rhs,
|
||||
ast::BinaryOperator::Equals => {
|
||||
let result = if lhs == rhs { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::NotEquals => {
|
||||
let result = if lhs != rhs { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::Less => {
|
||||
let condition = if lhs_s {
|
||||
(lhs as i128) < (rhs as i128)
|
||||
} else {
|
||||
lhs < rhs
|
||||
};
|
||||
let result = if condition { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::Greater => {
|
||||
let condition = if lhs_s {
|
||||
(lhs as i128) > (rhs as i128)
|
||||
} else {
|
||||
lhs > rhs
|
||||
};
|
||||
let result = if condition { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::LessOrEqual => {
|
||||
let condition = if lhs_s {
|
||||
(lhs as i128) <= (rhs as i128)
|
||||
} else {
|
||||
lhs <= rhs
|
||||
};
|
||||
let result = if condition { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
ast::BinaryOperator::GreaterOrEqual => {
|
||||
let condition = if lhs_s {
|
||||
(lhs as i128) >= (rhs as i128)
|
||||
} else {
|
||||
lhs >= rhs
|
||||
};
|
||||
let result = if condition { 1 } else { 0 };
|
||||
return Ok(Value::int(result, 1, false));
|
||||
}
|
||||
_ => todo!(
|
||||
"calculate_binary_operator_expression: not supported operator {:?}",
|
||||
op
|
||||
),
|
||||
};
|
||||
|
||||
let result = if lhs_s {
|
||||
sign_extension(result, lhs_w as u128)
|
||||
} else {
|
||||
trim_unnecessary_bits(result, lhs_w as u128)
|
||||
};
|
||||
|
||||
Ok(Value::int(result, lhs_w, lhs_s))
|
||||
calculate_integer_binary_operator_expression(op, lhs, rhs, lhs_w, lhs_s)
|
||||
}
|
||||
(op, lhs, rhs) => todo!(
|
||||
(
|
||||
Value::Float {
|
||||
value: lhs,
|
||||
width: lhs_w,
|
||||
},
|
||||
Value::Float {
|
||||
value: rhs,
|
||||
width: rhs_w,
|
||||
},
|
||||
) => {
|
||||
assert_eq!(lhs_w, rhs_w);
|
||||
|
||||
calculate_float_binary_operator_expression(op, lhs, rhs, lhs_w)
|
||||
}
|
||||
(Value::Pointer { bid, .. }, Value::Pointer { bid: other_bid, .. }) => match op {
|
||||
ast::BinaryOperator::Equals => {
|
||||
let result = if bid == other_bid { 1 } else { 0 };
|
||||
Ok(Value::int(result, 1, false))
|
||||
}
|
||||
ast::BinaryOperator::NotEquals => {
|
||||
let result = if bid != other_bid { 1 } else { 0 };
|
||||
Ok(Value::int(result, 1, false))
|
||||
}
|
||||
_ => todo!(
|
||||
"calculate_binary_operator_expression: not supported case for \
|
||||
{:?} between pointer and integer value",
|
||||
op,
|
||||
),
|
||||
},
|
||||
(lhs, rhs) => todo!(
|
||||
"calculate_binary_operator_expression: not supported case for {:?} {:?} {:?}",
|
||||
op,
|
||||
lhs,
|
||||
@@ -574,48 +672,47 @@ mod calculator {
|
||||
op: &ast::UnaryOperator,
|
||||
operand: Value,
|
||||
) -> Result<Value, ()> {
|
||||
match (op, operand) {
|
||||
(_, Value::Undef { .. }) => Err(()),
|
||||
(
|
||||
ast::UnaryOperator::Plus,
|
||||
Value::Int {
|
||||
value,
|
||||
width,
|
||||
is_signed,
|
||||
},
|
||||
) => Ok(Value::int(value, width, is_signed)),
|
||||
(
|
||||
ast::UnaryOperator::Minus,
|
||||
Value::Int {
|
||||
value,
|
||||
width,
|
||||
is_signed,
|
||||
},
|
||||
) => {
|
||||
// TODO: check what is exact behavior of appling minus to unsigned value
|
||||
let result = if is_signed {
|
||||
(-(value as i128)) as u128
|
||||
} else {
|
||||
let result = (-(value as i128)) as u128;
|
||||
let bit_mask = (1u128 << (width as u128)) - 1;
|
||||
result & bit_mask
|
||||
};
|
||||
Ok(Value::int(result as u128, width, is_signed))
|
||||
match operand {
|
||||
Value::Undef { .. } => Err(()),
|
||||
Value::Int {
|
||||
value,
|
||||
width,
|
||||
is_signed,
|
||||
} => {
|
||||
match op {
|
||||
ast::UnaryOperator::Plus => Ok(Value::int(value, width, is_signed)),
|
||||
ast::UnaryOperator::Minus => {
|
||||
let result = if is_signed {
|
||||
(-(value as i128)) as u128
|
||||
} else {
|
||||
let value = (-(value as i128)) as u128;
|
||||
trim_unnecessary_bits(value, width as u128)
|
||||
};
|
||||
Ok(Value::int(result as u128, width, is_signed))
|
||||
}
|
||||
ast::UnaryOperator::Negate => {
|
||||
// Check if it is boolean
|
||||
assert!(width == 1);
|
||||
let result = if value == 0 { 1 } else { 0 };
|
||||
Ok(Value::int(result, width, is_signed))
|
||||
}
|
||||
_ => todo!(
|
||||
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
|
||||
op,
|
||||
operand,
|
||||
),
|
||||
}
|
||||
}
|
||||
(
|
||||
ast::UnaryOperator::Negate,
|
||||
Value::Int {
|
||||
value,
|
||||
width,
|
||||
is_signed,
|
||||
},
|
||||
) => {
|
||||
// Check if it is boolean
|
||||
assert!(width == 1);
|
||||
let result = if value == 0 { 1 } else { 0 };
|
||||
Ok(Value::int(result, width, is_signed))
|
||||
}
|
||||
(op, operand) => todo!(
|
||||
Value::Float { value, width } => match op {
|
||||
ast::UnaryOperator::Plus => Ok(Value::float(value.into_inner(), width)),
|
||||
ast::UnaryOperator::Minus => Ok(Value::float(-value.into_inner(), width)),
|
||||
_ => todo!(
|
||||
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
|
||||
op,
|
||||
operand,
|
||||
),
|
||||
},
|
||||
_ => todo!(
|
||||
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
|
||||
op,
|
||||
operand,
|
||||
@@ -630,8 +727,6 @@ mod calculator {
|
||||
|
||||
match (value, dtype) {
|
||||
(Value::Undef { .. }, _) => Err(()),
|
||||
// TODO: distinguish zero/signed extension in the future
|
||||
// TODO: consider truncate in the future
|
||||
(
|
||||
Value::Int { value, width, .. },
|
||||
Dtype::Int {
|
||||
@@ -640,7 +735,6 @@ mod calculator {
|
||||
..
|
||||
},
|
||||
) => {
|
||||
// Other cases
|
||||
let result = if target_signed {
|
||||
if width >= target_width {
|
||||
// TODO: explain the logic in the future
|
||||
@@ -668,6 +762,17 @@ mod calculator {
|
||||
};
|
||||
Ok(Value::float(casted_value, width))
|
||||
}
|
||||
(Value::Int { value, .. }, Dtype::Pointer { inner, .. }) => {
|
||||
if value == 0 {
|
||||
Ok(Value::pointer(None, 0, inner.deref().clone()))
|
||||
} else {
|
||||
panic!(format!(
|
||||
"calculate_typecast: not support case \
|
||||
typecast int to pointer when `value` is {}",
|
||||
value
|
||||
))
|
||||
}
|
||||
}
|
||||
(
|
||||
Value::Float { value, .. },
|
||||
Dtype::Int {
|
||||
@@ -675,14 +780,14 @@ mod calculator {
|
||||
},
|
||||
) => {
|
||||
let casted_value = if is_signed {
|
||||
value as i128 as u128
|
||||
value.into_inner() as i128 as u128
|
||||
} else {
|
||||
value as u128
|
||||
value.into_inner() as u128
|
||||
};
|
||||
Ok(Value::int(casted_value, width, is_signed))
|
||||
}
|
||||
(Value::Float { value, .. }, Dtype::Float { width, .. }) => {
|
||||
Ok(Value::float(value, width))
|
||||
Ok(Value::float(value.into_inner(), width))
|
||||
}
|
||||
(value, dtype) => todo!("calculate_typecast ({:?}) {:?}", value, dtype),
|
||||
}
|
||||
@@ -706,12 +811,15 @@ mod calculator {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
#[allow(dead_code)]
|
||||
// TODO: delete `allow(dead_code)`
|
||||
/// Even though `Pointer` variant is constructed and actively used at run-time,
|
||||
/// the rust compiler analyzes it is dead code.
|
||||
/// For this reason, we add `allow(dead_code)` mark.
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
enum Byte {
|
||||
Undef,
|
||||
Concrete(u8),
|
||||
#[allow(dead_code)]
|
||||
Pointer {
|
||||
bid: Option<usize>,
|
||||
offset: isize,
|
||||
@@ -921,8 +1029,8 @@ impl Byte {
|
||||
} => {
|
||||
let size = value.dtype().size_align_of(structs).unwrap().0;
|
||||
let value_bits: u128 = match size {
|
||||
Dtype::SIZE_OF_FLOAT => (*float_value as f32).to_bits() as u128,
|
||||
Dtype::SIZE_OF_DOUBLE => (*float_value as f64).to_bits() as u128,
|
||||
Dtype::SIZE_OF_FLOAT => (float_value.into_inner() as f32).to_bits() as u128,
|
||||
Dtype::SIZE_OF_DOUBLE => (float_value.into_inner() as f64).to_bits() as u128,
|
||||
_ => panic!("value_to_bytes: {} is not a valid float size", size),
|
||||
};
|
||||
|
||||
@@ -1045,8 +1153,6 @@ impl Memory {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: allocation fields will be added in the future
|
||||
// TODO: program fields will be added in the future
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct State<'i> {
|
||||
/// A data structure that maps each global variable to a pointer value
|
||||
|
||||
@@ -186,7 +186,6 @@ pub struct Block {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum Instruction {
|
||||
// TODO: the variants of Instruction will be added in the future
|
||||
Nop,
|
||||
BinOp {
|
||||
op: ast::BinaryOperator,
|
||||
@@ -255,7 +254,6 @@ impl Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum BlockExit {
|
||||
Jump {
|
||||
|
||||
@@ -198,7 +198,6 @@ impl WriteString for Operand {
|
||||
|
||||
impl WriteOp for ast::BinaryOperator {
|
||||
fn write_operation(&self) -> String {
|
||||
// TODO: represent signed & unsigned if necessary
|
||||
match self {
|
||||
Self::Multiply => "mul",
|
||||
Self::Divide => "div",
|
||||
|
||||
10
src/tests.rs
10
src/tests.rs
@@ -8,6 +8,10 @@ use wait_timeout::ChildExt;
|
||||
|
||||
use crate::*;
|
||||
|
||||
// Rust sets an exit code of 101 when the process panicked.
|
||||
// So, we decide KECC sets an exit code of 102 after 101 when the test skipped.
|
||||
pub const SKIP_TEST: i32 = 102;
|
||||
|
||||
pub fn test_write_c(unit: &TranslationUnit, _path: &Path) {
|
||||
let temp_dir = tempdir().expect("temp dir creation failed");
|
||||
let temp_file_path = temp_dir.path().join("temp.c");
|
||||
@@ -43,7 +47,7 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) {
|
||||
.unwrap()
|
||||
.success()
|
||||
{
|
||||
return;
|
||||
::std::process::exit(SKIP_TEST);
|
||||
}
|
||||
|
||||
// Execute compiled executable
|
||||
@@ -64,10 +68,10 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) {
|
||||
println!("timeout occurs");
|
||||
child.kill().unwrap();
|
||||
child.wait().unwrap();
|
||||
return;
|
||||
::std::process::exit(SKIP_TEST);
|
||||
}
|
||||
);
|
||||
let status = some_or!(status.code(), return);
|
||||
let status = some_or_exit!(status.code(), SKIP_TEST);
|
||||
|
||||
let ir = match Irgen::default().translate(unit) {
|
||||
Ok(ir) => ir,
|
||||
|
||||
@@ -48,6 +48,7 @@ REPLACE_DICT = {
|
||||
"char _unused2[^;]*;": "char _unused2[10];",
|
||||
}
|
||||
CSMITH_DIR = "csmith-2.3.0"
|
||||
SKIP_TEST = 102
|
||||
|
||||
def install_csmith(tests_dir):
|
||||
global CSMITH_DIR
|
||||
@@ -200,17 +201,20 @@ def creduce(tests_dir, fuzz_arg):
|
||||
raise e
|
||||
|
||||
def fuzz(tests_dir, fuzz_arg, num_iter):
|
||||
global SKIP_TEST
|
||||
|
||||
csmith_bin, csmith_inc = install_csmith(tests_dir)
|
||||
try:
|
||||
if num_iter is None:
|
||||
print("Fuzzing with infinitely many test cases. Please press [ctrl+C] to break.")
|
||||
iterator = itertools.count(0)
|
||||
else:
|
||||
assert num_iter > 0
|
||||
print("Fuzzing with {} test cases.".format(num_iter))
|
||||
iterator = range(num_iter)
|
||||
|
||||
for i in iterator:
|
||||
print("Test case #{}".format(i))
|
||||
i = 0
|
||||
skip = 0
|
||||
while True:
|
||||
print("Test case #{} (skipped: {})".format(i, skip))
|
||||
src = generate(tests_dir, csmith_bin)
|
||||
with open(os.path.join(tests_dir, "test.c"), 'w') as dst:
|
||||
dst.write(src)
|
||||
@@ -223,11 +227,20 @@ def fuzz(tests_dir, fuzz_arg, num_iter):
|
||||
args = ["cargo", "run", "--release", "--bin", "fuzz", "--", fuzz_arg, os.path.join(tests_dir, "test_polished.c")]
|
||||
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tests_dir)
|
||||
proc.communicate(timeout=60)
|
||||
if proc.returncode != 0:
|
||||
|
||||
# KECC sets an exit code of 102 when the test skipped.
|
||||
if proc.returncode == SKIP_TEST:
|
||||
skip += 1
|
||||
continue
|
||||
elif proc.returncode != 0:
|
||||
raise Exception("Test `{}` failed with exit code {}.".format(" ".join(args), proc.returncode))
|
||||
|
||||
i += 1
|
||||
if num_iter is not None:
|
||||
if i > num_iter: break
|
||||
except subprocess.TimeoutExpired as e:
|
||||
proc.kill()
|
||||
raise e
|
||||
skip += 1
|
||||
except KeyboardInterrupt:
|
||||
proc.terminate()
|
||||
print("\n[Ctrl+C] interrupted")
|
||||
|
||||
@@ -29,6 +29,7 @@ if
|
||||
grep 'non-void function does not return a value' out.txt ||\
|
||||
grep 'too many arguments in call' out.txt ||\
|
||||
grep 'declaration does not declare anything' out.txt ||\
|
||||
grep 'not equal to a null pointer is always true' out.txt ||\
|
||||
! gcc -Wall -Wextra -O2 test_reduced.c > outa.txt 2>&1 ||\
|
||||
grep 'uninitialized' outa.txt ||\
|
||||
grep 'without a cast' outa.txt ||\
|
||||
|
||||
Reference in New Issue
Block a user