-
Notifications
You must be signed in to change notification settings - Fork 82
Sync from rust 2025/06/02 #694
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
Conversation
- Rename `USED` to `USED_COMPILER` to better reflect its behavior. - Reorder some items to group the used and allocator flags together - Renumber them without gaps
There is no safety contract and I don't think any of them can actually cause UB in more ways than passing malicious source code to rustc can. While LtoModuleCodegen::optimize says that the returned ModuleCodegen points into the LTO module, the LTO module has already been dropped by the time this function returns, so if the returned ModuleCodegen indeed points into the LTO module, we would have seen crashes on every LTO compilation, which we don't. As such the comment is outdated.
atomic_load intrinsic: use const generic parameter for ordering We have a gazillion intrinsics for the atomics because we encode the ordering into the intrinsic name rather than making it a parameter. This is particularly bad for those operations that take two orderings. Let's fix that! This PR only converts `load`, to see if there's any feedback that would fundamentally change the strategy we pursue for the const generic intrinsics. The first two commits are preparation and could be a separate PR if you prefer. `@BoxyUwU` -- I hope this is a use of const generics that is unlikely to explode? All we need is a const generic of enum type. We could funnel it through an integer if we had to but an enum is obviously nicer... `@bjorn3` it seems like the cranelift backend entirely ignores the ordering?
This avoids having to get the function signature.
Out of curiosity: could I help with this, somehow? |
Yes, if you are interested in debugging this. My hunch was that the first issue to fix is related to this hack. |
Reduced #![feature(core_intrinsics)]
extern crate core;
pub const fn u32_type_name() -> &'static str {
core::intrinsics::type_name::<u32>()
}
fn main() {
let s = u32_type_name();
assert!(s.len() < 100, "{}",s.len());
} The assert will fail with a garbage length.
Calling the intrinsic directly works fine, as does building with MIR opt level=2. Seems like if this function gets inlined, everything works out fine. Maybe an ABI bug? EDIT: the slice in question usually points to invalid memory, so both elements seem corrupted. Here is the GIMPLE of __attribute__((visibility ("default")))
struct struct u32_type_name ()
{
struct struct D.4023;
struct struct undefined;
size_t loadedValue3;
signed char * loadedValue2;
struct struct undefined;
signed char stack_var_1[16];
try
{
start:
undefined.field0_TODO = &global.11;
undefined.field1_TODO = 3;
stack_var_1.7_1 = &stack_var_1;
MEM[(struct struct * *)stack_var_1.7_1] = &undefined;
stack_var_1.8_2 = &stack_var_1;
loadedValue2 = MEM[(signed char * *)stack_var_1.8_2];
_3 = &stack_var_1 + 8;
loadedValue3 = MEM[(size_t *)_3];
undefined.field0_TODO = loadedValue2;
undefined.field1_TODO = loadedValue3;
D.4023 = undefined;
return D.4023;
}
finally
{
undefined = {CLOBBER(eos)};
undefined = {CLOBBER(eos)};
stack_var_1 = {CLOBBER(eos)};
}
} And here is the working version, which seems to be considerably longer. __attribute__((visibility ("default")))
struct struct u32_type_name ()
{
struct struct D.4022;
struct struct undefined;
size_t loadedValue3;
signed char * loadedValue2;
struct struct undefined;
signed char stack_var_1[16];
try
{
start:
undefined.field0_TODO = &global.11;
undefined.field1_TODO = 3;
stack_var_1.7_1 = &stack_var_1;
_2 = undefined.field0_TODO;
MEM[(signed char * *)stack_var_1.7_1] = _2;
_3 = &stack_var_1 + 8;
_4 = undefined.field1_TODO;
MEM[(size_t *)_3] = _4;
stack_var_1.8_5 = &stack_var_1;
loadedValue2 = MEM[(signed char * *)stack_var_1.8_5];
_6 = &stack_var_1 + 8;
loadedValue3 = MEM[(size_t *)_6];
undefined.field0_TODO = loadedValue2;
undefined.field1_TODO = loadedValue3;
D.4022 = undefined;
return D.4022;
}
finally
{
undefined = {CLOBBER(eos)};
undefined = {CLOBBER(eos)};
stack_var_1 = {CLOBBER(eos)};
}
} |
I think I understand the issue now... at least partially. If we count memory reads / writes, we'll see an interesting difference. In the new version, we perform 1 write of type We also... copy the pointer to the structure, instead of the structure itself, for some reason? undefined.field1_TODO = 3;
stack_var_1.7_1 = &stack_var_1;
MEM[(struct struct * *)stack_var_1.7_1] = &undefined;
stack_var_1.8_2 = &stack_var_1;
loadedValue2 = MEM[(signed char * *)stack_var_1.8_2];
_3 = &stack_var_1 + 8;
loadedValue3 = MEM[(size_t *)_3];
undefined.field0_TODO = loadedValue2;
undefined.field1_TODO = loadedValue3; The old code performed 2 writes, 2 reads. It copied both the metadata and the data pointer. stack_var_1.7_1 = &stack_var_1;
_2 = undefined.field0_TODO;
MEM[(signed char * *)stack_var_1.7_1] = _2;
_3 = &stack_var_1 + 8;
_4 = undefined.field1_TODO;
MEM[(size_t *)_3] = _4;
stack_var_1.8_5 = &stack_var_1;
loadedValue2 = MEM[(signed char * *)stack_var_1.8_5];
_6 = &stack_var_1 + 8;
loadedValue3 = MEM[(size_t *)_6]; My guess here is this: the write was supposed to be of type I don't yet know why this is broken, but at least I know what is broken. |
Yeah, this is also what I observed. All of this is very brittle, which is why I would want to fix cg_ssa to remove this hack at some point in the future. |
What does |
Why is it creating a local var? Should it not create a constant instead? |
In GCC, we can only assign to an |
The doc-comment on this function mentions:
|
I was more so speaking about what it does on LLVM level, and what does Rustc expect from it. What type is it supposed to return(pointer to a value or a value?), etc. Now I understand. We are trying to replicate: %2 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0, !dbg !241
%3 = insertvalue { ptr, i64 } %2, i64 %_0.1, 1, !dbg !241 In GCC. However, we cant do so, because we cant add a field to poison, in |
I am having a bit of a bad(?) idea. Could we first try syncing to an ealier version of nightly, just to see at what point things broke? We know that something went wrong between At that point, we'd know something broke at a certain day, and have an easier time figuring out what went wrong. We would only have a day or so of changes to comb trough. @antoyo if I managed to sync to an earlier date(for example, |
Yes, I would be down to merge that. The instructions for that can be found here. |
Those instructions don't work for me anymore: I can't build the patched version of git. // in builtin/index-pack.c
struct thread_local {
pthread_t thread;
struct base_data *base_cache;
size_t base_cache_used;
int pack_fd;
}; https://www.gnu.org/software/libc/manual/html_node/ISO-C-Thread_002dlocal-Storage.html EDIT: unrechable is not a valid function name: static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid) I will work around this, but I thought I will warn you that this may become an issue with future syncs. |
It seems like bjorn might have a forked of git as well: https://github.com/rust-lang/rustc_codegen_cranelift/blob/b2cafc96ec61a2bfa43caf1ef68be0cc348e9140/scripts/rustup.sh#L10 |
@FractalFir: I believe I found a fix and should be able to merge this PR soon. |
TODO: