Skip to content

Commit 16d791b

Browse files
committed
Auto merge of #825 - RalfJung:no-null, r=RalfJung
avoid Scalar::is_null_ptr, it is going away Comparing pointers should be done more carefully than that
2 parents 3525943 + 698b311 commit 16d791b

File tree

3 files changed

+55
-35
lines changed

3 files changed

+55
-35
lines changed

src/helpers.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
4343
})
4444
}
4545

46+
/// Write a 0 of the appropriate size to `dest`.
47+
fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
48+
self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
49+
}
50+
51+
/// Test if this immediate equals 0.
52+
fn is_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, bool> {
53+
let this = self.eval_context_ref();
54+
let null = Scalar::from_int(0, this.memory().pointer_size());
55+
this.ptr_eq(val, null)
56+
}
57+
58+
/// Turn a Scalar into an Option<NonNullScalar>
59+
fn test_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, Option<Scalar<Tag>>> {
60+
let this = self.eval_context_ref();
61+
Ok(if this.is_null(val)? {
62+
None
63+
} else {
64+
Some(val)
65+
})
66+
}
67+
4668
/// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter
4769
/// will be true if this is frozen, false if this is in an `UnsafeCell`.
4870
fn visit_freeze_sensitive(

src/shims/foreign_items.rs

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
4949
ptr: Scalar<Tag>,
5050
) -> InterpResult<'tcx> {
5151
let this = self.eval_context_mut();
52-
if !ptr.is_null_ptr(this) {
52+
if !this.is_null(ptr)? {
5353
this.memory_mut().deallocate(
5454
ptr.to_ptr()?,
5555
None,
@@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
6666
) -> InterpResult<'tcx, Scalar<Tag>> {
6767
let this = self.eval_context_mut();
6868
let align = this.min_align();
69-
if old_ptr.is_null_ptr(this) {
69+
if this.is_null(old_ptr)? {
7070
if new_size == 0 {
7171
Ok(Scalar::from_int(0, this.pointer_size()))
7272
} else {
@@ -427,7 +427,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
427427
let mut success = None;
428428
{
429429
let name_ptr = this.read_scalar(args[0])?.not_undef()?;
430-
if !name_ptr.is_null_ptr(this) {
430+
if !this.is_null(name_ptr)? {
431431
let name_ptr = name_ptr.to_ptr()?;
432432
let name = this
433433
.memory()
@@ -455,7 +455,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
455455
let name_ptr = this.read_scalar(args[0])?.not_undef()?;
456456
let value_ptr = this.read_scalar(args[1])?.to_ptr()?;
457457
let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?;
458-
if !name_ptr.is_null_ptr(this) {
458+
if !this.is_null(name_ptr)? {
459459
let name_ptr = name_ptr.to_ptr()?;
460460
let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
461461
if !name.is_empty() && !name.contains(&b'=') {
@@ -638,14 +638,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
638638
let key_ptr = this.read_scalar(args[0])?.not_undef()?;
639639

640640
// Extract the function type out of the signature (that seems easier than constructing it ourselves).
641-
let dtor = match this.read_scalar(args[1])?.not_undef()? {
642-
Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?),
643-
Scalar::Raw { data: 0, size } => {
644-
// NULL pointer
645-
assert_eq!(size as u64, this.memory().pointer_size().bytes());
646-
None
647-
},
648-
Scalar::Raw { .. } => return err!(ReadBytesAsPointer),
641+
let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? {
642+
Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr.to_ptr()?)?),
643+
None => None,
649644
};
650645

651646
// Figure out how large a pthread TLS key actually is.
@@ -657,7 +652,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
657652
let key_layout = this.layout_of(key_type)?;
658653

659654
// Create key and write it into the memory where `key_ptr` wants it.
660-
let key = this.machine.tls.create_tls_key(dtor, tcx) as u128;
655+
let key = this.machine.tls.create_tls_key(dtor) as u128;
661656
if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
662657
return err!(OutOfTls);
663658
}
@@ -682,13 +677,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
682677
}
683678
"pthread_getspecific" => {
684679
let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
685-
let ptr = this.machine.tls.load_tls(key)?;
680+
let ptr = this.machine.tls.load_tls(key, tcx)?;
686681
this.write_scalar(ptr, dest)?;
687682
}
688683
"pthread_setspecific" => {
689684
let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
690685
let new_ptr = this.read_scalar(args[1])?.not_undef()?;
691-
this.machine.tls.store_tls(key, new_ptr)?;
686+
this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;
692687

693688
// Return success (`0`).
694689
this.write_null(dest)?;
@@ -842,7 +837,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
842837
// This just creates a key; Windows does not natively support TLS destructors.
843838

844839
// Create key and return it.
845-
let key = this.machine.tls.create_tls_key(None, tcx) as u128;
840+
let key = this.machine.tls.create_tls_key(None) as u128;
846841

847842
// Figure out how large a TLS key actually is. This is `c::DWORD`.
848843
if dest.layout.size.bits() < 128
@@ -853,13 +848,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
853848
}
854849
"TlsGetValue" => {
855850
let key = this.read_scalar(args[0])?.to_u32()? as u128;
856-
let ptr = this.machine.tls.load_tls(key)?;
851+
let ptr = this.machine.tls.load_tls(key, tcx)?;
857852
this.write_scalar(ptr, dest)?;
858853
}
859854
"TlsSetValue" => {
860855
let key = this.read_scalar(args[0])?.to_u32()? as u128;
861856
let new_ptr = this.read_scalar(args[1])?.not_undef()?;
862-
this.machine.tls.store_tls(key, new_ptr)?;
857+
this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;
863858

864859
// Return success (`1`).
865860
this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
@@ -936,10 +931,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
936931
Ok(())
937932
}
938933

939-
fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
940-
self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
941-
}
942-
943934
/// Evaluates the scalar at the specified path. Returns Some(val)
944935
/// if the path could be resolved, and None otherwise
945936
fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option<ScalarMaybeUndef<Tag>>> {

src/shims/tls.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ use rustc::{ty, ty::layout::HasDataLayout, mir};
66
use crate::{
77
InterpResult, InterpError, StackPopCleanup,
88
MPlaceTy, Scalar, Tag,
9+
HelpersEvalContextExt,
910
};
1011

1112
pub type TlsKey = u128;
1213

1314
#[derive(Copy, Clone, Debug)]
1415
pub struct TlsEntry<'tcx> {
15-
pub(crate) data: Scalar<Tag>, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread.
16+
/// The data for this key. None is used to represent NULL.
17+
/// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.)
18+
/// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread.
19+
pub(crate) data: Option<Scalar<Tag>>,
1620
pub(crate) dtor: Option<ty::Instance<'tcx>>,
1721
}
1822

@@ -38,14 +42,13 @@ impl<'tcx> TlsData<'tcx> {
3842
pub fn create_tls_key(
3943
&mut self,
4044
dtor: Option<ty::Instance<'tcx>>,
41-
cx: &impl HasDataLayout,
4245
) -> TlsKey {
4346
let new_key = self.next_key;
4447
self.next_key += 1;
4548
self.keys.insert(
4649
new_key,
4750
TlsEntry {
48-
data: Scalar::ptr_null(cx).into(),
51+
data: None,
4952
dtor,
5053
},
5154
);
@@ -63,17 +66,21 @@ impl<'tcx> TlsData<'tcx> {
6366
}
6467
}
6568

66-
pub fn load_tls(&mut self, key: TlsKey) -> InterpResult<'tcx, Scalar<Tag>> {
69+
pub fn load_tls(
70+
&mut self,
71+
key: TlsKey,
72+
cx: &impl HasDataLayout,
73+
) -> InterpResult<'tcx, Scalar<Tag>> {
6774
match self.keys.get(&key) {
6875
Some(&TlsEntry { data, .. }) => {
6976
trace!("TLS key {} loaded: {:?}", key, data);
70-
Ok(data)
77+
Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into()))
7178
}
7279
None => err!(TlsOutOfBounds),
7380
}
7481
}
7582

76-
pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar<Tag>) -> InterpResult<'tcx> {
83+
pub fn store_tls(&mut self, key: TlsKey, new_data: Option<Scalar<Tag>>) -> InterpResult<'tcx> {
7784
match self.keys.get_mut(&key) {
7885
Some(&mut TlsEntry { ref mut data, .. }) => {
7986
trace!("TLS key {} stored: {:?}", key, new_data);
@@ -105,7 +112,6 @@ impl<'tcx> TlsData<'tcx> {
105112
fn fetch_tls_dtor(
106113
&mut self,
107114
key: Option<TlsKey>,
108-
cx: &impl HasDataLayout,
109115
) -> Option<(ty::Instance<'tcx>, Scalar<Tag>, TlsKey)> {
110116
use std::collections::Bound::*;
111117

@@ -117,10 +123,10 @@ impl<'tcx> TlsData<'tcx> {
117123
for (&key, &mut TlsEntry { ref mut data, dtor }) in
118124
thread_local.range_mut((start, Unbounded))
119125
{
120-
if !data.is_null_ptr(cx) {
126+
if let Some(data_scalar) = *data {
121127
if let Some(dtor) = dtor {
122-
let ret = Some((dtor, *data, key));
123-
*data = Scalar::ptr_null(cx);
128+
let ret = Some((dtor, data_scalar, key));
129+
*data = None;
124130
return ret;
125131
}
126132
}
@@ -133,10 +139,11 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc
133139
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
134140
fn run_tls_dtors(&mut self) -> InterpResult<'tcx> {
135141
let this = self.eval_context_mut();
136-
let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx);
142+
let mut dtor = this.machine.tls.fetch_tls_dtor(None);
137143
// FIXME: replace loop by some structure that works with stepping
138144
while let Some((instance, ptr, key)) = dtor {
139145
trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
146+
assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!");
140147
// TODO: Potentially, this has to support all the other possible instances?
141148
// See eval_fn_call in interpret/terminator/mod.rs
142149
let mir = this.load_mir(instance.def)?;
@@ -157,9 +164,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
157164
// step until out of stackframes
158165
this.run()?;
159166

160-
dtor = match this.machine.tls.fetch_tls_dtor(Some(key), &*this.tcx) {
167+
dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) {
161168
dtor @ Some(_) => dtor,
162-
None => this.machine.tls.fetch_tls_dtor(None, &*this.tcx),
169+
None => this.machine.tls.fetch_tls_dtor(None),
163170
};
164171
}
165172
// FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.

0 commit comments

Comments
 (0)