Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stacked Borrows: Raw pointers inhibit optimizations? #263

Closed
chorman0773 opened this issue Dec 5, 2020 · 5 comments
Closed

Stacked Borrows: Raw pointers inhibit optimizations? #263

chorman0773 opened this issue Dec 5, 2020 · 5 comments

Comments

@chorman0773
Copy link
Contributor

On #181 when discussing whether or not provenance destroying operations can be elided, I brought this code up

extern"C"{
pub fn does_something(param: *mut usize);
}
#[repr(C)]
struct Interesting{
    array: [usize;1], // prevents *pointer-interconvertibility* trick under lccc's model
    exclusive_access: *mut ()
};

pub fn do_interesting_things(ptr: &mut Interesting){
    let x = ptr.exclusive_access;
    does_something(&mut ptr.array[0]);
    ptr.exclusive_access =x;
}

For which the corresponding rust code would seem to rule out load-store elimination on ptr.exclusive_access

pub unsafe extern"C" fn does_something(ptr: *mut usize){
     let ptr = std::transmute(std::transmute<usize>(ptr)) as *mut Interesting;
     (*ptr).exclusive_access = ptr as *mut ();
}

While I was told that this code doesn't, replacing the first function with

pub fn do_interesting_things(ptr: &mut Interesting) {
    let x = ptr.exclusive_access;
    let y = &mut ptr.exclusive_access as *mut _;
    does_something(&mut ptr.array[0]);
    ptr.exclusive_access = x;
}

This seems odd to me. The fact that y is created by do_interesting_things inhibits optimizations accross the black-box does_something, even though does_something never recieves it, seems quite a bit off to me. In contrast, this is not permitted by C or C++, at all (if we replace the &mut in ptr with either Interesting* restrict in C, or an analogous compiler-specific extension in C++, to exclude aliasing access on entry to do_interesting_things).

In my head, pointers are pointers, reguardless of form (noting that references are pointers). It shouldn't be possible to use a pointer that was never recieved by a particular function to validate an operation in that function. This is particularily annoying because its clear through simple data-flow analysis that y never reaches does_something, yet it's mere existance is what invalidates the reasoning that ptr.exclusive_access is not modified.

If this is the case, this is a serious concern of mine, the pointer model in lccc would not permit this, and it is desired that this be the case, but it is intended to permit a superset of operations that Stacked Borrows does (A superset, because some operations that are permitted by C and C++ aren't by stacked borrows presently, one such operation is actually discussed in #256).

@bjorn3
Copy link
Member

bjorn3 commented Dec 5, 2020

You are converting a pointer to an integer. This makes it valid for all integers converted to pointers to write to the same memory as the pointer. This means that it is completely valid for does_something to get the address of ptr.exclusive_access from somewhere and then write to it. This rule exists as it is practically impossible to track the provenance of all pointers casted to integers. I think LLVM does the same.

@bjorn3
Copy link
Member

bjorn3 commented Dec 5, 2020

From https://sf.snu.ac.kr/llvmtwin/:

The model we showed in the previous section does not support low-level language features like integer to pointer casts. To support this functionality, we can extend integers with provenance information:
[...]
A drawback of this model—fatal in practice—is that it blocks many integer optimizations, such as propagation of equalities as done by, e.g., global value numbering (GVN) or range analysis. For example, transforming “(a == b) ? a : b” into “b” is incorrect in this model: even if two integer variables compare equal, they may still have different provenances. We give a more complete example to demonstrate the problem:
[...]
In fact, a transformation similar to this one performed by GVN was responsible for miscompiling the Rust code shown in Appendix B.

I strongly advice you to read the complete paper.

@chorman0773
Copy link
Contributor Author

chorman0773 commented Dec 5, 2020

You are converting a pointer to an integer.

Notably, I am not converting the pointer ptr.exclusive_access to an integer, it's a pointer to ptr.array[0], which, under both stacked borrows (currently) and lccc's model (which additionally permits access to ptr.array, but not *ptr, as pointer-interconvertibility stops at arrays), cannot access ptr.exclusive_access. If the pointer to ptr.exclusive_access (or ptr itself, or ptr.array on lccc) was converted to an integer, that would be a valid argument, especially wherever the ptr->int->ptr round trip is defined.

@bjorn3
Copy link
Member

bjorn3 commented Dec 5, 2020

I think this could be #248.

@chorman0773
Copy link
Contributor Author

Ah yeah, you would be right (closed because of the duplication).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants