Skip to content

Commit 82e8766

Browse files
committed
Fix out-of-bounce read access in the linear predict kernel.
1 parent 9a34225 commit 82e8766

File tree

7 files changed

+39
-20
lines changed

7 files changed

+39
-20
lines changed

include/plssvm/backends/HPX/kernel/predict_kernel.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
#include "plssvm/backends/HPX/detail/utility.hpp" // plssvm::hpx::detail::atomic_ref
1818
#include "plssvm/backends/HPX/kernel/kernel_functions.hpp" // plssvm::hpx::detail::{feature_reduce, apply_kernel_function}
19-
#include "plssvm/constants.hpp" // plssvm::{real_type, INTERNAL_BLOCK_SIZE, PADDING_SIZE}
19+
#include "plssvm/constants.hpp" // plssvm::{real_type, THREAD_BLOCK_SIZE, INTERNAL_BLOCK_SIZE, PADDING_SIZE}
2020
#include "plssvm/detail/assert.hpp" // PLSSVM_ASSERT
2121
#include "plssvm/kernel_function_types.hpp" // plssvm::kernel_function_type
2222
#include "plssvm/matrix.hpp" // plssvm::aos_matrix, plssvm::soa_matrix
@@ -111,7 +111,7 @@ inline void device_kernel_w_linear(soa_matrix<real_type> &w, const aos_matrix<re
111111
* @param[in] device_row_offset the first row in @p predict_points the current device is responsible for
112112
*/
113113
inline void device_kernel_predict_linear(aos_matrix<real_type> &prediction, const soa_matrix<real_type> &w, const std::vector<real_type> &rho, const soa_matrix<real_type> &predict_points, const std::size_t device_num_predict_points, const std::size_t device_row_offset) {
114-
PLSSVM_ASSERT(w.num_rows() == rho.size(), "Size mismatch: {} vs {}!", w.num_rows(), rho.size());
114+
PLSSVM_ASSERT(w.num_rows() == rho.size() - PADDING_SIZE, "Size mismatch: {} vs {}!", w.num_rows(), rho.size() - PADDING_SIZE);
115115
PLSSVM_ASSERT(w.num_cols() == predict_points.num_cols(), "Size mismatch: {} vs {}!", w.num_cols(), predict_points.num_cols());
116116
PLSSVM_ASSERT(prediction.shape() == (plssvm::shape{ predict_points.num_rows(), w.num_rows() }), "Shape mismatch: {} vs {}!", prediction.shape(), (plssvm::shape{ predict_points.num_rows(), w.num_rows() }));
117117
PLSSVM_ASSERT(predict_points.num_rows() >= device_num_predict_points, "The number of place specific predict points ({}) cannot be greater the the total number of predict points ({})!", device_num_predict_points, predict_points.num_rows());

include/plssvm/backends/OpenMP/kernel/predict_kernel.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#define PLSSVM_BACKENDS_OPENMP_KERNEL_PREDICT_KERNEL_HPP_
1414
#pragma once
1515

16-
#include "plssvm/constants.hpp" // plssvm::real_type
16+
#include "plssvm/constants.hpp" // plssvm::{real_type, THREAD_BLOCK_SIZE, INTERNAL_BLOCK_SIZE, PADDING_SIZE}
1717
#include "plssvm/detail/assert.hpp" // PLSSVM_ASSERT
1818
#include "plssvm/kernel_function_types.hpp" // plssvm::kernel_function_type
1919
#include "plssvm/matrix.hpp" // plssvm::aos_matrix, plssvm::matrix
@@ -108,7 +108,7 @@ inline void device_kernel_w_linear(soa_matrix<real_type> &w, const aos_matrix<re
108108
* @param[in] device_row_offset the first row in @p predict_points the current device is responsible for
109109
*/
110110
inline void device_kernel_predict_linear(aos_matrix<real_type> &prediction, const soa_matrix<real_type> &w, const std::vector<real_type> &rho, const soa_matrix<real_type> &predict_points, const std::size_t device_num_predict_points, const std::size_t device_row_offset) {
111-
PLSSVM_ASSERT(w.num_rows() == rho.size(), "Size mismatch: {} vs {}!", w.num_rows(), rho.size());
111+
PLSSVM_ASSERT(w.num_rows() == rho.size() - PADDING_SIZE, "Size mismatch: {} vs {}!", w.num_rows(), rho.size() - PADDING_SIZE);
112112
PLSSVM_ASSERT(w.num_cols() == predict_points.num_cols(), "Size mismatch: {} vs {}!", w.num_cols(), predict_points.num_cols());
113113
PLSSVM_ASSERT(prediction.shape() == (plssvm::shape{ predict_points.num_rows(), w.num_rows() }), "Shape mismatch: {} vs {}!", prediction.shape(), (plssvm::shape{ predict_points.num_rows(), w.num_rows() }));
114114
PLSSVM_ASSERT(predict_points.num_rows() >= device_num_predict_points, "The number of place specific predict points ({}) cannot be greater the the total number of predict points ({})!", device_num_predict_points, predict_points.num_rows());

include/plssvm/backends/stdpar/kernel/predict_kernel.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
#include "plssvm/backends/stdpar/detail/utility.hpp" // plssvm::stdpar::detail::atomic_ref
1717
#include "plssvm/backends/stdpar/kernel/kernel_functions.hpp" // plssvm::stdpar::detail::{feature_reduce, apply_kernel_function}
18-
#include "plssvm/constants.hpp" // plssvm::{real_type, INTERNAL_BLOCK_SIZE, PADDING_SIZE}
18+
#include "plssvm/constants.hpp" // plssvm::{real_type, THREAD_BLOCK_SIZE, INTERNAL_BLOCK_SIZE, PADDING_SIZE}
1919
#include "plssvm/detail/assert.hpp" // PLSSVM_ASSERT
2020
#include "plssvm/kernel_function_types.hpp" // plssvm::kernel_function_type
2121
#include "plssvm/matrix.hpp" // plssvm::aos_matrix, plssvm::soa_matrix
@@ -141,7 +141,7 @@ struct device_kernel_predict_linear {
141141
* @param[in] device_row_offset the first row in @p predict_points the current device is responsible for
142142
*/
143143
void operator()(aos_matrix<real_type> &prediction, const soa_matrix<real_type> &w, const std::vector<real_type> &rho, const soa_matrix<real_type> &predict_points, const std::size_t device_num_predict_points, const std::size_t device_row_offset) {
144-
PLSSVM_ASSERT(w.num_rows() == rho.size(), "Size mismatch: {} vs {}!", w.num_rows(), rho.size());
144+
PLSSVM_ASSERT(w.num_rows() == rho.size() - PADDING_SIZE, "Size mismatch: {} vs {}!", w.num_rows(), rho.size() - PADDING_SIZE);
145145
PLSSVM_ASSERT(w.num_cols() == predict_points.num_cols(), "Size mismatch: {} vs {}!", w.num_cols(), predict_points.num_cols());
146146
PLSSVM_ASSERT(prediction.shape() == (plssvm::shape{ predict_points.num_rows(), w.num_rows() }), "Shape mismatch: {} vs {}!", prediction.shape(), (plssvm::shape{ predict_points.num_rows(), w.num_rows() }));
147147
PLSSVM_ASSERT(predict_points.num_rows() >= device_num_predict_points, "The number of place specific predict points ({}) cannot be greater the the total number of predict points ({})!", device_num_predict_points, predict_points.num_rows());

src/plssvm/backends/HPX/csvm.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "plssvm/backends/HPX/kernel/cg_explicit/kernel_matrix_assembly.hpp" // plssvm::hpx::detail::device_kernel_assembly
1717
#include "plssvm/backends/HPX/kernel/cg_implicit/kernel_matrix_assembly_blas.hpp" // plssvm::hpx::detail::device_kernel_assembly_symm
1818
#include "plssvm/backends/HPX/kernel/predict_kernel.hpp" // plssvm::hpx::detail::{device_kernel_w_linear, device_kernel_predict_linear, device_kernel_predict}
19-
#include "plssvm/constants.hpp" // plssvm::real_type
19+
#include "plssvm/constants.hpp" // plssvm::real_type, plssvm::PADDING_SIZE
2020
#include "plssvm/detail/assert.hpp" // PLSSVM_ASSERT
2121
#include "plssvm/detail/data_distribution.hpp" // plssvm::detail::triangular_data_distribution
2222
#include "plssvm/detail/logging/mpi_log_untracked.hpp" // plssvm::detail::log_untracked
@@ -42,6 +42,7 @@
4242

4343
#include <chrono> // std::chrono::{steady_clock, duration_cast}
4444
#include <cstddef> // std::size_t
45+
#include <cstring> // std::memcpy
4546
#include <functional> // std::cref
4647
#include <memory> // std::make_unique, std::unique_ptr
4748
#include <optional> // std::optional, std::nullopt
@@ -356,8 +357,12 @@ aos_matrix<real_type> csvm::predict_values(const parameter &params,
356357
// call the predict kernels
357358
switch (params.kernel_type) {
358359
case kernel_function_type::linear:
359-
// predict the values using the w vector
360-
detail::device_kernel_predict_linear(out, w, rho, predict_points, device_specific_num_predict_points, row_offset);
360+
{
361+
// predict the values using the w vector
362+
std::vector<real_type> rho_padded(rho.size() + PADDING_SIZE, real_type{ 0.0 });
363+
std::memcpy(rho_padded.data(), rho.data(), rho.size() * sizeof(real_type));
364+
detail::device_kernel_predict_linear(out, w, rho_padded, predict_points, device_specific_num_predict_points, row_offset);
365+
}
361366
break;
362367
case kernel_function_type::polynomial:
363368
detail::device_kernel_predict<kernel_function_type::polynomial>(out, alpha, rho, support_vectors, predict_points, device_specific_num_predict_points, row_offset, params.degree, std::get<real_type>(params.gamma), params.coef0);

src/plssvm/backends/OpenMP/csvm.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include "plssvm/backends/OpenMP/kernel/cg_explicit/kernel_matrix_assembly.hpp" // plssvm::openmp::detail::device_kernel_assembly
1616
#include "plssvm/backends/OpenMP/kernel/cg_implicit/kernel_matrix_assembly_blas.hpp" // plssvm::openmp::detail::device_kernel_assembly_symm
1717
#include "plssvm/backends/OpenMP/kernel/predict_kernel.hpp" // plssvm::openmp::detail::{device_kernel_w_linear, device_kernel_predict_linear, device_kernel_predict}
18-
#include "plssvm/constants.hpp" // plssvm::real_type
18+
#include "plssvm/constants.hpp" // plssvm::real_type, plssvm::PADDING_SIZE
1919
#include "plssvm/detail/assert.hpp" // PLSSVM_ASSERT
2020
#include "plssvm/detail/data_distribution.hpp" // plssvm::detail::triangular_data_distribution
2121
#include "plssvm/detail/logging/mpi_log_untracked.hpp" // plssvm::detail::log_untracked
@@ -40,7 +40,7 @@
4040
#include <chrono> // std::chrono::{steady_clock, duration_cast}
4141
#include <cmath> // std::fma
4242
#include <cstddef> // std::size_t
43-
#include <cstring> // std::memset
43+
#include <cstring> // std::memset, std::memcpy
4444
#include <functional> // std::cref
4545
#include <memory> // std::make_unique
4646
#include <optional> // std::optional, std::nullopt
@@ -347,8 +347,12 @@ aos_matrix<real_type> csvm::predict_values(const parameter &params,
347347
// call the predict kernels
348348
switch (params.kernel_type) {
349349
case kernel_function_type::linear:
350-
// predict the values using the w vector
351-
detail::device_kernel_predict_linear(out, w, rho, predict_points, device_specific_num_predict_points, row_offset);
350+
{
351+
// predict the values using the w vector
352+
std::vector<real_type> rho_padded(rho.size() + PADDING_SIZE, real_type{ 0.0 });
353+
std::memcpy(rho_padded.data(), rho.data(), rho.size() * sizeof(real_type));
354+
detail::device_kernel_predict_linear(out, w, rho_padded, predict_points, device_specific_num_predict_points, row_offset);
355+
}
352356
break;
353357
case kernel_function_type::polynomial:
354358
detail::device_kernel_predict<kernel_function_type::polynomial>(out, alpha, rho, support_vectors, predict_points, device_specific_num_predict_points, row_offset, params.degree, std::get<real_type>(params.gamma), params.coef0);

src/plssvm/backends/stdpar/csvm.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include "plssvm/backends/stdpar/kernel/cg_explicit/kernel_matrix_assembly.hpp" // plssvm::stdpar::detail::device_kernel_assembly
1414
#include "plssvm/backends/stdpar/kernel/cg_implicit/kernel_matrix_assembly_blas.hpp" // plssvm::stdpar::detail::device_kernel_assembly_symm
1515
#include "plssvm/backends/stdpar/kernel/predict_kernel.hpp" // plssvm::stdpar::detail::{device_kernel_w_linear, device_kernel_predict_linear, device_kernel_predict}
16-
#include "plssvm/constants.hpp" // plssvm::real_type
16+
#include "plssvm/constants.hpp" // plssvm::real_type, plssvm::PADDING_SIZE
1717
#include "plssvm/detail/assert.hpp" // PLSSVM_ASSERT
1818
#include "plssvm/detail/data_distribution.hpp" // plssvm::detail::triangular_data_distribution
1919
#include "plssvm/detail/make_unique_for_overwrite.hpp" // plssvm::detail::{make_unique_for_overwrite, parallel_zero_memset}
@@ -31,6 +31,7 @@
3131

3232
#include <chrono> // std::chrono::{steady_clock, duration_cast}
3333
#include <cstddef> // std::size_t
34+
#include <cstring> // std::memcpy
3435
#include <functional> // std::cref
3536
#include <memory> // std::unique_ptr, std::make_unique
3637
#include <optional> // std::optional, std::nullopt
@@ -366,7 +367,9 @@ aos_matrix<real_type> csvm::predict_values(const parameter &params,
366367
const auto start = std::chrono::steady_clock::now();
367368
// call the predict kernels
368369
if (params.kernel_type == kernel_function_type::linear) {
369-
dispatch_target_platform<detail::device_kernel_predict_linear>(target_, out, w, rho, predict_points, device_specific_num_predict_points, row_offset);
370+
std::vector<real_type> rho_padded(rho.size() + PADDING_SIZE, real_type{ 0.0 });
371+
std::memcpy(rho_padded.data(), rho.data(), rho.size() * sizeof(real_type));
372+
dispatch_target_platform<detail::device_kernel_predict_linear>(target_, out, w, rho_padded, predict_points, device_specific_num_predict_points, row_offset);
370373
} else {
371374
dispatch_target_platform<detail::device_kernel_predict>(target_, params, out, alpha, rho, support_vectors, predict_points, device_specific_num_predict_points, row_offset);
372375
}

tests/backends/generic_csvm_tests.hpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
#include <algorithm> // std::min
3636
#include <cstddef> // std::size_t
37+
#include <cstring> // std::memcpy
3738
#include <tuple> // std::get
3839
#include <vector> // std::vector
3940

@@ -283,7 +284,11 @@ TYPED_TEST_P(GenericBackendCSVMKernelFunction, PredictValues) {
283284

284285
switch (kernel) {
285286
case plssvm::kernel_function_type::linear:
286-
device_kernel_predict_linear(out, correct_w, rho, predict_points, device_specific_num_predict_points, row_offset);
287+
{
288+
std::vector<plssvm::real_type> rho_padded(rho.size() + plssvm::PADDING_SIZE, plssvm::real_type{ 0.0 });
289+
std::memcpy(rho_padded.data(), rho.data(), rho.size() * sizeof(plssvm::real_type));
290+
device_kernel_predict_linear(out, correct_w, rho_padded, predict_points, device_specific_num_predict_points, row_offset);
291+
}
287292
break;
288293
case plssvm::kernel_function_type::polynomial:
289294
device_kernel_predict<plssvm::kernel_function_type::polynomial, int, plssvm::real_type, plssvm::real_type>(out, weights, rho, data_matr, predict_points, device_specific_num_predict_points, row_offset, params.degree, std::get<plssvm::real_type>(params.gamma), params.coef0);
@@ -567,7 +572,6 @@ TYPED_TEST_P(GenericBackendCSVMKernelFunctionDeathTest, PredictValues) {
567572

568573
const auto weights = util::generate_specific_matrix<plssvm::aos_matrix<plssvm::real_type>>(plssvm::shape{ 3, data.data().num_rows() }, plssvm::shape{ plssvm::PADDING_SIZE, plssvm::PADDING_SIZE });
569574
const auto predict_points = util::generate_specific_matrix<plssvm::soa_matrix<plssvm::real_type>>(plssvm::shape{ data.data().num_rows(), data.data().num_cols() }, plssvm::shape{ plssvm::PADDING_SIZE, plssvm::PADDING_SIZE });
570-
const std::vector<plssvm::real_type> rho = util::generate_random_vector<plssvm::real_type>(weights.num_rows());
571575
const plssvm::soa_matrix<plssvm::real_type> w = ground_truth::calculate_w(weights, data.data());
572576

573577
plssvm::aos_matrix<plssvm::real_type> out{ plssvm::shape{ predict_points.num_rows(), weights.num_rows() }, plssvm::shape{ plssvm::PADDING_SIZE, plssvm::PADDING_SIZE } };
@@ -578,11 +582,12 @@ TYPED_TEST_P(GenericBackendCSVMKernelFunctionDeathTest, PredictValues) {
578582
const std::size_t row_offset = dist.place_row_offset(0);
579583

580584
if constexpr (kernel == plssvm::kernel_function_type::linear) {
585+
const std::vector<plssvm::real_type> rho = util::generate_random_vector<plssvm::real_type>(weights.num_rows() + plssvm::PADDING_SIZE);
586+
581587
// the number of classes must match
582-
std::vector<plssvm::real_type> rho_wrong = util::generate_random_vector<plssvm::real_type>(weights.num_rows());
583-
rho_wrong.pop_back();
588+
const std::vector<plssvm::real_type> rho_wrong = util::generate_random_vector<plssvm::real_type>(rho.size() - 1);
584589
EXPECT_DEATH(device_kernel_predict_linear(out, w, rho_wrong, predict_points, device_specific_num_predict_points, row_offset),
585-
::testing::HasSubstr(fmt::format("Size mismatch: {} vs {}!", w.num_rows(), rho_wrong.size())));
590+
::testing::HasSubstr(fmt::format("Size mismatch: {} vs {}!", w.num_rows(), rho_wrong.size() - plssvm::PADDING_SIZE)));
586591

587592
// the number of features must match
588593
const auto predict_points_wrong = util::generate_specific_matrix<plssvm::soa_matrix<plssvm::real_type>>(plssvm::shape{ data.data().num_rows(), data.data().num_cols() + 1 }, plssvm::shape{ plssvm::PADDING_SIZE, plssvm::PADDING_SIZE });
@@ -602,6 +607,8 @@ TYPED_TEST_P(GenericBackendCSVMKernelFunctionDeathTest, PredictValues) {
602607
EXPECT_DEATH(device_kernel_predict_linear(out, w, rho, predict_points, device_specific_num_predict_points, predict_points.num_rows() + 1),
603608
::testing::HasSubstr(fmt::format("The row offset ({}) cannot be greater the the total number of predict points ({})!", predict_points.num_rows() + 1, predict_points.num_rows())));
604609
} else {
610+
const std::vector<plssvm::real_type> rho = util::generate_random_vector<plssvm::real_type>(weights.num_rows());
611+
605612
// helper lambda to reduce the amount of needed switches!
606613
const auto run_predict_values = [=](const plssvm::parameter &params_p, plssvm::aos_matrix<plssvm::real_type> &out_p, const plssvm::aos_matrix<plssvm::real_type> &weights_p, const std::vector<plssvm::real_type> &rho_p, const plssvm::soa_matrix<plssvm::real_type> &support_vectors_p, const plssvm::soa_matrix<plssvm::real_type> &predict_points_p, const std::size_t device_specific_num_predict_points_p, const std::size_t row_offset_p) {
607614
switch (kernel) {

0 commit comments

Comments
 (0)