-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Use StringData for Nix language value documentation too
#14527
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: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,7 +108,7 @@ struct PrimOp | |
| /** | ||
| * Optional free-form documentation about the primop. | ||
| */ | ||
| const char * doc = nullptr; | ||
| const StringData * doc = nullptr; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PrimOp is usually not traced, so these StringData would get collected and become a dangling reference. The C API does allocate them on the GC heap because I needed dynamically allocated ones for NixOps4, but the other, "static" primops will reference garbage.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I made these all be statically allocated |
||
|
|
||
| /** | ||
| * Add a trace item, while calling the `<name>` builtin. | ||
|
|
@@ -156,7 +156,7 @@ struct Constant | |
| /** | ||
| * Optional free-form documentation about the constant. | ||
| */ | ||
| const char * doc = nullptr; | ||
| const StringData * doc = nullptr; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same |
||
|
|
||
| /** | ||
| * Whether the constant is impure, and not available in pure mode. | ||
|
|
@@ -837,11 +837,7 @@ public: | |
| std::optional<std::string> name; | ||
| size_t arity; | ||
| std::vector<std::string> args; | ||
| /** | ||
| * Unlike the other `doc` fields in this file, this one should never be | ||
| * `null`. | ||
| */ | ||
| const char * doc; | ||
| const StringData & doc; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably be similar to the |
||
| }; | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| #pragma once | ||
| ///@file | ||
|
|
||
| #include "nix/expr/value.hh" | ||
| #include "nix/expr/string-data.hh" | ||
|
|
||
| namespace nix { | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| #pragma once | ||
| ///@file | ||
|
|
||
| #include <cstddef> | ||
| #include <cstring> | ||
| #include <memory_resource> | ||
| #include <string_view> | ||
|
|
||
| namespace nix { | ||
|
|
||
| class StringData | ||
| { | ||
| public: | ||
| using size_type = std::size_t; | ||
|
|
||
| size_type size_; | ||
| char data_[]; | ||
|
|
||
| /* | ||
| * This in particular ensures that we cannot have a `StringData` | ||
| * that we use by value, which is just what we want! | ||
| * | ||
| * Dynamically sized types aren't a thing in C++ and even flexible array | ||
| * members are a language extension and beyond the realm of standard C++. | ||
| * Technically, sizeof data_ member is 0 and the intended way to use flexible | ||
| * array members is to allocate sizeof(StrindData) + count * sizeof(char) bytes | ||
| * and the compiler will consider alignment restrictions for the FAM. | ||
| * | ||
| */ | ||
|
|
||
| StringData(StringData &&) = delete; | ||
| StringData & operator=(StringData &&) = delete; | ||
| StringData(const StringData &) = delete; | ||
| StringData & operator=(const StringData &) = delete; | ||
| ~StringData() = default; | ||
|
|
||
| private: | ||
| StringData() = delete; | ||
|
|
||
| explicit StringData(size_type size) | ||
| : size_(size) | ||
| { | ||
| } | ||
|
|
||
| public: | ||
| /** | ||
| * Allocate StringData on the (possibly) GC-managed heap and copy | ||
| * the contents of s to it. | ||
| */ | ||
| static const StringData & make(std::string_view s); | ||
|
|
||
| /** | ||
| * Allocate StringData on the (possibly) GC-managed heap. | ||
| * @param size Length of the string (without the NUL terminator). | ||
| */ | ||
| static StringData & alloc(size_t size); | ||
|
|
||
| size_t size() const | ||
| { | ||
| return size_; | ||
| } | ||
|
|
||
| char * data() noexcept | ||
| { | ||
| return data_; | ||
| } | ||
|
|
||
| const char * data() const noexcept | ||
| { | ||
| return data_; | ||
| } | ||
|
|
||
| const char * c_str() const noexcept | ||
| { | ||
| return data_; | ||
| } | ||
|
|
||
| constexpr std::string_view view() const noexcept | ||
| { | ||
| return std::string_view(data_, size_); | ||
| } | ||
|
|
||
| template<size_t N> | ||
| struct Static; | ||
|
|
||
| static StringData & make(std::pmr::memory_resource & resource, std::string_view s) | ||
| { | ||
| auto & res = | ||
| *new (resource.allocate(sizeof(StringData) + s.size() + 1, alignof(StringData))) StringData(s.size()); | ||
| std::memcpy(res.data_, s.data(), s.size()); | ||
| res.data_[s.size()] = '\0'; | ||
| return res; | ||
| } | ||
| }; | ||
|
|
||
| } // namespace nix |
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.
This seems to be a reference to a local temporary
StringDatawhich promptly becomes a dangling pointer.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 turning a reference into a pointer, and the reference is to a freshly heap-allocated thing, so actually it is fine.
(It errs on the side of leaking without GC, not on the side of the lifetime being too short and getting heap corruption.)