Skip to content

Commit 7406afb

Browse files
fniksiccopybara-github
authored andcommitted
Rename GetInputFileComponents and extract it to a common library.
The new name for the function is `ParseCrashingInputFilename`. It is extracted so that it can be reused in other parts of the code base (in particular, googletest_adapter) which are supported in the CMake builds. PiperOrigin-RevId: 828504089
1 parent 29bde2e commit 7406afb

File tree

9 files changed

+199
-74
lines changed

9 files changed

+199
-74
lines changed

centipede/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ cc_library(
895895
"@abseil-cpp//absl/status:statusor",
896896
"@abseil-cpp//absl/strings",
897897
"@abseil-cpp//absl/time",
898+
"@com_google_fuzztest//common:crashing_input_filename",
898899
"@com_google_fuzztest//common:defs",
899900
"@com_google_fuzztest//common:hash",
900901
"@com_google_fuzztest//common:logging",
@@ -1864,7 +1865,6 @@ cc_test(
18641865
":util",
18651866
":workdir",
18661867
"@abseil-cpp//absl/container:flat_hash_map",
1867-
"@abseil-cpp//absl/status:status_matchers",
18681868
"@abseil-cpp//absl/strings:str_format",
18691869
"@abseil-cpp//absl/time",
18701870
"@com_google_fuzztest//common:defs",

centipede/crash_deduplication.cc

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,14 @@
2626
#include "absl/status/status.h"
2727
#include "absl/status/statusor.h"
2828
#include "absl/strings/str_cat.h"
29-
#include "absl/strings/str_join.h"
30-
#include "absl/strings/str_split.h"
3129
#include "absl/time/clock.h"
3230
#include "absl/time/time.h"
3331
#include "./centipede/centipede_callbacks.h"
3432
#include "./centipede/crash_summary.h"
3533
#include "./centipede/environment.h"
3634
#include "./centipede/runner_result.h"
3735
#include "./centipede/workdir.h"
36+
#include "./common/crashing_input_filename.h"
3837
#include "./common/defs.h"
3938
#include "./common/hash.h"
4039
#include "./common/logging.h"
@@ -102,33 +101,6 @@ absl::flat_hash_map<std::string, CrashDetails> GetCrashesFromWorkdir(
102101
return crashes;
103102
}
104103

105-
absl::StatusOr<InputFileComponents> GetInputFileComponents(
106-
std::string_view input_file_path) {
107-
const std::string file_name =
108-
std::filesystem::path(std::string(input_file_path)).filename();
109-
std::vector<std::string> parts = absl::StrSplit(file_name, '-');
110-
if (parts.size() == 1) {
111-
// Old format where the input file name is both the bug ID and the input
112-
// signature.
113-
return InputFileComponents{
114-
/*bug_id=*/parts[0],
115-
/*crash_signature=*/"",
116-
/*input_signature=*/parts[0],
117-
};
118-
}
119-
if (parts.size() < 3) {
120-
return absl::InvalidArgumentError(
121-
absl::StrCat("Input file name not in the format of "
122-
"<bug_id>-<crash_signature>-<input_signature>: ",
123-
file_name));
124-
}
125-
return InputFileComponents{
126-
/*bug_id=*/absl::StrJoin(parts.begin(), parts.end() - 2, "-"),
127-
/*crash_signature=*/std::move(parts[parts.size() - 2]),
128-
/*input_signature=*/std::move(parts[parts.size() - 1]),
129-
};
130-
}
131-
132104
void OrganizeCrashingInputs(
133105
const std::filesystem::path& regression_dir,
134106
const std::filesystem::path& crashing_dir, const Environment& env,
@@ -154,7 +126,7 @@ void OrganizeCrashingInputs(
154126
const bool is_reproducible = !scoped_callbacks.callbacks()->Execute(
155127
env.binary, {old_input}, batch_result) &&
156128
batch_result.IsInputFailure();
157-
auto input_file_components = GetInputFileComponents(old_input_file);
129+
auto input_file_components = ParseCrashingInputFilename(old_input_file);
158130
FUZZTEST_LOG_IF(WARNING, !input_file_components.ok())
159131
<< "Failed to get input file components for " << old_input_file
160132
<< ". Status: " << input_file_components.status();

centipede/crash_deduplication.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@
1818
#include <cstddef>
1919
#include <filesystem> // NOLINT
2020
#include <string>
21-
#include <string_view>
2221

2322
#include "absl/container/flat_hash_map.h"
24-
#include "absl/status/statusor.h"
2523
#include "./centipede/centipede_callbacks.h"
2624
#include "./centipede/crash_summary.h"
2725
#include "./centipede/environment.h"
@@ -40,24 +38,6 @@ struct CrashDetails {
4038
absl::flat_hash_map<std::string, CrashDetails> GetCrashesFromWorkdir(
4139
const WorkDir& workdir, size_t total_shards);
4240

43-
struct InputFileComponents {
44-
// The identifier that is used to keep track of the crash over time even if
45-
// the crash signature or the crashing input changes.
46-
std::string bug_id;
47-
// The hash of the crash metadata used to deduplicate crashes.
48-
std::string crash_signature;
49-
// The hash of the input.
50-
std::string input_signature;
51-
};
52-
53-
// Returns the components of an input file extracted from the file name.
54-
// The file name is expected to be in the format
55-
// `<bug_id>-<crash_signature>-<input_signature>` or `<input_signature>` for
56-
// backwards compatibility, where `<crash_signature>` and `<input_signature>`
57-
// don't contain dashes.
58-
absl::StatusOr<InputFileComponents> GetInputFileComponents(
59-
std::string_view input_file_path);
60-
6141
// Organizes crashing inputs from `crashing_dir` by attempting to reproduce
6242
// them, and stores new crashes from `new_crashes_by_signature` that are not
6343
// duplicates of existing ones.

centipede/crash_deduplication_test.cc

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include "gmock/gmock.h"
2525
#include "gtest/gtest.h"
2626
#include "absl/container/flat_hash_map.h"
27-
#include "absl/status/status_matchers.h"
2827
#include "absl/strings/str_format.h"
2928
#include "absl/time/clock.h"
3029
#include "absl/time/time.h"
@@ -41,15 +40,12 @@
4140
namespace fuzztest::internal {
4241
namespace {
4342

44-
using ::absl_testing::IsOk;
45-
using ::absl_testing::IsOkAndHolds;
4643
using ::testing::AllOf;
4744
using ::testing::AnyOf;
4845
using ::testing::EndsWith;
4946
using ::testing::FieldsAre;
5047
using ::testing::HasSubstr;
5148
using ::testing::IsEmpty;
52-
using ::testing::Not;
5349
using ::testing::Pair;
5450
using ::testing::UnorderedElementsAre;
5551

@@ -104,25 +100,6 @@ TEST(GetCrashesFromWorkdirTest, ReturnsOneCrashPerCrashSignature) {
104100
Pair("csig2", FieldsAre("isig2", "desc2", input2_path))));
105101
}
106102

107-
TEST(GetInputFileComponentsTest, ParsesFileNameWithOnlyInputSignature) {
108-
EXPECT_THAT(GetInputFileComponents("input_signature"),
109-
IsOkAndHolds(FieldsAre(/*bug_id=*/"input_signature",
110-
/*crash_signature=*/"",
111-
/*input_signature=*/"input_signature")));
112-
}
113-
114-
TEST(GetInputFileComponentsTest, FailsOnInvalidFileName) {
115-
EXPECT_THAT(GetInputFileComponents("single-dash"), Not(IsOk()));
116-
}
117-
118-
TEST(GetInputFileComponentsTest, ParsesFileNameWithAllComponents) {
119-
EXPECT_THAT(
120-
GetInputFileComponents("id-with-dash-crash_signature-input_signature"),
121-
IsOkAndHolds(FieldsAre(/*bug_id=*/"id-with-dash",
122-
/*crash_signature=*/"crash_signature",
123-
/*input_signature=*/"input_signature")));
124-
}
125-
126103
class FakeCentipedeCallbacks : public CentipedeCallbacks {
127104
public:
128105
struct Crash {

common/BUILD

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ cc_library(
8080
}),
8181
)
8282

83+
cc_library(
84+
name = "crashing_input_filename",
85+
srcs = ["crashing_input_filename.cc"],
86+
hdrs = ["crashing_input_filename.h"],
87+
deps = [
88+
"@abseil-cpp//absl/status",
89+
"@abseil-cpp//absl/status:statusor",
90+
"@abseil-cpp//absl/strings",
91+
"@com_google_fuzztest//fuzztest/internal:io",
92+
],
93+
)
94+
8395
cc_library(
8496
name = "defs",
8597
hdrs = ["defs.h"],
@@ -222,6 +234,15 @@ cc_test(
222234
],
223235
)
224236

237+
cc_test(
238+
name = "crashing_input_filename_test",
239+
srcs = ["crashing_input_filename_test.cc"],
240+
deps = [
241+
":crashing_input_filename",
242+
"@googletest//:gtest_main",
243+
],
244+
)
245+
225246
cc_test(
226247
name = "hash_test",
227248
srcs = ["hash_test.cc"],

common/CMakeLists.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ fuzztest_cc_library(
5959
absl::time
6060
)
6161

62+
fuzztest_cc_library(
63+
NAME
64+
crashing_input_filename
65+
HDRS
66+
"crashing_input_filename.h"
67+
SRCS
68+
"crashing_input_filename.cc"
69+
DEPS
70+
absl::status
71+
absl::statusor
72+
absl::strings
73+
fuzztest::io
74+
)
75+
6276
fuzztest_cc_library(
6377
NAME
6478
defs
@@ -178,6 +192,16 @@ fuzztest_cc_test(
178192
GTest::gmock_main
179193
)
180194

195+
fuzztest_cc_test(
196+
NAME
197+
crashing_input_filename_test
198+
SRCS
199+
"crashing_input_filename_test.cc"
200+
DEPS
201+
fuzztest::crashing_input_filename
202+
GTest::gmock_main
203+
)
204+
181205
fuzztest_cc_test(
182206
NAME
183207
hash_test

common/crashing_input_filename.cc

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2025 The Centipede Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "./common/crashing_input_filename.h"
16+
17+
#include <string>
18+
#include <string_view>
19+
#include <utility>
20+
#include <vector>
21+
22+
#include "absl/status/status.h"
23+
#include "absl/status/statusor.h"
24+
#include "absl/strings/str_cat.h"
25+
#include "absl/strings/str_join.h"
26+
#include "absl/strings/str_split.h"
27+
#include "absl/strings/string_view.h"
28+
#include "./fuzztest/internal/io.h"
29+
30+
namespace fuzztest::internal {
31+
32+
absl::StatusOr<InputFileComponents> ParseCrashingInputFilename(
33+
std::string_view input_file_path) {
34+
absl::string_view file_name = Basename(
35+
absl::string_view{input_file_path.data(), input_file_path.size()});
36+
std::vector<std::string> parts = absl::StrSplit(file_name, '-');
37+
if (parts.size() == 1) {
38+
// Old format where the input file name is both the bug ID and the input
39+
// signature.
40+
return InputFileComponents{
41+
/*bug_id=*/parts[0],
42+
/*crash_signature=*/"",
43+
/*input_signature=*/parts[0],
44+
};
45+
}
46+
if (parts.size() < 3) {
47+
return absl::InvalidArgumentError(
48+
absl::StrCat("Input file name not in the format of "
49+
"<bug_id>-<crash_signature>-<input_signature>: ",
50+
file_name));
51+
}
52+
return InputFileComponents{
53+
/*bug_id=*/absl::StrJoin(parts.begin(), parts.end() - 2, "-"),
54+
/*crash_signature=*/std::move(parts[parts.size() - 2]),
55+
/*input_signature=*/std::move(parts[parts.size() - 1]),
56+
};
57+
}
58+
59+
} // namespace fuzztest::internal

common/crashing_input_filename.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2025 The Centipede Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef FUZZTEST_COMMON_CRASHING_INPUT_FILENAME_H_
16+
#define FUZZTEST_COMMON_CRASHING_INPUT_FILENAME_H_
17+
18+
#include <string>
19+
#include <string_view>
20+
21+
#include "absl/status/statusor.h"
22+
23+
namespace fuzztest::internal {
24+
25+
struct InputFileComponents {
26+
// The identifier that is used to keep track of the crash over time even if
27+
// the crash signature or the crashing input changes.
28+
std::string bug_id;
29+
// The hash of the crash metadata used to deduplicate crashes.
30+
std::string crash_signature;
31+
// The hash of the input.
32+
std::string input_signature;
33+
};
34+
35+
// Returns the components of an input file extracted from the file name.
36+
// The file name is expected to be in the format
37+
// `<bug_id>-<crash_signature>-<input_signature>` or `<input_signature>` for
38+
// backwards compatibility, where `<crash_signature>` and `<input_signature>`
39+
// don't contain dashes.
40+
absl::StatusOr<InputFileComponents> ParseCrashingInputFilename(
41+
std::string_view input_file_path);
42+
43+
} // namespace fuzztest::internal
44+
45+
#endif // FUZZTEST_COMMON_CRASHING_INPUT_FILENAME_H_
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2025 The Centipede Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "./common/crashing_input_filename.h"
16+
17+
#include "gmock/gmock.h"
18+
#include "gtest/gtest.h"
19+
20+
namespace fuzztest::internal {
21+
namespace {
22+
23+
using ::testing::FieldsAre;
24+
25+
TEST(ParseCrashingInputFilenameTest, ParsesFileNameWithOnlyInputSignature) {
26+
auto components = ParseCrashingInputFilename("input_signature");
27+
ASSERT_TRUE(components.ok());
28+
EXPECT_THAT(*components, FieldsAre(/*bug_id=*/"input_signature",
29+
/*crash_signature=*/"",
30+
/*input_signature=*/"input_signature"));
31+
}
32+
33+
TEST(ParseCrashingInputFilenameTest, FailsOnInvalidFileName) {
34+
EXPECT_FALSE(ParseCrashingInputFilename("single-dash").ok());
35+
}
36+
37+
TEST(ParseCrashingInputFilenameTest, ParsesFileNameWithAllComponents) {
38+
auto components = ParseCrashingInputFilename(
39+
"id-with-dash-crash_signature-input_signature");
40+
ASSERT_TRUE(components.ok());
41+
EXPECT_THAT(*components, FieldsAre(/*bug_id=*/"id-with-dash",
42+
/*crash_signature=*/"crash_signature",
43+
/*input_signature=*/"input_signature"));
44+
}
45+
46+
} // namespace
47+
} // namespace fuzztest::internal

0 commit comments

Comments
 (0)