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

tests: Simplify VaList run-make test #56396

Merged
merged 1 commit into from
Dec 2, 2018
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
152 changes: 45 additions & 107 deletions src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,127 +16,65 @@ extern crate libc;

use libc::{c_char, c_double, c_int, c_long, c_longlong};
use std::ffi::VaList;
use std::slice;
use std::ffi::CStr;
use std::ffi::{CString, CStr};

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum AnswerType {
Double,
Long,
LongLong,
Int,
Byte,
CStr,
Skip,
macro_rules! continue_if {
($cond:expr) => {
if !($cond) {
return 0xff;
}
}
}

#[repr(C)]
pub union AnswerData {
pub double: c_double,
pub long: c_long,
pub longlong: c_longlong,
pub int: c_int,
pub byte: c_char,
pub cstr: *const c_char,
pub skip_ty: AnswerType,
unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
let cstr0 = CStr::from_ptr(ptr);
let cstr1 = CString::new(val).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this fails, this would panic across an FFI boundary, which is UB. Not expected to happen, but doing something more conservative (return false / abort) would be better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW this'll soon become a deterministic abort (not UB), so this is probably fine to leave in

&*cstr1 == cstr0
}

#[repr(C)]
pub struct Answer {
tag: AnswerType,
data: AnswerData,
#[no_mangle]
pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize {
continue_if!(ap.arg::<c_longlong>() == 1);
continue_if!(ap.arg::<c_int>() == 2);
continue_if!(ap.arg::<c_longlong>() == 3);
0
}

#[no_mangle]
pub unsafe fn compare_answers(answers: &[Answer], mut ap: VaList) -> usize {
for (i, answer) in answers.iter().enumerate() {
match answer {
Answer { tag: AnswerType::Double, data: AnswerData { double: d } } => {
let tmp = ap.arg::<c_double>();
if d.floor() != tmp.floor() {
println!("Double: {} != {}", d, tmp);
return i + 1;
}
}
Answer { tag: AnswerType::Long, data: AnswerData { long: l } } => {
let tmp = ap.arg::<c_long>();
if *l != tmp {
println!("Long: {} != {}", l, tmp);
return i + 1;
}
}
Answer { tag: AnswerType::LongLong, data: AnswerData { longlong: l } } => {
let tmp = ap.arg::<c_longlong>();
if *l != tmp {
println!("Long Long: {} != {}", l, tmp);
return i + 1;
}
}
Answer { tag: AnswerType::Int, data: AnswerData { int: n } } => {
let tmp = ap.arg::<c_int>();
if *n != tmp {
println!("Int: {} != {}", n, tmp);
return i + 1;
}
}
Answer { tag: AnswerType::Byte, data: AnswerData { byte: b } } => {
let tmp = ap.arg::<c_char>();
if *b != tmp {
println!("Byte: {} != {}", b, tmp);
return i + 1;
}
}
Answer { tag: AnswerType::CStr, data: AnswerData { cstr: c0 } } => {
let c1 = ap.arg::<*const c_char>();
let cstr0 = CStr::from_ptr(*c0);
let cstr1 = CStr::from_ptr(c1);
if cstr0 != cstr1 {
println!("C String: {:?} != {:?}", cstr0, cstr1);
return i + 1;
}
}
_ => {
println!("Unknown type!");
return i + 1;
}
}
}
return 0;
pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
continue_if!(ap.arg::<c_int>() == -1);
continue_if!(ap.arg::<c_char>() == 'A' as c_char);
continue_if!(ap.arg::<c_char>() == '4' as c_char);
continue_if!(ap.arg::<c_char>() == ';' as c_char);
continue_if!(ap.arg::<c_int>() == 0x32);
continue_if!(ap.arg::<c_int>() == 0x10000001);
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Valid!"));
0
}

#[no_mangle]
pub unsafe extern "C" fn check_rust(argc: usize, answers: *const Answer, ap: VaList) -> usize {
let slice = slice::from_raw_parts(answers, argc);
compare_answers(slice, ap)
pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
continue_if!(ap.arg::<c_long>() == 12);
continue_if!(ap.arg::<c_char>() == 'a' as c_char);
continue_if!(ap.arg::<c_double>().floor() == 6.18f64.floor());
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello"));
continue_if!(ap.arg::<c_int>() == 42);
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "World"));
0
}

