Skip to content

Added some sanity checks to function call compilation. This will catch *some* cases of ABI mismatch. #715

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

FractalFir
Copy link
Contributor

@FractalFir FractalFir commented Jun 18, 2025

This PR introduces 2 changes:

  1. The function known_eq is a fallible form of equality. known_eq does not suffer from the issues the current implementation of Eq suffers from(sometimes, a float would be compared as uneqal to float simply because the pointer was different). known_eq reimplements some of that logic by itself, returning Some(true) if and only if types are known to be equal, and Some(false) if and only if it is known that the types can't be possibly equal.

  2. This is later used in a sanity check in Builder::check_ptr_call. Instead of checking if both types are / are not vectors, it will check if they are "known to be unequal". So, it will also painc if this code path is taken with types struct and pointer(ABI mismatch) but will still allow primitive types to pass trough. Since we only panic if the types are not vectors, and are known to be uneqal, this will effectively only catch ABI issues.

This change allows us to catch ABI bugs like #711 on the cg_gcc side, giving us a proper backtrace, and more detalied information about the bug(the types in play, the argument), and allowing us to use a debuger to see exactly what went wrong.

@FractalFir FractalFir force-pushed the master branch 3 times, most recently from 6c97dd7 to f14745c Compare June 18, 2025 22:50
Copy link
Contributor

@antoyo antoyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some questions.

src/common.rs Outdated
if !other.is_vector() {
return Some(false);
}
return None;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it would be worth it to check the sizes match?
We can probably do it with get_element_type() and get_num_units()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth checking. Will add now.

let Some(other_ptr) = other.get_pointee() else {
return Some(false);
};
return s_ptr.known_eq(&other_ptr, cx);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it doesn't matter much since there's a check for pointers in the assert in the other file, but is this the expected behavior to check if the pointee types are equal since we can bitcast pointers of different types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code path calling this funcition in the assert should not be hit by pointers at all - it is meant to bitcast vectors.

The idea behind known_eq is to serve as a saner replacement for the current Eq implementation of Type.

As we discussed before, comparing Types / Rvalues on the libgccjit side is quite hard to do, and would require a lot of code to be added.

Here, I am seeing if I could possibly work around that issue, by doing some of that comparison logic on the Rust side.

Really, I am trying to see if I could implement the functions we require entirely on the Rust side, subverting the limitations of the GCC API.

One thing I am considering attempting is field-vise comparison of structs(so that structs with identical elements compare as equal).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be quite useful for our constant deduplication code. Since my last attempt at fixing that leak introduces non-determinism to the compiler, we will have to revert and replace that.

At one point, I suggested we compare the types of Rvalues before comparing them using string formatting.

I was told that will not work because we can't reliably compare types. known_eq solves that problem(once I get struct comparisons working). If 2 rvalues have different types, we know they can't be equal, so we don't do the string-based comparison.

I belive this would remove most of that memory leak in a sound and reliable way. I have other ways to aleviate that issue, but this will be the most impactfull.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still believe that using that using global_set_initializer() would be better than this approach. Was there any reason it would not work?

Also, I would be very wary of a struct comparison done like that: we need to take some attributes into account like packed and possibly some others: I much prefer to let that job to the gcc backend even though I'm not sure right now how that could work since it would involve the target part of the compiler.

Copy link
Contributor Author

@FractalFir FractalFir Jun 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global_set_initializer(and globlal_set_initialized_rvalue) required globals to have unique names, and I think that messed with the string-based comparisons. I also belive could not get it to ever run right - global_set_initializer always errored out when I used it. I belive that was caused by some kind of type issue - it always complained about the type of the global and the type of the initializer rvalue being different. Maybe this is related to us calling get_aligned needlessly.

Also, I would be very wary of a struct comparison done like that: we need to take some attributes into account like packed and possibly some others: I much prefer to let that job to the gcc backend even though I'm not sure right now how that could work since it would involve the target part of the compiler.

Which is why known_eq will not return Some(true) for structs(at least for now). For structs, the current version only allows us to check that structs are unequal which is fine for our purposes.

Overall, the idea is for known_eq to return Some(true) if and only if the types are guaranteed to be equal, and return Some(false) if we can show that they are not equal.

For the global de-duplication, this comparison is simply an optimization. All it does skip the more costly comparison if we know for sure it will return false.

Additionally, for our purposes, catching most of the cases where types are not equal is already good enough.

If a sanity check can catch 99.9% of issues early, then it is worth it in my book.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also global_set_initializer will not help us with deduplication, at all. We will still have to manage the lvalues by ourselves, and deduplicate them ourselves.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also global_set_initializer will not help us with deduplication, at all.

Oh, sorry: I was mixing things up with the reduction of the memory usage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global_set_initializer(and globlal_set_initialized_rvalue) required globals to have unique names, and I think that messed with the string-based comparisons. I also belive could not get it to ever run right - global_set_initializer always errored out when I used it. I belive that was caused by some kind of type issue - it always complained about the type of the global and the type of the initializer rvalue being different. Maybe this is related to us calling get_aligned needlessly.

Please tell me if a fix to libgccjit related to global_set_initializer would help you with your fix the reduce the memory usage (e.g. remove the non-determinism). I could take a look.

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

Successfully merging this pull request may close these issues.

2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy