summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <ecoal95@gmail.com>2016-11-17 10:50:48 +0100
committerEmilio Cobos Álvarez <ecoal95@gmail.com>2016-11-17 11:09:01 +0100
commit06e5f6c8bcc7fba5994a349b9ce88c1063eb4279 (patch)
treeb31a8a8e02f63325d19a327b73e2a59632c310b4
parentb9e15e9fc7f7100aa03256b6997639142ab38e87 (diff)
ir: Avoid generating out-of-range values in constants.
Fixes #274
-rw-r--r--libbindgen/src/codegen/mod.rs6
-rw-r--r--libbindgen/src/ir/int.rs5
-rw-r--r--libbindgen/src/ir/item.rs3
-rw-r--r--libbindgen/src/ir/ty.rs4
-rw-r--r--libbindgen/src/ir/var.rs35
-rw-r--r--libbindgen/tests/expectations/tests/constant-evaluate.rs3
-rw-r--r--libbindgen/tests/headers/constant-evaluate.h5
7 files changed, 42 insertions, 19 deletions
diff --git a/libbindgen/src/codegen/mod.rs b/libbindgen/src/codegen/mod.rs
index f15b92d1..5a54c113 100644
--- a/libbindgen/src/codegen/mod.rs
+++ b/libbindgen/src/codegen/mod.rs
@@ -228,7 +228,8 @@ impl CodeGenerator for Item {
result: &mut CodegenResult,
_extra: &()) {
if self.is_hidden(ctx) || result.seen(self.id()) {
- debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: self = {:?}", self);
+ debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \
+ self = {:?}", self);
return;
}
@@ -328,8 +329,7 @@ impl CodeGenerator for Var {
.build(ty)
}
VarType::Int(val) => {
- const_item.build(helpers::ast_ty::int_expr(val))
- .build(ty)
+ const_item.build(helpers::ast_ty::int_expr(val)).build(ty)
}
VarType::String(ref bytes) => {
// Account the trailing zero.
diff --git a/libbindgen/src/ir/int.rs b/libbindgen/src/ir/int.rs
index 2d85db83..179ebb96 100644
--- a/libbindgen/src/ir/int.rs
+++ b/libbindgen/src/ir/int.rs
@@ -90,4 +90,9 @@ impl IntKind {
Custom { is_signed, .. } => is_signed,
}
}
+
+ /// Whether this type's signedness matches the value.
+ pub fn signedness_matches(&self, val: i64) -> bool {
+ val >= 0 || self.is_signed()
+ }
}
diff --git a/libbindgen/src/ir/item.rs b/libbindgen/src/ir/item.rs
index 253db8c0..f464ce4a 100644
--- a/libbindgen/src/ir/item.rs
+++ b/libbindgen/src/ir/item.rs
@@ -1032,7 +1032,8 @@ impl ClangItemParser for Item {
// It's harmless, but if we restrict that, then
// tests/headers/nsStyleAutoArray.hpp crashes.
if let Err(ParseError::Recurse) = result {
- warn!("Unknown type, assuming named template type: id = {:?}; spelling = {}",
+ warn!("Unknown type, assuming named template type: \
+ id = {:?}; spelling = {}",
id,
ty.spelling());
Ok(Self::named_type_with_id(id,
diff --git a/libbindgen/src/ir/ty.rs b/libbindgen/src/ir/ty.rs
index b87dd11b..60611b8d 100644
--- a/libbindgen/src/ir/ty.rs
+++ b/libbindgen/src/ir/ty.rs
@@ -878,7 +878,9 @@ impl TypeCollector for Type {
}
// FIXME: Pending types!
ref other @ _ => {
- debug!("<Type as TypeCollector>::collect_types: Ignoring: {:?}", other);
+ debug!("<Type as TypeCollector>::collect_types: Ignoring: \
+ {:?}",
+ other);
}
}
}
diff --git a/libbindgen/src/ir/var.rs b/libbindgen/src/ir/var.rs
index 98b94da3..bbaea939 100644
--- a/libbindgen/src/ir/var.rs
+++ b/libbindgen/src/ir/var.rs
@@ -13,7 +13,7 @@ use super::ty::{FloatKind, TypeKind};
/// The type for a constant variable.
#[derive(Debug)]
pub enum VarType {
- /// An boolean.
+ /// A boolean.
Bool(bool),
/// An integer.
Int(i64),
@@ -196,7 +196,6 @@ impl ClangSubItemParser for Var {
let canonical_ty = ctx.safe_resolve_type(ty)
.and_then(|t| t.safe_canonical_type(ctx));
- let is_bool = canonical_ty.map_or(false, |t| t.is_bool());
let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
let is_float = canonical_ty.map_or(false, |t| t.is_float());
@@ -204,18 +203,26 @@ impl ClangSubItemParser for Var {
// TODO: Strings, though the lookup is a bit more hard (we need
// to look at the canonical type of the pointee too, and check
// is char, u8, or i8 I guess).
- let value = if is_bool {
- cursor.evaluate().as_int()
- .map(|val| VarType::Bool(val != 0))
- } else if is_integer {
- cursor.evaluate()
- .as_int()
- .map(|val| val as i64)
- .or_else(|| {
- let tu = ctx.translation_unit();
- get_integer_literal_from_cursor(&cursor, tu)
- })
- .map(VarType::Int)
+ let value = if is_integer {
+ let kind = match *canonical_ty.unwrap().kind() {
+ TypeKind::Int(kind) => kind,
+ _ => unreachable!(),
+ };
+
+ let mut val =
+ cursor.evaluate().as_int().map(|val| val as i64);
+ if val.is_none() || !kind.signedness_matches(val.unwrap()) {
+ let tu = ctx.translation_unit();
+ val = get_integer_literal_from_cursor(&cursor, tu);
+ }
+
+ val.map(|val| {
+ if kind == IntKind::Bool {
+ VarType::Bool(val != 0)
+ } else {
+ VarType::Int(val)
+ }
+ })
} else if is_float {
cursor.evaluate()
.as_double()
diff --git a/libbindgen/tests/expectations/tests/constant-evaluate.rs b/libbindgen/tests/expectations/tests/constant-evaluate.rs
index 27b8d829..6947be98 100644
--- a/libbindgen/tests/expectations/tests/constant-evaluate.rs
+++ b/libbindgen/tests/expectations/tests/constant-evaluate.rs
@@ -9,6 +9,9 @@ pub const bar: _bindgen_ty_1 = _bindgen_ty_1::bar;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum _bindgen_ty_1 { foo = 4, bar = 8, }
+pub type EasyToOverflow = ::std::os::raw::c_ulonglong;
+pub const k: EasyToOverflow = 2147483648;
+pub const k_expr: EasyToOverflow = 0;
pub const BAZ: ::std::os::raw::c_longlong = 24;
pub const fuzz: f64 = 51.;
pub const BAZZ: ::std::os::raw::c_char = 53;
diff --git a/libbindgen/tests/headers/constant-evaluate.h b/libbindgen/tests/headers/constant-evaluate.h
index 2790d603..b6a0492f 100644
--- a/libbindgen/tests/headers/constant-evaluate.h
+++ b/libbindgen/tests/headers/constant-evaluate.h
@@ -5,6 +5,11 @@ enum {
bar = 8,
};
+typedef unsigned long long EasyToOverflow;
+const EasyToOverflow k = 0x80000000;
+
+const EasyToOverflow k_expr = 1ULL << 60;
+
const long long BAZ = (1 << foo) | bar;
const double fuzz = (1 + 50.0f);
const char BAZZ = '5';