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

Eq for Bytes returns true for unequal Bytes #4868

Open
segfault-magnet opened this issue Jul 26, 2023 · 10 comments
Open

Eq for Bytes returns true for unequal Bytes #4868

segfault-magnet opened this issue Jul 26, 2023 · 10 comments
Labels
bug Something isn't working compiler General compiler. Should eventually become more specific as the issue is triaged P: critical Should be looked at before anything else

Comments

@segfault-magnet
Copy link
Contributor

Minimal example here: https://github.com/segfault-magnet/sway_bytes_eq_bug

script;

use std::string::String;
use std::assert::assert_eq;

fn main() {
    let string_a = String::from_ascii_str("Hello World");
    assert_eq(string_a.as_bytes().len(), 11);

    let string_b = String::from_ascii_str("NoNoNo");
    assert_eq(string_b.as_bytes().len(), 6);

    // Should not pass but it does
    assert_eq(string_a.as_bytes(), string_b.as_bytes());
}

forc build && cargo test

Tested on forc 0.42.1 and fuel-core 0.19

@IGI-111 IGI-111 added bug Something isn't working lib: std Standard library labels Jul 26, 2023
@Braqzen
Copy link
Contributor

Braqzen commented Jul 26, 2023

Could you add

assert(string_a.as_bytes() == string_b.as_bytes());

above the last line to see if that fails?

@bitzoic
Copy link
Member

bitzoic commented Jul 26, 2023

Could you add
assert(string_a.as_bytes() == string_b.as_bytes());
above the last line to see if that fails?

This fails. Seems like there might be a problem with the assert_eq function

@Braqzen
Copy link
Contributor

Braqzen commented Jul 26, 2023

Could you add
assert(string_a.as_bytes() == string_b.as_bytes());
above the last line to see if that fails?

This fails. Seems like there might be a problem with the assert_eq function

If that also fails then it's the Eq, no? Or do you mean that it passes and hence it's the assert_eq?

@IGI-111
Copy link
Contributor

IGI-111 commented Jul 26, 2023

If __eq returns the right result then it's definitely a problem with std and the trait implementation for Bytes specifically.

@Braqzen
Copy link
Contributor

Braqzen commented Jul 26, 2023

If __eq returns the right result then it's definitely a problem with std and the trait implementation for Bytes specifically.

We check the length first which seems to work everywhere else

impl core::ops::Eq for Bytes {
fn eq(self, other: Self) -> bool {
if self.len != other.len {
return false;
}
asm(result, r2: self.buf.ptr, r3: other.buf.ptr, r4: self.len) {
meq result r2 r3 r4;
result: bool
}
}
}

@IGI-111
Copy link
Contributor

IGI-111 commented Jul 26, 2023

Maybe the length is set wrong? Like zero or something?

@segfault-magnet
Copy link
Contributor Author

    let string_a = String::from_ascii_str("Hello World");
    assert_eq(string_a.as_bytes().len(), 11);

    let string_b = String::from_ascii_str("NoNoNo");
    assert_eq(string_b.as_bytes().len(), 6);

It would seem that the len is OK. Tried changing 6 to 7 and it failed. So guess Eq works for u64 :D

@bitzoic
Copy link
Member

bitzoic commented Jul 26, 2023

I think it's related to the where clause with the Eq trait and not something in the std lib. I've created this test function and am seeing the following behavior when passing Bytes.

pub fn takes_generics_with_where_clause<T>(gen_1: T, gen_2: T) -> bool where T: Eq {
    // This evaluates the opposite
    return gen_1 != gen_2;
    // This evaluates the opposite
    return gen_1 == gen_2;
    // This evaluates the opposite
    if (gen_1 != gen_2) {
        return false;
    }
    // This has an internal compiler error
    if (gen_1 == gen_2) {
        return true;
    }
}

The assert() function takes a bool and the evaluation is done before entering the function, hence why we see different behavior between the two.

@bitzoic
Copy link
Member

bitzoic commented Jul 26, 2023

Sorry correction, any case where we are checking for equal will not evaluate to true or false. Checking for not equal will provide the opposite.

This is a minimal repo:

use std::string::String;
use std::assert::assert_eq;
use std::assert::assert;

pub fn test_1<T>(gen_1: T, gen_2: T) -> bool where T: Eq {
    // This evaluate the opposite
    gen_1 != gen_2
}

pub fn test_2<T>(gen_1: T, gen_2: T) -> bool where T: Eq {
    // This evaluates to Failing call to `std::assert::assert`
    gen_1 == gen_2
}

pub fn test_3<T>(gen_1: T, gen_2: T) -> bool where T: Eq {
    // This evaluate the opposite
    if (gen_1 != gen_2) {
        return false;
    }
    return true;
}

pub fn test_4<T>(gen_1: T, gen_2: T) -> bool where T: Eq {
    // This has an internal compiler error
    if (gen_1 == gen_2) {
        return true;
    }
    return false;
}

#[test]
fn foo() {
    let string_a = String::from_ascii_str("Hello World");
    assert_eq(string_a.as_bytes().len(), 11);

    let string_b = String::from_ascii_str("NoNoNo");
    assert_eq(string_b.as_bytes().len(), 6);

    // Should eval to true
    assert(false == test_1(string_a.as_bytes(), string_b.as_bytes()));

    // Should eval to false
    // This evaluates to Failing call to `std::assert::assert` 
    // Will not pass either case but compiles
    assert(false == test_2(string_a.as_bytes(), string_b.as_bytes()));

    // Should eval to false
    assert(true == test_3(string_a.as_bytes(), string_b.as_bytes()));

    // Should eval to false
    // Internal compiler error: Verification failed: Expression used for conditional is not a boolean.
    assert(true == test_4(string_a.as_bytes(), string_b.as_bytes()));
}

@bitzoic bitzoic added compiler General compiler. Should eventually become more specific as the issue is triaged P: critical Should be looked at before anything else and removed lib: std Standard library labels Jul 26, 2023
@IGI-111 IGI-111 added the compiler: ir IRgen and sway-ir including optimization passes label Jul 26, 2023
@vaivaswatha
Copy link
Contributor

I triaged this a little bit and it appears to be the same problem that is seen in #4770.

@vaivaswatha vaivaswatha removed the compiler: ir IRgen and sway-ir including optimization passes label Aug 4, 2023
This was referenced Aug 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working compiler General compiler. Should eventually become more specific as the issue is triaged P: critical Should be looked at before anything else
Projects
None yet
Development

No branches or pull requests

5 participants