Skip to content

Matrix index out of bounds. #310

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
Johannes0021 opened this issue Jan 29, 2025 · 3 comments · May be fixed by #319
Open

Matrix index out of bounds. #310

Johannes0021 opened this issue Jan 29, 2025 · 3 comments · May be fixed by #319
Labels
bug Something isn't working

Comments

@Johannes0021
Copy link

Johannes0021 commented Jan 29, 2025

// Error / Panic --------------------------------------------------------------

parry2d-f64-0.18.0/src/query/clip/clip_aabb_line.rs:141:19:
Matrix index out of bounds.

// What happened ---------------------------------------------------------

I accidentally created a triangle ColliderShape with:

point_a -> Vec2 { data: [40.0, 0.0] }
point_b -> Vec2 { data: [ 0.0, 80.0] } // Same as point_c
point_c -> Vec2 { data: [ 0.0, 80.0] } // Same as point_b

In clip_aabb_line.rs the origin parameter has NAN values -> pub fn clip_aabb_line(...);

In the loop in the else part:
let mut inter_with_near_halfspace = (aabb.mins[i] - origin[i]) * denom; // Results in NaN (origin[i] == NaN)
let mut inter_with_far_halfspace = (aabb.maxs[i] - origin[i]) * denom; // Results in NaN (origin[i] == NaN)

near_diag stays false
near_side stays 0

in line 141 [0 - 1] Matrix index out of bounds.

// Solution ----------------------------------------------------------------

let near = if near_diag {
    (tmin, -dir.normalize(), near_side)
} else {
    let mut normal = Vector::zeros();

    if near_side < 0 {
        normal[(-near_side - 1) as usize] = 1.0;
    } else if near_side > 0 { // <-------------------------------------- Here
        normal[(near_side - 1) as usize] = -1.0;
    }
    else { // <--------------------------------------------------------- Here
        return None;
    }

    (tmin, normal, near_side)
};

let far = if far_diag {
    (tmax, -dir.normalize(), far_side)
} else {
    let mut normal = Vector::zeros();

    if far_side < 0 {
        normal[(-far_side - 1) as usize] = -1.0;
    } else if far_side > 0 { // <--------------------------------------- Here
        normal[(far_side - 1) as usize] = 1.0;
    }
    else { // <--------------------------------------------------------- Here
        return None;
    }

    (tmax, normal, far_side)
};
Johannes0021 added a commit to Johannes0021/parry that referenced this issue Mar 4, 2025
@Johannes0021 Johannes0021 linked a pull request Mar 4, 2025 that will close this issue
@Vrixyz Vrixyz added the bug Something isn't working label Mar 5, 2025
Johannes0021 added a commit to Johannes0021/parry that referenced this issue Mar 19, 2025
Johannes0021 added a commit to Johannes0021/parry that referenced this issue Mar 19, 2025
@hakolao
Copy link
Contributor

hakolao commented Apr 29, 2025

I'm getting this too, an only panic I've seen in a long time. Would be nice to get this fixed.

@Johannes0021
Copy link
Author

Johannes0021 commented May 5, 2025

Problem:
If a triangle collider has two or all three points the same,
the code divides by zero inside project_local_point_and_get_location.
This makes the result NaN and breaks further calculations.


How to Reproduce:
This example uses Rapier2D for demonstration, but the root cause of the error lies in Parry.

use rapier2d::prelude::*;

fn main() {
    let mut rigid_body_set = RigidBodySet::new();
    let mut collider_set = ColliderSet::new();

    /* Create the ground. */
    let collider = ColliderBuilder::ball(100.0).build();
    collider_set.insert(collider);

    /* Create the bouncing ball. */
    let rigid_body = RigidBodyBuilder::dynamic()
        .translation(vector![0.0, 0.0])
        .build();

    let a = point![40.0,  0.0];
    let b = point![ 0.0, 80.0];
    let c = point![ 0.0, 80.0];

    let collider = ColliderBuilder::triangle(a, b, c).restitution(0.7).build();
    let triangle_body_handle = rigid_body_set.insert(rigid_body);
    collider_set.insert_with_parent(collider, triangle_body_handle, &mut rigid_body_set);

    /* Create other structures necessary for the simulation. */
    let gravity = vector![0.0, -9.81];
    let integration_parameters = IntegrationParameters::default();
    let mut physics_pipeline = PhysicsPipeline::new();
    let mut island_manager = IslandManager::new();
    let mut broad_phase = DefaultBroadPhase::new();
    let mut narrow_phase = NarrowPhase::new();
    let mut impulse_joint_set = ImpulseJointSet::new();
    let mut multibody_joint_set = MultibodyJointSet::new();
    let mut ccd_solver = CCDSolver::new();
    let mut query_pipeline = QueryPipeline::new();
    let physics_hooks = ();
    let event_handler = ();

    /* Run the game loop, stepping the simulation once per frame. */
    for _ in 0..3 {
        physics_pipeline.step(
            &gravity,
            &integration_parameters,
            &mut island_manager,
            &mut broad_phase,
            &mut narrow_phase,
            &mut rigid_body_set,
            &mut collider_set,
            &mut impulse_joint_set,
            &mut multibody_joint_set,
            &mut ccd_solver,
            Some(&mut query_pipeline),
            &physics_hooks,
            &event_handler,
        );

        let triangle_body = &rigid_body_set[triangle_body_handle];
        println!("Triangle altitude: {}", triangle_body.translation().y); // Prints NaN
    }
}

Output:
Triangle altitude: NaN
Triangle altitude: NaN
Triangle altitude: NaN


What Happens:

  • In "src/query/point/point_triangle.rs" in the fn project_local_point_and_get_location (around line 254), the code does:
let u = (ac_bp - ab_bp) / (ac_bp - ab_bp + ab_cp - ac_cp); // proj on bc = b + bc * u

This resolves in the NaN.


Propagation and Panic:
If a invalid triangle makes u become NaN, later code still uses these NaN values. For example, in clip_aabb_line:

let inter_with_near_halfspace = (aabb.mins[i] - origin[i]) * denom;
let inter_with_far_halfspace = (aabb.maxs[i] - origin[i]) * denom;

Both results are NaN because origin[i] is NaN. The flags near_diag and far_diag stay false, and near_side and far_side remain 0. Eventually the code does:

normal[(near_side - 1) as usize] = 1.0;

This becomes normal[-1], causing a panic: index out of bounds.


Note: I’m not sure how critical this is in practice, since you normally create triangles with valid, distinct points.
I investigated this mainly to pinpoint the root cause of the matrix index out of bounds panic.*

@Johannes0021
Copy link
Author

Just to add:
This was the first place I found where a triangle with duplicate points leads to issues, but I’m not sure if it’s the only one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants