-
Notifications
You must be signed in to change notification settings - Fork 1.7k
python: fix segfault on empty argv
in main()
#2003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
d9d0138
to
82f5ae1
Compare
82f5ae1
to
7fe6010
Compare
I think there's more explicit and expressive way to update the logic:
should I change it, @LebedevRI? |
7fe6010
to
f04717f
Compare
f04717f
to
91c8495
Compare
Now I'm glad with this simple fix @LebedevRI |
btw, my initial command for reproducing the issue is no longer giving me segmentation fault, it just says |
if (!ptrs.empty()) { | ||
// The `argv` pointers here become invalid when this function returns, but | ||
// benchmark holds the pointer to `argv[0]`. We create a static copy of it | ||
// so it persists, and replace the pointer below. | ||
static std::string executable_name(argv[0]); | ||
ptrs[0] = const_cast<char*>(executable_name.c_str()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this just exchange one bug for another?
The comment suggests that something uses the binary name (argv[0]
) later on,
but now instead of "crashing" here, we'll crash the code that tries to take argv[0]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code that tries to take argv[0]
is in benchmark::Initialize
, and there's already a check that ensures that it does not happen when argc
is 0. That's why this little change is enough. I'm not sure how to make the comment better.
@@ -14,16 +14,18 @@ namespace { | |||
namespace nb = nanobind; | |||
|
|||
std::vector<std::string> Initialize(const std::vector<std::string>& argv) { | |||
// The `argv` pointers here become invalid when this function returns, but |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-std::vector<std::string> Initialize(const std::vector<std::string>& argv) {
- // The `argv` pointers here become invalid when this function returns, but
- // benchmark holds the pointer to `argv[0]`. We create a static copy of it
- // so it persists, and replace the pointer below.
- static std::string executable_name(argv[0]);
- std::vector<char*> ptrs;
- ptrs.reserve(argv.size());
- for (auto& arg : argv) {
- ptrs.push_back(const_cast<char*>(arg.c_str()));
- }
- ptrs[0] = const_cast<char*>(executable_name.c_str());
- int argc = static_cast<int>(argv.size());
- benchmark::Initialize(&argc, ptrs.data());
- std::vector<std::string> remaining_argv;
- remaining_argv.reserve(argc);
- for (int i = 0; i < argc; ++i) {
- remaining_argv.emplace_back(ptrs[i]);
- }
- return remaining_argv;
-}
+std::vector<std::string> Initialize(const std::vector<std::string>& argv) {
+ // The `argv` pointers here become invalid when this function returns, but
+ // benchmark holds the pointer to `argv[0]`. We create a static copy of it
+ // so it persists, and replace the pointer below.
+ std::vector<char*> ptrs;
+ if(argv.empty()) {
+ static std::string executable_name("unknown");
+ ptrs.emplace_back(executable_name.c_str());
+ } else {
+ ptrs.reserve(argv.size());
+ for (auto& arg : argv) {
+ ptrs.push_back(const_cast<char*>(arg.c_str()));
+ }
+ static std::string executable_name(argv[0]);
+ ptrs[0] = const_cast<char*>(executable_name.c_str());
+ }
+ int argc = static_cast<int>(ptrs.size());
+ benchmark::Initialize(&argc, ptrs.data());
+ std::vector<std::string> remaining_argv;
+ remaining_argv.reserve(argc);
+ for (int i = 0; i < argc; ++i) {
+ remaining_argv.emplace_back(ptrs[i]);
+ }
+ return remaining_argv;
+}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is okay to pass empty array to benchmark::Initialize
Lines 753 to 754 in b20cea6
BenchmarkReporter::Context::executable_name = | |
((argc != nullptr) && *argc > 0) ? argv[0] : "unknown"; |
I don't really touch python stuff here. |
test:
python -c 'import google_benchmark as b;b.register(print);b.main([]);'