Rework null terminated arrays

Several functions including wgetopt and execve operate on null-terminated
arrays of nul-terminated pointers: a list of pointers to C strings where
the last pointer is null. Prior to this change, each process_t stored its
argv in such an array. This had two problems:

1. It was awkward to work with this type, instead of using std::vector,
etc.
2. The process's arguments would be rearranged by builtins which is
surprising

Our null terminated arrays were built around a fancy type that would copy
input strings and also generate an array of pointers to them, in one big
allocation.

Switch to a new model where we construct an array of pointers over
existing strings. So you can supply a `vector<string>` and now
`null_terminated_array_t` will just make a list of pointers to them. Now
processes can just store their argv in a familiar wcstring_list_t.
This commit is contained in:
ridiculousfish
2021-02-14 13:15:29 -08:00
parent e0e4b11dbd
commit fb92ad946b
12 changed files with 127 additions and 209 deletions

View File

@@ -534,7 +534,7 @@ class env_scoped_impl_t : public environment_t {
~env_scoped_impl_t() override = default;
std::shared_ptr<const null_terminated_array_t<char>> export_array();
std::shared_ptr<owning_null_terminated_array_t> export_array();
env_scoped_impl_t(env_scoped_impl_t &&) = delete;
env_scoped_impl_t(const env_scoped_impl_t &) = delete;
@@ -552,7 +552,7 @@ class env_scoped_impl_t : public environment_t {
perproc_data_t perproc_data_{};
// Exported variable array used by execv.
std::shared_ptr<const null_terminated_array_t<char>> export_array_{};
std::shared_ptr<owning_null_terminated_array_t> export_array_{};
// Cached list of export generations corresponding to the above export_array_.
// If this differs from the current export generations then we need to regenerate the array.
@@ -584,7 +584,7 @@ class env_scoped_impl_t : public environment_t {
bool export_array_needs_regeneration() const;
/// \return a newly allocated export array.
std::shared_ptr<const null_terminated_array_t<char>> create_export_array() const;
std::shared_ptr<owning_null_terminated_array_t> create_export_array() const;
};
/// Get the exported variables into a variable table.
@@ -631,8 +631,7 @@ bool env_scoped_impl_t::export_array_needs_regeneration() const {
return mismatch;
}
std::shared_ptr<const null_terminated_array_t<char>> env_scoped_impl_t::create_export_array()
const {
std::shared_ptr<owning_null_terminated_array_t> env_scoped_impl_t::create_export_array() const {
var_table_t table;
FLOG(env_export, L"create_export_array() recalc");
@@ -665,10 +664,10 @@ std::shared_ptr<const null_terminated_array_t<char>> env_scoped_impl_t::create_e
str.append(wcs2string(kv.second.as_string()));
export_list.push_back(std::move(str));
}
return std::make_shared<null_terminated_array_t<char>>(export_list);
return std::make_shared<owning_null_terminated_array_t>(std::move(export_list));
}
std::shared_ptr<const null_terminated_array_t<char>> env_scoped_impl_t::export_array() {
std::shared_ptr<owning_null_terminated_array_t> env_scoped_impl_t::export_array() {
ASSERT_IS_NOT_FORKED_CHILD();
if (export_array_needs_regeneration()) {
export_array_ = create_export_array();
@@ -1341,7 +1340,7 @@ int env_stack_t::remove(const wcstring &key, int mode, std::vector<event_t> *out
return ret.status;
}
std::shared_ptr<const null_terminated_array_t<char>> env_stack_t::export_arr() {
std::shared_ptr<owning_null_terminated_array_t> env_stack_t::export_arr() {
return acquire_impl()->export_array();
}