Skip to content

NaN/Inf lon/lat reaches std::sort with a NaN comparator in snyder_forward, causing undefined behavior #37

Description

@gcol33

NaN/Inf lon/lat reaches std::sort with a NaN-producing comparator in snyder_forward, causing undefined behavior

Defect

src/projection_forward.cpp:198-222: snyder_forward computes face_dists[i] = {face_distance(...), i} for all 20 faces and calls std::sort(face_dists.begin(), face_dists.end()). If lon_deg/lat_deg is NaN, face_distance (line 190) produces NaN for every face (via clampd, which passes NaN through unchanged since both its comparisons are false for NaN — icosahedron.cpp:112), so all 20 pairs compare as NaN.

std::pair's operator< on NaN violates strict-weak-ordering, which is undefined behavior for std::sort — this can corrupt memory during introsort's partitioning in libstdc++/MSVC implementations, not merely "produce the wrong order."

Reachability

Directly via cpp_snyder_forward (src/rcpp_projection.cpp:50), and via cpp_lonlat_to_index_ap3/4/7 (src/rcpp_index.cpp:121-163), called from R/hexify_index.R:91 with zero NA/Inf filtering upstream.

Related

icosahedron.cpp's which_face() (lines 181-197) has the analogous issue: with NaN inputs, every candidate distance is NaN, and since d < bestd is always false for NaN, best never updates past its initial value — the function silently returns face 0 for any NaN input instead of erroring, exposed directly via cpp_which_face (rcpp_projection.cpp:30-32).

Impact

tests/testthat/test-projection-forward.R has no NaN/Inf/NA test case, so this UB path is completely untested.

Fix

Add an explicit std::isfinite() check on lon_deg/lat_deg at the top of snyder_forward (and which_face) that throws a clear R-facing error via Rcpp::stop, matching the pattern already used elsewhere in this codebase (e.g. rcpp_aperture.cpp's checked_ij()).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions