//@HEADER // ************************************************************************ // // Kokkos v. 4.0 // Copyright (2022) National Technology & Engineering // Solutions of Sandia, LLC (NTESS). // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions. // See https://kokkos.org/LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //@HEADER #include #include #include namespace { TEST(TEST_CATEGORY, append_formatted_multidimensional_index) { using Kokkos::Impl::append_formatted_multidimensional_index; { char buffer[64] = "my prefix "; append_formatted_multidimensional_index(buffer, 1); EXPECT_STREQ(buffer, "my prefix [1]"); } { char buffer[64] = "I was here"; append_formatted_multidimensional_index(buffer, 1, 2, 3); EXPECT_STREQ(buffer, "I was here[1,2,3]"); } { char buffer[64] = "with mixed integer types "; append_formatted_multidimensional_index(buffer, 1u, -2); EXPECT_STREQ(buffer, "with mixed integer types [1,-2]"); } } #ifdef KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK template struct TestViewOutOfBoundAccess { View v; static constexpr auto rank = View::rank; template KOKKOS_FUNCTION decltype(auto) bad_access(std::index_sequence) const { return v((Is * 1 + Is == 0 ? v.extent(Is) + 3 : 0)...); } KOKKOS_FUNCTION void operator()(int) const { ++bad_access(std::make_index_sequence{}); } template std::string get_details(std::index_sequence) { std::stringstream ss; ss << "with indices \\["; ((ss << (Is == 0 ? v.extent(Is) + 3 : 0) << (Is == View::rank() - 1 ? "\\]" : ",")), ...); ss << " but extents \\["; ((ss << v.extent(Is) << (Is == View::rank() - 1 ? "\\]" : ",")), ...); return ss.str(); } auto get_details() { return get_details(std::make_index_sequence()); } TestViewOutOfBoundAccess(View w, ExecutionSpace const& s, std::string matcher) : v(std::move(w)) { constexpr bool view_accessible_from_execution_space = Kokkos::SpaceAccessibility< /*AccessSpace=*/ExecutionSpace, /*MemorySpace=*/typename View::memory_space>::accessible; EXPECT_TRUE(view_accessible_from_execution_space); matcher += ".*" + get_details(); EXPECT_DEATH( { Kokkos::parallel_for(Kokkos::RangePolicy(s, 0, 1), *this); Kokkos::fence(); }, matcher); } }; template auto make_view_impl(LblOrPtr x, std::index_sequence) { return View(x, (Is + 1)...); } template auto make_view(LblOrPtr x) { return make_view_impl(std::move(x), std::make_index_sequence()); } template void test_view_out_of_bounds_access() { ExecutionSpace const exec_space{}; // clang-format off using V1 = Kokkos::View; using V2 = Kokkos::View; using V3 = Kokkos::View; using V4 = Kokkos::View; using V5 = Kokkos::View; using V6 = Kokkos::View; using V7 = Kokkos::View; using V8 = Kokkos::View; std::string const prefix = "Kokkos::View ERROR: out of bounds access"; std::string const lbl = "my_label"; TestViewOutOfBoundAccess(make_view(lbl), exec_space, prefix + ".*" + lbl); TestViewOutOfBoundAccess(make_view(lbl), exec_space, prefix + ".*" + lbl); TestViewOutOfBoundAccess(make_view(lbl), exec_space, prefix + ".*" + lbl); TestViewOutOfBoundAccess(make_view(lbl), exec_space, prefix + ".*" + lbl); TestViewOutOfBoundAccess(make_view(lbl), exec_space, prefix + ".*" + lbl); TestViewOutOfBoundAccess(make_view(lbl), exec_space, prefix + ".*" + lbl); TestViewOutOfBoundAccess(make_view(lbl), exec_space, prefix + ".*" + lbl); TestViewOutOfBoundAccess(make_view(lbl), exec_space, prefix + ".*" + lbl); int* const ptr = nullptr; TestViewOutOfBoundAccess(make_view(ptr), exec_space, prefix + ".*UNMANAGED"); TestViewOutOfBoundAccess(make_view(ptr), exec_space, prefix + ".*UNMANAGED"); TestViewOutOfBoundAccess(make_view(ptr), exec_space, prefix + ".*UNMANAGED"); TestViewOutOfBoundAccess(make_view(ptr), exec_space, prefix + ".*UNMANAGED"); TestViewOutOfBoundAccess(make_view(ptr), exec_space, prefix + ".*UNMANAGED"); TestViewOutOfBoundAccess(make_view(ptr), exec_space, prefix + ".*UNMANAGED"); TestViewOutOfBoundAccess(make_view(ptr), exec_space, prefix + ".*UNMANAGED"); TestViewOutOfBoundAccess(make_view(ptr), exec_space, prefix + ".*UNMANAGED"); // clang-format on } TEST(TEST_CATEGORY_DEATH, view_out_of_bounds_access) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; using ExecutionSpace = TEST_EXECSPACE; if (false && Kokkos::SpaceAccessibility< /*AccessSpace=*/ExecutionSpace, /*MemorySpace=*/Kokkos::HostSpace>::accessible) { GTEST_SKIP() << "skipping since no memory access violation would occur"; } #if defined(KOKKOS_ENABLE_SYCL) && defined(NDEBUG) // FIXME_SYCL if (std::is_same_v) { GTEST_SKIP() << "skipping SYCL device-side abort does not work when NDEBUG " "is defined"; } #endif #if defined(KOKKOS_ENABLE_OPENMPTARGET) // FIXME_OPENMPTARGET if (std::is_same_v) { GTEST_SKIP() << "skipping because OpenMPTarget backend is currently not " "able to abort from the device"; } #endif #if defined(KOKKOS_ENABLE_OPENACC) // FIXME_OPENACC if (std::is_same::value) { GTEST_SKIP() << "skipping because OpenACC backend is currently not " "able to abort from the device"; } #endif test_view_out_of_bounds_access(); } #endif } // namespace