#[no_mangle]
pub unsafe extern "C" fn check_rust_copy(argc: usize, answers: *const Answer,
mut ap: VaList) -> usize {
let slice = slice::from_raw_parts(answers, argc);
let mut skip_n = 0;
for (i, answer) in slice.iter().enumerate() {
match answer {
Answer { tag: AnswerType::Skip, data: AnswerData { skip_ty } } => {
match skip_ty {
AnswerType::Double => { ap.arg::<c_double>(); }
AnswerType::Long => { ap.arg::<c_long>(); }
AnswerType::LongLong => { ap.arg::<c_longlong>(); }
AnswerType::Int => { ap.arg::<c_int>(); }
AnswerType::Byte => { ap.arg::<c_char>(); }
AnswerType::CStr => { ap.arg::<*const c_char>(); }
_ => { return i; }
};
}
_ => {
skip_n = i;
break;
}
pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
continue_if!(ap.arg::<c_double>().floor() == 6.28f64.floor());
continue_if!(ap.arg::<c_int>() == 16);
continue_if!(ap.arg::<c_char>() == 'A' as c_char);
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!"));
ap.copy(|mut ap| {
if compare_c_str(ap.arg::<*const c_char>(), "Correct") {
0
} else {
0xff
}
}

ap.copy(|ap| {
compare_answers(&slice[skip_n..], ap)
})
}
79 changes: 12 additions & 67 deletions src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,84 +12,29 @@
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

typedef enum {
TAG_DOUBLE,
TAG_LONG,
TAG_LONGLONG,
TAG_INT,
TAG_BYTE,
TAG_CSTR,
TAG_SKIP,
} tag;
extern size_t check_list_0(va_list ap);
extern size_t check_list_1(va_list ap);
extern size_t check_list_2(va_list ap);
extern size_t check_list_copy_0(va_list ap);

typedef struct {
tag answer_type;
union {
double double_precision;
long num_long;
long long num_longlong;
int num_int;
int8_t byte;
char* cstr;
tag skip_ty;
} answer_data;
} answer;

#define MK_DOUBLE(n) \
{ TAG_DOUBLE, { .double_precision = n } }
#define MK_LONG(n) \
{ TAG_LONG, { .num_long = n } }
#define MK_LONGLONG(n) \
{ TAG_LONGLONG, { .num_longlong = n } }
#define MK_INT(n) \
{ TAG_INT, { .num_int = n } }
#define MK_BYTE(b) \
{ TAG_BYTE, { .byte = b } }
#define MK_CSTR(s) \
{ TAG_CSTR, { .cstr = s } }
#define MK_SKIP(ty) \
{ TAG_SKIP, { .skip_ty = TAG_ ## ty } }

extern size_t check_rust(size_t argc, const answer* answers, va_list ap);
extern size_t check_rust_copy(size_t argc, const answer* answers, va_list ap);

size_t test_check_rust(size_t argc, const answer* answers, ...) {
size_t ret = 0;
va_list ap;
va_start(ap, answers);
ret = check_rust(argc, answers, ap);
va_end(ap);
return ret;
}

size_t test_check_rust_copy(size_t argc, const answer* answers, ...) {
int test_rust(size_t (*fn)(va_list), ...) {
size_t ret = 0;
va_list ap;
va_start(ap, answers);
ret = check_rust_copy(argc, answers, ap);
va_start(ap, fn);
ret = fn(ap);
va_end(ap);
return ret;
}

int main(int argc, char* argv[]) {
answer test_alignment0[] = {MK_LONGLONG(0x01LL), MK_INT(0x02), MK_LONGLONG(0x03LL)};
assert(test_check_rust(3, test_alignment0, 0x01LL, 0x02, 0x03LL) == 0);
assert(test_rust(check_list_0, 0x01LL, 0x02, 0x03LL) == 0);

answer test_alignment1[] = {MK_INT(-1), MK_BYTE('A'), MK_BYTE('4'), MK_BYTE(';'),
MK_INT(0x32), MK_INT(0x10000001), MK_CSTR("Valid!")};
assert(test_check_rust(7, test_alignment1, -1, 'A', '4', ';', 0x32, 0x10000001,
"Valid!") == 0);
assert(test_rust(check_list_1, -1, 'A', '4', ';', 0x32, 0x10000001, "Valid!") == 0);

answer basic_answers[] = {MK_DOUBLE(3.14), MK_LONG(12l), MK_BYTE('a'),
MK_DOUBLE(6.28), MK_CSTR("Hello"), MK_INT(42),
MK_CSTR("World")};
assert(test_check_rust(7, basic_answers, 3.14, 12l, 'a', 6.28, "Hello",
42, "World") == 0);
assert(test_rust(check_list_2, 3.14, 12l, 'a', 6.28, "Hello", 42, "World") == 0);

answer copy_answers[] = { MK_SKIP(DOUBLE), MK_SKIP(INT), MK_SKIP(BYTE), MK_SKIP(CSTR),
MK_CSTR("Correctly skipped and copied list") };
assert(test_check_rust_copy(5, copy_answers, 6.28, 16, 'A', "Skip Me!",
"Correctly skipped and copied list") == 0);
assert(test_rust(check_list_copy_0, 6.28, 16, 'A', "Skip Me!", "Correct") == 0);
return 0;
}