Skip to content

Commit b62bac3

Browse files
committed
ir: Handle overflowing integer constant evaluation properly.
Fixes #1380
1 parent 0db9588 commit b62bac3

12 files changed

+93
-19
lines changed

src/clang.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::ffi::{CStr, CString};
1212
use std::fmt;
1313
use std::hash::Hash;
1414
use std::hash::Hasher;
15-
use std::os::raw::{c_char, c_int, c_uint, c_ulong};
15+
use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_longlong, c_ulonglong};
1616

1717
/// A cursor into the Clang AST, pointing to an AST node.
1818
///
@@ -1786,13 +1786,34 @@ impl EvalResult {
17861786
}
17871787

17881788
/// Try to get back the result as an integer.
1789-
pub fn as_int(&self) -> Option<i32> {
1790-
match self.kind() {
1791-
CXEval_Int => {
1792-
Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32)
1789+
pub fn as_int(&self) -> Option<i64> {
1790+
if self.kind() != CXEval_Int {
1791+
return None;
1792+
}
1793+
1794+
if !clang_EvalResult_isUnsignedInt::is_loaded() {
1795+
// FIXME(emilio): There's no way to detect underflow here, and clang
1796+
// will just happily give us a value.
1797+
return Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i64)
1798+
}
1799+
1800+
if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 {
1801+
let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) };
1802+
if value > i64::max_value() as c_ulonglong {
1803+
return None;
17931804
}
1794-
_ => None,
1805+
1806+
return Some(value as i64)
1807+
}
1808+
1809+
let value = unsafe { clang_EvalResult_getAsLongLong(self.x) };
1810+
if value > i64::max_value() as c_longlong {
1811+
return None;
1812+
}
1813+
if value < i64::min_value() as c_longlong {
1814+
return None;
17951815
}
1816+
Some(value as i64)
17961817
}
17971818

17981819
/// Evaluates the expression as a literal string, that may or may not be

src/ir/var.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,7 @@ impl ClangSubItemParser for Var {
265265

266266
let mut val = cursor
267267
.evaluate()
268-
.and_then(|v| v.as_int())
269-
.map(|val| val as i64);
268+
.and_then(|v| v.as_int());
270269
if val.is_none() || !kind.signedness_matches(val.unwrap()) {
271270
let tu = ctx.translation_unit();
272271
val = get_integer_literal_from_cursor(&cursor, tu);

tests/expectations/tests/error-E0600-cannot-apply-unary-negation-to-u32.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/expectations/tests/libclang-3.8/constant-evaluate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ extern "C" {
1515
#[link_name = "\u{1}k_expr"]
1616
pub static mut k_expr: EasyToOverflow;
1717
}
18+
extern "C" {
19+
#[link_name = "\u{1}wow"]
20+
pub static mut wow: EasyToOverflow;
21+
}
1822
extern "C" {
1923
#[link_name = "\u{1}BAZ"]
2024
pub static mut BAZ: ::std::os::raw::c_longlong;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
9+
10+
pub const a: u32 = 18446744073709551611;

tests/expectations/tests/libclang-3.9/constant-evaluate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ pub enum _bindgen_ty_1 {
1515
pub type EasyToOverflow = ::std::os::raw::c_ulonglong;
1616
pub const k: EasyToOverflow = 2147483648;
1717
pub const k_expr: EasyToOverflow = 0;
18+
extern "C" {
19+
#[link_name = "\u{1}wow"]
20+
pub static mut wow: EasyToOverflow;
21+
}
1822
pub const BAZ: ::std::os::raw::c_longlong = 24;
1923
pub const fuzz: f64 = 51.0;
2024
pub const BAZZ: ::std::os::raw::c_char = 53;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
9+
10+
pub const a: u32 = 18446744073709551611;

tests/expectations/tests/libclang-4/constant-evaluate.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
/* automatically generated by rust-bindgen */
22

3-
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
49

510
pub const foo: _bindgen_ty_1 = _bindgen_ty_1::foo;
611
pub const bar: _bindgen_ty_1 = _bindgen_ty_1::bar;
@@ -12,7 +17,8 @@ pub enum _bindgen_ty_1 {
1217
}
1318
pub type EasyToOverflow = ::std::os::raw::c_ulonglong;
1419
pub const k: EasyToOverflow = 2147483648;
15-
pub const k_expr: EasyToOverflow = 0;
20+
pub const k_expr: EasyToOverflow = 1152921504606846976;
21+
pub const wow: EasyToOverflow = 2147483648;
1622
pub const BAZ: ::std::os::raw::c_longlong = 24;
1723
pub const fuzz: f64 = 51.0;
1824
pub const BAZZ: ::std::os::raw::c_char = 53;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
9+
10+
pub const a: u32 = 4294967291;

tests/expectations/tests/libclang-5/constant-evaluate.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
/* automatically generated by rust-bindgen */
22

3-
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
49

510
pub const foo: _bindgen_ty_1 = _bindgen_ty_1::foo;
611
pub const bar: _bindgen_ty_1 = _bindgen_ty_1::bar;
@@ -12,7 +17,8 @@ pub enum _bindgen_ty_1 {
1217
}
1318
pub type EasyToOverflow = ::std::os::raw::c_ulonglong;
1419
pub const k: EasyToOverflow = 2147483648;
15-
pub const k_expr: EasyToOverflow = 0;
20+
pub const k_expr: EasyToOverflow = 1152921504606846976;
21+
pub const wow: EasyToOverflow = 2147483648;
1622
pub const BAZ: ::std::os::raw::c_longlong = 24;
1723
pub const fuzz: f64 = 51.0;
1824
pub const BAZZ: ::std::os::raw::c_char = 53;

0 commit comments

Comments
 (0)