Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
50999336
R
Rust
项目概览
int
/
Rust
接近 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
50999336
编写于
8月 17, 2018
作者:
R
Ralf Jung
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
move validation to its own file
上级
f2aeb5b8
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
346 addition
and
331 deletion
+346
-331
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/eval_context.rs
+2
-331
src/librustc_mir/interpret/mod.rs
src/librustc_mir/interpret/mod.rs
+1
-0
src/librustc_mir/interpret/validity.rs
src/librustc_mir/interpret/validity.rs
+343
-0
未找到文件。
src/librustc_mir/interpret/eval_context.rs
浏览文件 @
50999336
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
use
rustc
::
hir
::
map
::
definitions
::
DefPathData
;
use
rustc
::
hir
::
map
::
definitions
::
DefPathData
;
use
rustc
::
mir
;
use
rustc
::
mir
;
use
rustc
::
ty
::
layout
::{
use
rustc
::
ty
::
layout
::{
self
,
Size
,
Align
,
HasDataLayout
,
LayoutOf
,
TyLayout
,
Primitive
self
,
Size
,
Align
,
HasDataLayout
,
LayoutOf
,
TyLayout
};
};
use
rustc
::
ty
::
subst
::{
Subst
,
Substs
};
use
rustc
::
ty
::
subst
::{
Subst
,
Substs
};
use
rustc
::
ty
::{
self
,
Ty
,
TyCtxt
,
TypeFoldable
};
use
rustc
::
ty
::{
self
,
Ty
,
TyCtxt
,
TypeFoldable
};
...
@@ -15,7 +15,7 @@
...
@@ -15,7 +15,7 @@
use
rustc_data_structures
::
fx
::{
FxHashSet
,
FxHasher
};
use
rustc_data_structures
::
fx
::{
FxHashSet
,
FxHasher
};
use
rustc_data_structures
::
indexed_vec
::
IndexVec
;
use
rustc_data_structures
::
indexed_vec
::
IndexVec
;
use
rustc
::
mir
::
interpret
::{
use
rustc
::
mir
::
interpret
::{
GlobalId
,
Scalar
,
FrameInfo
,
AllocType
,
GlobalId
,
Scalar
,
FrameInfo
,
EvalResult
,
EvalErrorKind
,
EvalResult
,
EvalErrorKind
,
ScalarMaybeUndef
,
ScalarMaybeUndef
,
truncate
,
sign_extend
,
truncate
,
sign_extend
,
...
@@ -29,31 +29,6 @@
...
@@ -29,31 +29,6 @@
Memory
,
Machine
Memory
,
Machine
};
};
macro_rules!
validation_failure
{
(
$what:expr
,
$where:expr
,
$details:expr
)
=>
{{
let
where_
=
if
$where
.is_empty
()
{
String
::
new
()
}
else
{
format!
(
" at {}"
,
$where
)
};
err!
(
ValidationFailure
(
format!
(
"encountered {}{}, but expected {}"
,
$what
,
where_
,
$details
,
)))
}};
(
$what:expr
,
$where:expr
)
=>
{{
let
where_
=
if
$where
.is_empty
()
{
String
::
new
()
}
else
{
format!
(
" at {}"
,
$where
)
};
err!
(
ValidationFailure
(
format!
(
"encountered {}{}"
,
$what
,
where_
,
)))
}};
}
pub
struct
EvalContext
<
'a
,
'mir
,
'tcx
:
'a
+
'mir
,
M
:
Machine
<
'mir
,
'tcx
>>
{
pub
struct
EvalContext
<
'a
,
'mir
,
'tcx
:
'a
+
'mir
,
M
:
Machine
<
'mir
,
'tcx
>>
{
/// Stores the `Machine` instance.
/// Stores the `Machine` instance.
pub
machine
:
M
,
pub
machine
:
M
,
...
@@ -670,243 +645,6 @@ pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Cons
...
@@ -670,243 +645,6 @@ pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Cons
self
.tcx
.const_eval
(
param_env
.and
(
gid
))
.map_err
(|
err
|
EvalErrorKind
::
ReferencedConstant
(
err
)
.into
())
self
.tcx
.const_eval
(
param_env
.and
(
gid
))
.map_err
(|
err
|
EvalErrorKind
::
ReferencedConstant
(
err
)
.into
())
}
}
fn
validate_scalar
(
&
self
,
value
:
ScalarMaybeUndef
,
size
:
Size
,
scalar
:
&
layout
::
Scalar
,
path
:
&
str
,
ty
:
Ty
,
)
->
EvalResult
<
'tcx
>
{
trace!
(
"validate scalar: {:#?}, {:#?}, {:#?}, {}"
,
value
,
size
,
scalar
,
ty
);
let
(
lo
,
hi
)
=
scalar
.valid_range
.clone
()
.into_inner
();
let
value
=
match
value
{
ScalarMaybeUndef
::
Scalar
(
scalar
)
=>
scalar
,
ScalarMaybeUndef
::
Undef
=>
return
validation_failure!
(
"undefined bytes"
,
path
),
};
let
bits
=
match
value
{
Scalar
::
Bits
{
bits
,
size
:
value_size
}
=>
{
assert_eq!
(
value_size
as
u64
,
size
.bytes
());
bits
},
Scalar
::
Ptr
(
_
)
=>
{
let
ptr_size
=
self
.memory
.pointer_size
();
let
ptr_max
=
u128
::
max_value
()
>>
(
128
-
ptr_size
.bits
());
return
if
lo
>
hi
{
if
lo
-
hi
==
1
{
// no gap, all values are ok
Ok
(())
}
else
if
hi
<
ptr_max
||
lo
>
1
{
let
max
=
u128
::
max_value
()
>>
(
128
-
size
.bits
());
validation_failure!
(
"pointer"
,
path
,
format!
(
"something in the range {:?} or {:?}"
,
0
..=
lo
,
hi
..=
max
)
)
}
else
{
Ok
(())
}
}
else
if
hi
<
ptr_max
||
lo
>
1
{
validation_failure!
(
"pointer"
,
path
,
format!
(
"something in the range {:?}"
,
scalar
.valid_range
)
)
}
else
{
Ok
(())
};
},
};
// char gets a special treatment, because its number space is not contiguous so `TyLayout`
// has no special checks for chars
match
ty
.sty
{
ty
::
TyChar
=>
{
debug_assert_eq!
(
size
.bytes
(),
4
);
if
::
std
::
char
::
from_u32
(
bits
as
u32
)
.is_none
()
{
return
err!
(
InvalidChar
(
bits
));
}
}
_
=>
{},
}
use
std
::
ops
::
RangeInclusive
;
let
in_range
=
|
bound
:
RangeInclusive
<
u128
>
|
bound
.contains
(
&
bits
);
if
lo
>
hi
{
if
in_range
(
0
..=
hi
)
||
in_range
(
lo
..=
u128
::
max_value
())
{
Ok
(())
}
else
{
validation_failure!
(
bits
,
path
,
format!
(
"something in the range {:?} or {:?}"
,
..=
hi
,
lo
..
)
)
}
}
else
{
if
in_range
(
scalar
.valid_range
.clone
())
{
Ok
(())
}
else
{
validation_failure!
(
bits
,
path
,
format!
(
"something in the range {:?}"
,
scalar
.valid_range
)
)
}
}
}
/// This function checks the memory where `ptr` points to.
/// It will error if the bits at the destination do not match the ones described by the layout.
pub
fn
validate_mplace
(
&
self
,
dest
:
MPlaceTy
<
'tcx
>
,
path
:
String
,
seen
:
&
mut
FxHashSet
<
(
MPlaceTy
<
'tcx
>
)
>
,
todo
:
&
mut
Vec
<
(
MPlaceTy
<
'tcx
>
,
String
)
>
,
)
->
EvalResult
<
'tcx
>
{
self
.memory
.dump_alloc
(
dest
.to_ptr
()
?
.alloc_id
);
trace!
(
"validate_mplace: {:?}, {:#?}"
,
*
dest
,
dest
.layout
);
// Find the right variant
let
(
variant
,
dest
)
=
match
dest
.layout.variants
{
layout
::
Variants
::
NicheFilling
{
niche
:
ref
tag
,
..
}
|
layout
::
Variants
::
Tagged
{
ref
tag
,
..
}
=>
{
let
size
=
tag
.value
.size
(
self
);
// we first read the tag value as scalar, to be able to validate it
let
tag_mplace
=
self
.mplace_field
(
dest
,
0
)
?
;
let
tag_value
=
self
.read_scalar
(
tag_mplace
.into
())
?
;
let
path
=
format!
(
"{}.TAG"
,
path
);
self
.validate_scalar
(
tag_value
,
size
,
tag
,
&
path
,
tag_mplace
.layout.ty
)
?
;
// then we read it again to get the index, to continue
let
variant
=
self
.read_discriminant_as_variant_index
(
dest
.into
())
?
;
let
dest
=
self
.mplace_downcast
(
dest
,
variant
)
?
;
trace!
(
"variant layout: {:#?}"
,
dest
.layout
);
(
variant
,
dest
)
},
layout
::
Variants
::
Single
{
index
}
=>
{
(
index
,
dest
)
}
};
// Validate all fields
match
dest
.layout.fields
{
// primitives are unions with zero fields
layout
::
FieldPlacement
::
Union
(
0
)
=>
{
match
dest
.layout.abi
{
// nothing to do, whatever the pointer points to, it is never going to be read
layout
::
Abi
::
Uninhabited
=>
validation_failure!
(
"a value of an uninhabited type"
,
path
),
// check that the scalar is a valid pointer or that its bit range matches the
// expectation.
layout
::
Abi
::
Scalar
(
ref
scalar_layout
)
=>
{
let
size
=
scalar_layout
.value
.size
(
self
);
let
value
=
self
.read_value
(
dest
.into
())
?
;
let
scalar
=
value
.to_scalar_or_undef
();
self
.validate_scalar
(
scalar
,
size
,
scalar_layout
,
&
path
,
dest
.layout.ty
)
?
;
if
scalar_layout
.value
==
Primitive
::
Pointer
{
// ignore integer pointers, we can't reason about the final hardware
if
let
Scalar
::
Ptr
(
ptr
)
=
scalar
.not_undef
()
?
{
let
alloc_kind
=
self
.tcx.alloc_map
.lock
()
.get
(
ptr
.alloc_id
);
if
let
Some
(
AllocType
::
Static
(
did
))
=
alloc_kind
{
// statics from other crates are already checked
// extern statics should not be validated as they have no body
if
!
did
.is_local
()
||
self
.tcx
.is_foreign_item
(
did
)
{
return
Ok
(());
}
}
if
value
.layout.ty
.builtin_deref
(
false
)
.is_some
()
{
trace!
(
"Recursing below ptr {:#?}"
,
value
);
let
ptr_place
=
self
.ref_to_mplace
(
value
)
?
;
// we have not encountered this pointer+layout combination before
if
seen
.insert
(
ptr_place
)
{
todo
.push
((
ptr_place
,
format!
(
"(*{})"
,
path
)))
}
}
}
}
Ok
(())
},
_
=>
bug!
(
"bad abi for FieldPlacement::Union(0): {:#?}"
,
dest
.layout.abi
),
}
}
layout
::
FieldPlacement
::
Union
(
_
)
=>
{
// We can't check unions, their bits are allowed to be anything.
// The fields don't need to correspond to any bit pattern of the union's fields.
// See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
Ok
(())
},
layout
::
FieldPlacement
::
Array
{
count
,
..
}
=>
{
for
i
in
0
..
count
{
let
mut
path
=
path
.clone
();
self
.dump_field_name
(
&
mut
path
,
dest
.layout.ty
,
i
as
usize
,
variant
)
.unwrap
();
let
field
=
self
.mplace_field
(
dest
,
i
)
?
;
self
.validate_mplace
(
field
,
path
,
seen
,
todo
)
?
;
}
Ok
(())
},
layout
::
FieldPlacement
::
Arbitrary
{
ref
offsets
,
..
}
=>
{
// fat pointers need special treatment
match
dest
.layout.ty
.builtin_deref
(
false
)
.map
(|
tam
|
&
tam
.ty.sty
)
{
|
Some
(
ty
::
TyStr
)
|
Some
(
ty
::
TySlice
(
_
))
=>
{
// check the length (for nicer error messages)
let
len_mplace
=
self
.mplace_field
(
dest
,
1
)
?
;
let
len
=
self
.read_scalar
(
len_mplace
.into
())
?
;
let
len
=
match
len
.to_bits
(
len_mplace
.layout.size
)
{
Err
(
_
)
=>
return
validation_failure!
(
"length is not a valid integer"
,
path
),
Ok
(
len
)
=>
len
as
u64
,
};
// get the fat ptr, and recursively check it
let
ptr
=
self
.ref_to_mplace
(
self
.read_value
(
dest
.into
())
?
)
?
;
assert_eq!
(
ptr
.extra
,
PlaceExtra
::
Length
(
len
));
let
unpacked_ptr
=
self
.unpack_unsized_mplace
(
ptr
)
?
;
if
seen
.insert
(
unpacked_ptr
)
{
let
mut
path
=
path
.clone
();
self
.dump_field_name
(
&
mut
path
,
dest
.layout.ty
,
0
,
0
)
.unwrap
();
todo
.push
((
unpacked_ptr
,
path
))
}
},
Some
(
ty
::
TyDynamic
(
..
))
=>
{
// check the vtable (for nicer error messages)
let
vtable
=
self
.read_scalar
(
self
.mplace_field
(
dest
,
1
)
?
.into
())
?
;
let
vtable
=
match
vtable
.to_ptr
()
{
Err
(
_
)
=>
return
validation_failure!
(
"vtable address is not a pointer"
,
path
),
Ok
(
vtable
)
=>
vtable
,
};
// get the fat ptr, and recursively check it
let
ptr
=
self
.ref_to_mplace
(
self
.read_value
(
dest
.into
())
?
)
?
;
assert_eq!
(
ptr
.extra
,
PlaceExtra
::
Vtable
(
vtable
));
let
unpacked_ptr
=
self
.unpack_unsized_mplace
(
ptr
)
?
;
if
seen
.insert
(
unpacked_ptr
)
{
let
mut
path
=
path
.clone
();
self
.dump_field_name
(
&
mut
path
,
dest
.layout.ty
,
0
,
0
)
.unwrap
();
todo
.push
((
unpacked_ptr
,
path
))
}
// FIXME: More checks for the vtable... making sure it is exactly
// the one one would expect for this type.
},
Some
(
ty
)
=>
bug!
(
"Unexpected fat pointer target type {:?}"
,
ty
),
None
=>
{
// Not a pointer, perform regular aggregate handling below
for
i
in
0
..
offsets
.len
()
{
let
mut
path
=
path
.clone
();
self
.dump_field_name
(
&
mut
path
,
dest
.layout.ty
,
i
,
variant
)
.unwrap
();
let
field
=
self
.mplace_field
(
dest
,
i
as
u64
)
?
;
self
.validate_mplace
(
field
,
path
,
seen
,
todo
)
?
;
}
// FIXME: For a TyStr, check that this is valid UTF-8.
},
}
Ok
(())
}
}
}
#[inline(always)]
#[inline(always)]
pub
fn
frame
(
&
self
)
->
&
Frame
<
'mir
,
'tcx
>
{
pub
fn
frame
(
&
self
)
->
&
Frame
<
'mir
,
'tcx
>
{
self
.stack
.last
()
.expect
(
"no call frames exist"
)
self
.stack
.last
()
.expect
(
"no call frames exist"
)
...
@@ -1041,72 +779,5 @@ pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
...
@@ -1041,72 +779,5 @@ pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
pub
fn
truncate
(
&
self
,
value
:
u128
,
ty
:
TyLayout
<
'_
>
)
->
u128
{
pub
fn
truncate
(
&
self
,
value
:
u128
,
ty
:
TyLayout
<
'_
>
)
->
u128
{
truncate
(
value
,
ty
.size
)
truncate
(
value
,
ty
.size
)
}
}
fn
dump_field_name
(
&
self
,
s
:
&
mut
String
,
ty
:
Ty
<
'tcx
>
,
i
:
usize
,
variant
:
usize
)
->
::
std
::
fmt
::
Result
{
match
ty
.sty
{
ty
::
TyBool
|
ty
::
TyChar
|
ty
::
TyInt
(
_
)
|
ty
::
TyUint
(
_
)
|
ty
::
TyFloat
(
_
)
|
ty
::
TyFnPtr
(
_
)
|
ty
::
TyNever
|
ty
::
TyFnDef
(
..
)
|
ty
::
TyGeneratorWitness
(
..
)
|
ty
::
TyForeign
(
..
)
|
ty
::
TyDynamic
(
..
)
=>
{
bug!
(
"field_name({:?}): not applicable"
,
ty
)
}
// Potentially-fat pointers.
ty
::
TyRef
(
_
,
pointee
,
_
)
|
ty
::
TyRawPtr
(
ty
::
TypeAndMut
{
ty
:
pointee
,
..
})
=>
{
assert
!
(
i
<
2
);
// Reuse the fat *T type as its own thin pointer data field.
// This provides information about e.g. DST struct pointees
// (which may have no non-DST form), and will work as long
// as the `Abi` or `FieldPlacement` is checked by users.
if
i
==
0
{
return
write!
(
s
,
".data_ptr"
);
}
match
self
.tcx
.struct_tail
(
pointee
)
.sty
{
ty
::
TySlice
(
_
)
|
ty
::
TyStr
=>
write!
(
s
,
".len"
),
ty
::
TyDynamic
(
..
)
=>
write!
(
s
,
".vtable_ptr"
),
_
=>
bug!
(
"field_name({:?}): not applicable"
,
ty
)
}
}
// Arrays and slices.
ty
::
TyArray
(
_
,
_
)
|
ty
::
TySlice
(
_
)
|
ty
::
TyStr
=>
write!
(
s
,
"[{}]"
,
i
),
// generators and closures.
ty
::
TyClosure
(
def_id
,
_
)
|
ty
::
TyGenerator
(
def_id
,
_
,
_
)
=>
{
let
node_id
=
self
.tcx.hir
.as_local_node_id
(
def_id
)
.unwrap
();
let
freevar
=
self
.tcx
.with_freevars
(
node_id
,
|
fv
|
fv
[
i
]);
write!
(
s
,
".upvar({})"
,
self
.tcx.hir
.name
(
freevar
.var_id
()))
}
ty
::
TyTuple
(
_
)
=>
write!
(
s
,
".{}"
,
i
),
// enums
ty
::
TyAdt
(
def
,
..
)
if
def
.is_enum
()
=>
{
let
variant
=
&
def
.variants
[
variant
];
write!
(
s
,
".{}::{}"
,
variant
.name
,
variant
.fields
[
i
]
.ident
)
}
// other ADTs.
ty
::
TyAdt
(
def
,
_
)
=>
write!
(
s
,
".{}"
,
def
.non_enum_variant
()
.fields
[
i
]
.ident
),
ty
::
TyProjection
(
_
)
|
ty
::
TyAnon
(
..
)
|
ty
::
TyParam
(
_
)
|
ty
::
TyInfer
(
_
)
|
ty
::
TyError
=>
{
bug!
(
"dump_field_name: unexpected type `{}`"
,
ty
)
}
}
}
}
}
src/librustc_mir/interpret/mod.rs
浏览文件 @
50999336
...
@@ -11,6 +11,7 @@
...
@@ -11,6 +11,7 @@
mod
terminator
;
mod
terminator
;
mod
traits
;
mod
traits
;
mod
const_eval
;
mod
const_eval
;
mod
validity
;
pub
use
self
::
eval_context
::{
pub
use
self
::
eval_context
::{
EvalContext
,
Frame
,
StackPopCleanup
,
LocalValue
,
EvalContext
,
Frame
,
StackPopCleanup
,
LocalValue
,
...
...
src/librustc_mir/interpret/validity.rs
0 → 100644
浏览文件 @
50999336
use
std
::
fmt
::
Write
;
use
rustc
::
ty
::
layout
::{
self
,
Size
,
Primitive
};
use
rustc
::
ty
::{
self
,
Ty
};
use
rustc_data_structures
::
fx
::
FxHashSet
;
use
rustc
::
mir
::
interpret
::{
Scalar
,
AllocType
,
EvalResult
,
ScalarMaybeUndef
,
};
use
super
::{
MPlaceTy
,
PlaceExtra
,
Machine
,
EvalContext
};
macro_rules!
validation_failure
{
(
$what:expr
,
$where:expr
,
$details:expr
)
=>
{{
let
where_
=
if
$where
.is_empty
()
{
String
::
new
()
}
else
{
format!
(
" at {}"
,
$where
)
};
err!
(
ValidationFailure
(
format!
(
"encountered {}{}, but expected {}"
,
$what
,
where_
,
$details
,
)))
}};
(
$what:expr
,
$where:expr
)
=>
{{
let
where_
=
if
$where
.is_empty
()
{
String
::
new
()
}
else
{
format!
(
" at {}"
,
$where
)
};
err!
(
ValidationFailure
(
format!
(
"encountered {}{}"
,
$what
,
where_
,
)))
}};
}
impl
<
'a
,
'mir
,
'tcx
,
M
:
Machine
<
'mir
,
'tcx
>>
EvalContext
<
'a
,
'mir
,
'tcx
,
M
>
{
fn
validate_scalar
(
&
self
,
value
:
ScalarMaybeUndef
,
size
:
Size
,
scalar
:
&
layout
::
Scalar
,
path
:
&
str
,
ty
:
Ty
,
)
->
EvalResult
<
'tcx
>
{
trace!
(
"validate scalar: {:#?}, {:#?}, {:#?}, {}"
,
value
,
size
,
scalar
,
ty
);
let
(
lo
,
hi
)
=
scalar
.valid_range
.clone
()
.into_inner
();
let
value
=
match
value
{
ScalarMaybeUndef
::
Scalar
(
scalar
)
=>
scalar
,
ScalarMaybeUndef
::
Undef
=>
return
validation_failure!
(
"undefined bytes"
,
path
),
};
let
bits
=
match
value
{
Scalar
::
Bits
{
bits
,
size
:
value_size
}
=>
{
assert_eq!
(
value_size
as
u64
,
size
.bytes
());
bits
},
Scalar
::
Ptr
(
_
)
=>
{
let
ptr_size
=
self
.memory
.pointer_size
();
let
ptr_max
=
u128
::
max_value
()
>>
(
128
-
ptr_size
.bits
());
return
if
lo
>
hi
{
if
lo
-
hi
==
1
{
// no gap, all values are ok
Ok
(())
}
else
if
hi
<
ptr_max
||
lo
>
1
{
let
max
=
u128
::
max_value
()
>>
(
128
-
size
.bits
());
validation_failure!
(
"pointer"
,
path
,
format!
(
"something in the range {:?} or {:?}"
,
0
..=
lo
,
hi
..=
max
)
)
}
else
{
Ok
(())
}
}
else
if
hi
<
ptr_max
||
lo
>
1
{
validation_failure!
(
"pointer"
,
path
,
format!
(
"something in the range {:?}"
,
scalar
.valid_range
)
)
}
else
{
Ok
(())
};
},
};
// char gets a special treatment, because its number space is not contiguous so `TyLayout`
// has no special checks for chars
match
ty
.sty
{
ty
::
TyChar
=>
{
debug_assert_eq!
(
size
.bytes
(),
4
);
if
::
std
::
char
::
from_u32
(
bits
as
u32
)
.is_none
()
{
return
err!
(
InvalidChar
(
bits
));
}
}
_
=>
{},
}
use
std
::
ops
::
RangeInclusive
;
let
in_range
=
|
bound
:
RangeInclusive
<
u128
>
|
bound
.contains
(
&
bits
);
if
lo
>
hi
{
if
in_range
(
0
..=
hi
)
||
in_range
(
lo
..=
u128
::
max_value
())
{
Ok
(())
}
else
{
validation_failure!
(
bits
,
path
,
format!
(
"something in the range {:?} or {:?}"
,
..=
hi
,
lo
..
)
)
}
}
else
{
if
in_range
(
scalar
.valid_range
.clone
())
{
Ok
(())
}
else
{
validation_failure!
(
bits
,
path
,
format!
(
"something in the range {:?}"
,
scalar
.valid_range
)
)
}
}
}
/// This function checks the memory where `ptr` points to.
/// It will error if the bits at the destination do not match the ones described by the layout.
pub
fn
validate_mplace
(
&
self
,
dest
:
MPlaceTy
<
'tcx
>
,
path
:
String
,
seen
:
&
mut
FxHashSet
<
(
MPlaceTy
<
'tcx
>
)
>
,
todo
:
&
mut
Vec
<
(
MPlaceTy
<
'tcx
>
,
String
)
>
,
)
->
EvalResult
<
'tcx
>
{
self
.memory
.dump_alloc
(
dest
.to_ptr
()
?
.alloc_id
);
trace!
(
"validate_mplace: {:?}, {:#?}"
,
*
dest
,
dest
.layout
);
// Find the right variant
let
(
variant
,
dest
)
=
match
dest
.layout.variants
{
layout
::
Variants
::
NicheFilling
{
niche
:
ref
tag
,
..
}
|
layout
::
Variants
::
Tagged
{
ref
tag
,
..
}
=>
{
let
size
=
tag
.value
.size
(
self
);
// we first read the tag value as scalar, to be able to validate it
let
tag_mplace
=
self
.mplace_field
(
dest
,
0
)
?
;
let
tag_value
=
self
.read_scalar
(
tag_mplace
.into
())
?
;
let
path
=
format!
(
"{}.TAG"
,
path
);
self
.validate_scalar
(
tag_value
,
size
,
tag
,
&
path
,
tag_mplace
.layout.ty
)
?
;
// then we read it again to get the index, to continue
let
variant
=
self
.read_discriminant_as_variant_index
(
dest
.into
())
?
;
let
dest
=
self
.mplace_downcast
(
dest
,
variant
)
?
;
trace!
(
"variant layout: {:#?}"
,
dest
.layout
);
(
variant
,
dest
)
},
layout
::
Variants
::
Single
{
index
}
=>
{
(
index
,
dest
)
}
};
// Validate all fields
match
dest
.layout.fields
{
// primitives are unions with zero fields
layout
::
FieldPlacement
::
Union
(
0
)
=>
{
match
dest
.layout.abi
{
// nothing to do, whatever the pointer points to, it is never going to be read
layout
::
Abi
::
Uninhabited
=>
validation_failure!
(
"a value of an uninhabited type"
,
path
),
// check that the scalar is a valid pointer or that its bit range matches the
// expectation.
layout
::
Abi
::
Scalar
(
ref
scalar_layout
)
=>
{
let
size
=
scalar_layout
.value
.size
(
self
);
let
value
=
self
.read_value
(
dest
.into
())
?
;
let
scalar
=
value
.to_scalar_or_undef
();
self
.validate_scalar
(
scalar
,
size
,
scalar_layout
,
&
path
,
dest
.layout.ty
)
?
;
if
scalar_layout
.value
==
Primitive
::
Pointer
{
// ignore integer pointers, we can't reason about the final hardware
if
let
Scalar
::
Ptr
(
ptr
)
=
scalar
.not_undef
()
?
{
let
alloc_kind
=
self
.tcx.alloc_map
.lock
()
.get
(
ptr
.alloc_id
);
if
let
Some
(
AllocType
::
Static
(
did
))
=
alloc_kind
{
// statics from other crates are already checked
// extern statics should not be validated as they have no body
if
!
did
.is_local
()
||
self
.tcx
.is_foreign_item
(
did
)
{
return
Ok
(());
}
}
if
value
.layout.ty
.builtin_deref
(
false
)
.is_some
()
{
trace!
(
"Recursing below ptr {:#?}"
,
value
);
let
ptr_place
=
self
.ref_to_mplace
(
value
)
?
;
// we have not encountered this pointer+layout combination before
if
seen
.insert
(
ptr_place
)
{
todo
.push
((
ptr_place
,
format!
(
"(*{})"
,
path
)))
}
}
}
}
Ok
(())
},
_
=>
bug!
(
"bad abi for FieldPlacement::Union(0): {:#?}"
,
dest
.layout.abi
),
}
}
layout
::
FieldPlacement
::
Union
(
_
)
=>
{
// We can't check unions, their bits are allowed to be anything.
// The fields don't need to correspond to any bit pattern of the union's fields.
// See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
Ok
(())
},
layout
::
FieldPlacement
::
Array
{
count
,
..
}
=>
{
for
i
in
0
..
count
{
let
mut
path
=
path
.clone
();
self
.dump_field_name
(
&
mut
path
,
dest
.layout.ty
,
i
as
usize
,
variant
)
.unwrap
();
let
field
=
self
.mplace_field
(
dest
,
i
)
?
;
self
.validate_mplace
(
field
,
path
,
seen
,
todo
)
?
;
}
Ok
(())
},
layout
::
FieldPlacement
::
Arbitrary
{
ref
offsets
,
..
}
=>
{
// fat pointers need special treatment
match
dest
.layout.ty
.builtin_deref
(
false
)
.map
(|
tam
|
&
tam
.ty.sty
)
{
|
Some
(
ty
::
TyStr
)
|
Some
(
ty
::
TySlice
(
_
))
=>
{
// check the length (for nicer error messages)
let
len_mplace
=
self
.mplace_field
(
dest
,
1
)
?
;
let
len
=
self
.read_scalar
(
len_mplace
.into
())
?
;
let
len
=
match
len
.to_bits
(
len_mplace
.layout.size
)
{
Err
(
_
)
=>
return
validation_failure!
(
"length is not a valid integer"
,
path
),
Ok
(
len
)
=>
len
as
u64
,
};
// get the fat ptr, and recursively check it
let
ptr
=
self
.ref_to_mplace
(
self
.read_value
(
dest
.into
())
?
)
?
;
assert_eq!
(
ptr
.extra
,
PlaceExtra
::
Length
(
len
));
let
unpacked_ptr
=
self
.unpack_unsized_mplace
(
ptr
)
?
;
if
seen
.insert
(
unpacked_ptr
)
{
let
mut
path
=
path
.clone
();
self
.dump_field_name
(
&
mut
path
,
dest
.layout.ty
,
0
,
0
)
.unwrap
();
todo
.push
((
unpacked_ptr
,
path
))
}
},
Some
(
ty
::
TyDynamic
(
..
))
=>
{
// check the vtable (for nicer error messages)
let
vtable
=
self
.read_scalar
(
self
.mplace_field
(
dest
,
1
)
?
.into
())
?
;
let
vtable
=
match
vtable
.to_ptr
()
{
Err
(
_
)
=>
return
validation_failure!
(
"vtable address is not a pointer"
,
path
),
Ok
(
vtable
)
=>
vtable
,
};
// get the fat ptr, and recursively check it
let
ptr
=
self
.ref_to_mplace
(
self
.read_value
(
dest
.into
())
?
)
?
;
assert_eq!
(
ptr
.extra
,
PlaceExtra
::
Vtable
(
vtable
));
let
unpacked_ptr
=
self
.unpack_unsized_mplace
(
ptr
)
?
;
if
seen
.insert
(
unpacked_ptr
)
{
let
mut
path
=
path
.clone
();
self
.dump_field_name
(
&
mut
path
,
dest
.layout.ty
,
0
,
0
)
.unwrap
();
todo
.push
((
unpacked_ptr
,
path
))
}
// FIXME: More checks for the vtable... making sure it is exactly
// the one one would expect for this type.
},
Some
(
ty
)
=>
bug!
(
"Unexpected fat pointer target type {:?}"
,
ty
),
None
=>
{
// Not a pointer, perform regular aggregate handling below
for
i
in
0
..
offsets
.len
()
{
let
mut
path
=
path
.clone
();
self
.dump_field_name
(
&
mut
path
,
dest
.layout.ty
,
i
,
variant
)
.unwrap
();
let
field
=
self
.mplace_field
(
dest
,
i
as
u64
)
?
;
self
.validate_mplace
(
field
,
path
,
seen
,
todo
)
?
;
}
// FIXME: For a TyStr, check that this is valid UTF-8.
},
}
Ok
(())
}
}
}
fn
dump_field_name
(
&
self
,
s
:
&
mut
String
,
ty
:
Ty
<
'tcx
>
,
i
:
usize
,
variant
:
usize
)
->
::
std
::
fmt
::
Result
{
match
ty
.sty
{
ty
::
TyBool
|
ty
::
TyChar
|
ty
::
TyInt
(
_
)
|
ty
::
TyUint
(
_
)
|
ty
::
TyFloat
(
_
)
|
ty
::
TyFnPtr
(
_
)
|
ty
::
TyNever
|
ty
::
TyFnDef
(
..
)
|
ty
::
TyGeneratorWitness
(
..
)
|
ty
::
TyForeign
(
..
)
|
ty
::
TyDynamic
(
..
)
=>
{
bug!
(
"field_name({:?}): not applicable"
,
ty
)
}
// Potentially-fat pointers.
ty
::
TyRef
(
_
,
pointee
,
_
)
|
ty
::
TyRawPtr
(
ty
::
TypeAndMut
{
ty
:
pointee
,
..
})
=>
{
assert
!
(
i
<
2
);
// Reuse the fat *T type as its own thin pointer data field.
// This provides information about e.g. DST struct pointees
// (which may have no non-DST form), and will work as long
// as the `Abi` or `FieldPlacement` is checked by users.
if
i
==
0
{
return
write!
(
s
,
".data_ptr"
);
}
match
self
.tcx
.struct_tail
(
pointee
)
.sty
{
ty
::
TySlice
(
_
)
|
ty
::
TyStr
=>
write!
(
s
,
".len"
),
ty
::
TyDynamic
(
..
)
=>
write!
(
s
,
".vtable_ptr"
),
_
=>
bug!
(
"field_name({:?}): not applicable"
,
ty
)
}
}
// Arrays and slices.
ty
::
TyArray
(
_
,
_
)
|
ty
::
TySlice
(
_
)
|
ty
::
TyStr
=>
write!
(
s
,
"[{}]"
,
i
),
// generators and closures.
ty
::
TyClosure
(
def_id
,
_
)
|
ty
::
TyGenerator
(
def_id
,
_
,
_
)
=>
{
let
node_id
=
self
.tcx.hir
.as_local_node_id
(
def_id
)
.unwrap
();
let
freevar
=
self
.tcx
.with_freevars
(
node_id
,
|
fv
|
fv
[
i
]);
write!
(
s
,
".upvar({})"
,
self
.tcx.hir
.name
(
freevar
.var_id
()))
}
ty
::
TyTuple
(
_
)
=>
write!
(
s
,
".{}"
,
i
),
// enums
ty
::
TyAdt
(
def
,
..
)
if
def
.is_enum
()
=>
{
let
variant
=
&
def
.variants
[
variant
];
write!
(
s
,
".{}::{}"
,
variant
.name
,
variant
.fields
[
i
]
.ident
)
}
// other ADTs.
ty
::
TyAdt
(
def
,
_
)
=>
write!
(
s
,
".{}"
,
def
.non_enum_variant
()
.fields
[
i
]
.ident
),
ty
::
TyProjection
(
_
)
|
ty
::
TyAnon
(
..
)
|
ty
::
TyParam
(
_
)
|
ty
::
TyInfer
(
_
)
|
ty
::
TyError
=>
{
bug!
(
"dump_field_name: unexpected type `{}`"
,
ty
)
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录