xtensor icon indicating copy to clipboard operation
xtensor copied to clipboard

Runtime crash in xtensor

Open Sallee1 opened this issue 5 months ago • 2 comments

Environment:

  • xtensor: 0.25.0

  • xtl: 0.7.7

  • xsimd: 13.2.0

  • OS: Windows 11 24H2

  • Compiler: MSVC 19.44 (Visual Studio 2022)

  • C++ Standard: C++14

  • Compilation flags:

    /permissive- /ifcOutput "x64\Release\" /GS /GL /W3 /Gy /Zc:wchar_t 
    /I"xtensor-0.25.0\include" /I"xtl-0.7.7\include" /I"xsimd-13.2.0\include" 
    /Zi /Gm- /Od /Ob0 /sdl /Fd"vc143.pdb" /Zc:inline /fp:precise 
    /D "XTENSOR_USE_XSIMD" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" 
    /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /std:c++17 /FC 
    /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Fp"demo.pch" 
    /diagnostics:column /utf-8
    
  • Linking flags:

    /MANIFEST /LTCG:incremental /NXCOMPAT /PDB:"demo.pdb" /DYNAMICBASE 
    "opencv_core4100.lib" ...(other libs)... /DEBUG /MACHINE:X64 /OPT:REF 
    /SUBSYSTEM:CONSOLE /LTCGOUT:"demo.iobj" /OPT:ICF /ERRORREPORT:PROMPT 
    /LIBPATH:"opencv_lib_path"
    

Description: It might be the following statement that caused the subsequent lazy evaluation to crash:

auto mfd_flow_weight = mfd_flow_weight_unnorm / mfd_flow_weight_sum;  // [H,W,8]

And the following statement triggers lazy evaluation, resulting in a segmentation fault:

xt::xtensor<double, 3>  result = mfd_flow_weight;

Minimal Reproducible Example:

#include <xtensor.hpp>
#include <opencv2/opencv.hpp>
using namespace xt::placeholders;
/**
 * @brief Sliding window view similar to numpy
 * @param img Input image
 * @param shape Window size
 * @return Sliding window view
*/
xt::xtensor<double, 4> sliding_window_view(const xt::xtensor<double, 2>& img, const std::array<size_t, 2>& shape, const std::array<size_t, 2>& stride = { 1,1 }) {
    assert((shape[0] & 1) == 1 && (shape[1] & 1) == 1);
    assert(stride[0] > 0 && stride[1] > 0);
    xt::svector<size_t, 4> new_shape{
        (img.shape(0) - shape[0]) / stride[0] + 1,
        (img.shape(1) - shape[1]) / stride[1] + 1,
        shape[0],
        shape[1] };
    xt::svector<std::ptrdiff_t, 4> new_strides{
        static_cast<std::ptrdiff_t>(stride[0] * img.strides()[0]),
        static_cast<std::ptrdiff_t>(stride[1] * img.strides()[1]),
        img.strides()[0],
        img.strides()[1]
    };
    auto sliding_window = xt::strided_view(img, new_shape, std::move(new_strides), 0);
    return sliding_window;
}
xt::xtensor<double, 3> mfd(xt::xtensor<double,2> dem, double dem_resolution) {
    // Sliding window view
    auto dem_pad = xt::pad(dem, 1, xt::pad_mode::constant, 0);            // [H+2,W+2]
    auto dem_slide_window = sliding_window_view(dem_pad, { 3,3 });         // [H,W,3,3]
    // Elevation differences
    auto diffs = xt::maximum(0,
        xt::view(dem_slide_window, xt::all(), xt::all(), xt::range(1, 2), xt::range(1, 2)) - dem_slide_window);   // [H,W,3,3]
    // Remove center
    auto diffs_without_center = xt::view(
        xt::reshape_view(diffs, { diffs.shape(0), diffs.shape(1), 9ULL }),
        xt::all(), xt::all(), xt::drop(4));            // [H,W,8]
    // Compute gradients
    const double diag_dist = dem_resolution * sqrt(2);
    xt::xtensor_fixed<double, xt::xshape<8>> slope_dist{
        diag_dist, dem_resolution, diag_dist,
        dem_resolution, dem_resolution,
        diag_dist, dem_resolution, diag_dist };        // [8]
    auto gradient8 = diffs_without_center / slope_dist;     // [H,W,8]
    auto max_gradient = xt::amax(gradient8, 2, xt::keep_dims);     // [H,W,1]
    std::cout << xt::adapt(max_gradient.shape()) << std::endl;
    // Compute flow concentration coefficient
    auto mfd_p = 8.9 * xt::minimum(max_gradient, 1.0) + 1.1;   // [H,W,1]
    std::cout << xt::adapt(mfd_p.shape()) << std::endl;
    // Compute unnormalized flow weights
    xt::xtensor_fixed<double, xt::xshape<8>> mfd_l{
        0.354,0.5,0.354,
        0.5,      0.5,
        0.354,0.5,0.354,
    };        // [8]
    auto mfd_flow_weight_unnorm = xt::pow(gradient8, mfd_p) * mfd_l;        // [H,W,8]
    auto mfd_flow_weight_sum = xt::sum(mfd_flow_weight_unnorm, 2, xt::keep_dims);        // [H,W,1]
    // Normalize the flow weights
    auto mfd_flow_weight = mfd_flow_weight_unnorm / mfd_flow_weight_sum;    // [H,W,8]
    xt::xtensor<double, 3>  result = mfd_flow_weight;
    std::cout << result << std::endl;
    return result;
}
int main() {
    cv::Mat dem_img = cv::imread("assets/dem.tif", cv::IMREAD_UNCHANGED);
    dem_img.convertTo(dem_img, CV_64FC1);
    xt::xtensor<double, 2> dem_tensor = xt::adapt(dem_img.data, dem_img.total(), xt::no_ownership(), 
        std::array<size_t, 2>{ static_cast<size_t>(dem_img.rows), static_cast<size_t>(dem_img.cols) });
    double resolution = 30.0;
    auto result = mfd(dem_tensor, resolution);
}

Attachments:

The call stack, executable program, pdb debug information, and minidump are provided in the following onedrive sharing

https://1drv.ms/u/c/4d2e14be0cb87b34/EWKRw2KHtwRDj8MKgIbLOy0Bc_LxLcAdvdhQXscQoLNX4g?e=gzj9ES

Sallee1 avatar Aug 18 '25 03:08 Sallee1