Repository: rapidsai/cudf (language: python)

Issue:
[BUG] `strings::split_record` throws exception on input having one empty row
Instead of returning an empty output, `strings::split_record` crashes on the input having just one empty row. Below is a reproducible unit test:
```
TEST_F(StringsSplitTest, SplitRecordOneEmptyString)
{
  std::vector<char const*> h_strings{""};
  cudf::test::strings_column_wrapper input(h_strings.begin(), h_strings.end());

  auto result =
    cudf::strings::split_record(cudf::strings_column_view(input), cudf::string_scalar("s"));
  using LCW = cudf::test::lists_column_wrapper<cudf::string_view>;
  LCW expected{LCW{}};
  CUDF_TEST_EXPECT_COLUMNS_EQUAL(result->view(), expected);
}
```

Output:
```
C++ exception with description "parallel_for failed: cudaErrorInvalidDevice: invalid device ordinal" thrown in the test body.
```

Note that the existing unit tests like https://github.com/rapidsai/cudf/blob/04330f2e9e73ac71a86666c55d0fe7248eaf8db6/cpp/tests/strings/split_tests.cpp#L246 already has empty string in the input but this issue only shows up when the input has only one (empty string) row.


Discussion / hints:
CC @davidwendt.

Fix patch:
diff --git a/cpp/src/strings/split/split.cuh b/cpp/src/strings/split/split.cuh
index 23614ac0733..4d7096c02ca 100644
--- a/cpp/src/strings/split/split.cuh
+++ b/cpp/src/strings/split/split.cuh
@@ -357,6 +357,12 @@ std::pair<std::unique_ptr<column>, rmm::device_uvector<string_index_pair>> split
   auto const chars_bytes =
     get_offset_value(input.offsets(), input.offset() + strings_count, stream) -
     get_offset_value(input.offsets(), input.offset(), stream);
+  if (chars_bytes == 0) {
+    auto offsets = cudf::make_column_from_scalar(
+      numeric_scalar<int32_t>(0, true, stream), strings_count + 1, stream, mr);
+    auto tokens = rmm::device_uvector<string_index_pair>(0, stream);
+    return std::pair{std::move(offsets), std::move(tokens)};
+  }
   auto const d_offsets =
     cudf::detail::offsetalator_factory::make_input_iterator(input.offsets(), input.offset());
 


Test patch:
diff --git a/cpp/tests/strings/split_tests.cpp b/cpp/tests/strings/split_tests.cpp
index d53c64ed539..4c020cb4c29 100644
--- a/cpp/tests/strings/split_tests.cpp
+++ b/cpp/tests/strings/split_tests.cpp
@@ -307,6 +307,26 @@ TEST_F(StringsSplitTest, SplitRecordWhitespaceWithMaxSplit)
   CUDF_TEST_EXPECT_COLUMNS_EQUAL(result->view(), expected);
 }
 
+TEST_F(StringsSplitTest, SplitRecordAllEmpty)
+{
+  auto input     = cudf::test::strings_column_wrapper({"", "", "", ""});
+  auto sv        = cudf::strings_column_view(input);
+  auto delimiter = cudf::string_scalar("s");
+  auto empty     = cudf::string_scalar("");
+
+  using LCW = cudf::test::lists_column_wrapper<cudf::string_view>;
+  LCW expected({LCW{}, LCW{}, LCW{}, LCW{}});
+  auto result = cudf::strings::split_record(sv, delimiter);
+  CUDF_TEST_EXPECT_COLUMNS_EQUAL(result->view(), expected);
+  result = cudf::strings::split_record(sv, empty);
+  CUDF_TEST_EXPECT_COLUMNS_EQUAL(result->view(), expected);
+
+  result = cudf::strings::rsplit_record(sv, delimiter);
+  CUDF_TEST_EXPECT_COLUMNS_EQUAL(result->view(), expected);
+  result = cudf::strings::rsplit_record(sv, empty);
+  CUDF_TEST_EXPECT_COLUMNS_EQUAL(result->view(), expected);
+}
+
 TEST_F(StringsSplitTest, MultiByteDelimiters)
 {
   // Overlapping delimiters