Skip to content

Commit a34b58c

Browse files
authoredJul 26, 2019
Merge pull request rust-lang#99 from wasmerio/stringradix
Improve safety of const_int_from_string function by only allowing valid radixes.
2 parents d0eb92c + d0cb04a commit a34b58c

File tree

4 files changed

+65
-27
lines changed

4 files changed

+65
-27
lines changed
 

‎Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ enum-methods = "0.0.8"
2828
inkwell_internal_macros = { path = "./internal_macros", version = "0.1.0" }
2929
libc = "0.2"
3030
llvm-sys = "80.1"
31+
regex = "1"
3132

3233
[badges]
3334
travis-ci = { repository = "TheDan64/inkwell" }

‎src/types/int_type.rs

+54-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,47 @@ use crate::types::traits::AsTypeRef;
99
use crate::types::{Type, ArrayType, BasicTypeEnum, VectorType, PointerType, FunctionType};
1010
use crate::values::{AsValueRef, ArrayValue, GenericValue, IntValue};
1111

12+
use regex::Regex;
13+
14+
/// How to interpret a string or digits used to construct an integer constant.
15+
#[derive(Clone, Copy, Debug, EnumAsGetters, EnumIntoGetters, EnumToGetters, Eq, Hash, PartialEq)]
16+
pub enum StringRadix {
17+
/// Binary 0 or 1
18+
Binary = 2,
19+
/// Octal 0-7
20+
Octal = 8,
21+
/// Decimal 0-9
22+
Decimal = 10,
23+
/// Hexadecimal with upper or lowercase letters up to F.
24+
Hexadecimal = 16,
25+
/// Alphanumeric, 0-9 and all 26 letters in upper or lowercase.
26+
Alphanumeric = 36,
27+
}
28+
impl StringRadix {
29+
/// Create a radix from a base.
30+
pub fn from_u8(value: u8) -> Option<StringRadix> {
31+
match value {
32+
2 => Some(StringRadix::Binary),
33+
8 => Some(StringRadix::Octal),
34+
10 => Some(StringRadix::Decimal),
35+
16 => Some(StringRadix::Hexadecimal),
36+
36 => Some(StringRadix::Alphanumeric),
37+
_ => None
38+
}
39+
}
40+
41+
/// Create a Regex that matches valid strings for the given radix.
42+
pub fn to_regex(&self) -> Regex {
43+
match self {
44+
StringRadix::Binary => Regex::new(r"^[-+]?[01]+$").unwrap(),
45+
StringRadix::Octal => Regex::new(r"^[-+]?[0-7]+$").unwrap(),
46+
StringRadix::Decimal => Regex::new(r"^[-+]?[0-9]+$").unwrap(),
47+
StringRadix::Hexadecimal => Regex::new(r"^[-+]?[0-9abcdefABCDEF]+$").unwrap(),
48+
StringRadix::Alphanumeric => Regex::new(r"^[-+]?[0-9[:alpha:]]+$").unwrap(),
49+
}
50+
}
51+
}
52+
1253
/// An `IntType` is the type of an integer constant or variable.
1354
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1455
pub struct IntType {
@@ -209,32 +250,32 @@ impl IntType {
209250
///
210251
/// ```no_run
211252
/// use inkwell::context::Context;
253+
/// use inkwell::types::StringRadix;
212254
///
213255
/// let context = Context::create();
214256
/// let i8_type = context.i8_type();
215-
/// let i8_val = i8_type.const_int_from_string("0121", 10);
257+
/// let i8_val = i8_type.const_int_from_string("0121", StringRadix::Decimal).unwrap();
216258
///
217259
/// assert_eq!(i8_val.print_to_string().to_string(), "i8 121");
218260
///
219-
/// let i8_val = i8_type.const_int_from_string("0121", 3);
261+
/// let i8_val = i8_type.const_int_from_string("0121", StringRadix::from_u8(10).unwrap()).unwrap();
220262
///
221263
/// assert_eq!(i8_val.print_to_string().to_string(), "i8 16");
222264
///
223-
/// // Unexpected outputs:
224-
/// let i8_val = i8_type.const_int_from_string("0121", 2);
225-
///
226-
/// assert_eq!(i8_val.print_to_string().to_string(), "i8 3");
227-
///
228-
/// let i8_val = i8_type.const_int_from_string("ABCD", 2);
265+
/// let i8_val = i8_type.const_int_from_string("0121", StringRadix::Binary);
266+
/// assert!(i8_val.is_none());
229267
///
230-
/// assert_eq!(i8_val.print_to_string().to_string(), "i8 -15");
268+
/// let i8_val = i8_type.const_int_from_string("ABCD", StringRadix::Binary);
269+
/// assert!(i8_val.is_none());
231270
/// ```
232-
pub fn const_int_from_string(&self, slice: &str, radix: u8) -> IntValue {
271+
pub fn const_int_from_string(&self, slice: &str, radix: StringRadix) -> Option<IntValue> {
272+
if !radix.to_regex().is_match(slice) {
273+
return None
274+
}
233275
let value = unsafe {
234-
LLVMConstIntOfStringAndSize(self.as_type_ref(), slice.as_ptr() as *const i8, slice.len() as u32, radix)
276+
LLVMConstIntOfStringAndSize(self.as_type_ref(), slice.as_ptr() as *const i8, slice.len() as u32, radix as u8)
235277
};
236-
237-
IntValue::new(value)
278+
Some(IntValue::new(value))
238279
}
239280

240281
/// Create a constant `IntValue` of arbitrary precision.

‎src/types/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub use crate::types::array_type::ArrayType;
2424
pub use crate::types::enums::{AnyTypeEnum, BasicTypeEnum};
2525
pub use crate::types::float_type::FloatType;
2626
pub use crate::types::fn_type::FunctionType;
27-
pub use crate::types::int_type::IntType;
27+
pub use crate::types::int_type::{IntType, StringRadix};
2828
pub use crate::types::ptr_type::PointerType;
2929
pub use crate::types::struct_type::StructType;
3030
pub use crate::types::traits::{AnyType, BasicType, IntMathType, FloatMathType, PointerMathType};

‎tests/all/test_values.rs

+9-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ extern crate inkwell;
33
use self::inkwell::{DLLStorageClass, FloatPredicate, GlobalVisibility, ThreadLocalMode, AddressSpace};
44
use self::inkwell::context::Context;
55
use self::inkwell::module::Linkage::*;
6-
use self::inkwell::types::{StructType, VectorType};
6+
use self::inkwell::types::{StringRadix, StructType, VectorType};
77
use self::inkwell::values::{InstructionOpcode::*, MetadataValue, FIRST_CUSTOM_METADATA_KIND_ID, VectorValue};
88
#[llvm_versions(7.0..=latest)]
99
use self::inkwell::comdat::ComdatSelectionKind;
@@ -711,23 +711,19 @@ fn test_function_value_no_params() {
711711
fn test_value_from_string() {
712712
let context = Context::create();
713713
let i8_type = context.i8_type();
714-
let i8_val = i8_type.const_int_from_string("0121", 10);
714+
let i8_val = i8_type.const_int_from_string("0121", StringRadix::Decimal).unwrap();
715715

716716
assert_eq!(*i8_val.print_to_string(), *CString::new("i8 121").unwrap());
717717

718-
let i8_val = i8_type.const_int_from_string("0121", 3);
718+
let i8_val = i8_type.const_int_from_string("0121", StringRadix::from_u8(10).unwrap()).unwrap();
719719

720-
assert_eq!(*i8_val.print_to_string(), *CString::new("i8 16").unwrap());
720+
assert_eq!(i8_val.print_to_string().to_string(), "i8 121");
721721

722-
// LLVM will not throw an error, just parse until it can parse no more (and
723-
// possibly spit out something completely unexpected):
724-
let i8_val = i8_type.const_int_from_string("0121", 2);
725-
726-
assert_eq!(*i8_val.print_to_string(), *CString::new("i8 3").unwrap());
727-
728-
let i8_val = i8_type.const_int_from_string("ABCD", 2);
729-
730-
assert_eq!(*i8_val.print_to_string(), *CString::new("i8 -15").unwrap());
722+
assert_eq!(i8_type.const_int_from_string("", StringRadix::Binary), None);
723+
assert_eq!(i8_type.const_int_from_string("-", StringRadix::Binary), None);
724+
assert_eq!(i8_type.const_int_from_string("--1", StringRadix::Binary), None);
725+
assert_eq!(i8_type.const_int_from_string("2", StringRadix::Binary), None);
726+
assert_eq!(i8_type.const_int_from_string("2", StringRadix::Binary), None);
731727

732728
// Floats
733729
let f64_type = context.f64_type();

0 commit comments

Comments
 (0)
Please sign in to comment.