This is an automated email from the ASF dual-hosted git repository.
yangxk1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-graphar.git
The following commit(s) were added to refs/heads/main by this push:
new 9816a9ee fix(cpp): remove UB when reading unset builder vertex id
(#892)
9816a9ee is described below
commit 9816a9eebea929d93a881d16b0bd33555dc7d6c7
Author: Jinye Wu <[email protected]>
AuthorDate: Sun Aug 16 23:41:43 2026 +0800
fix(cpp): remove UB when reading unset builder vertex id (#892)
* use optional and remove empty_
* chore: trigger CI
---
cpp/src/graphar/high-level/vertices_builder.h | 25 ++++++++++++++++---------
cpp/test/test_builder.cc | 17 +++++++++++++++++
python/src/bindings/high_level_binding.cc | 2 +-
python/test/test_high_level_api.py | 10 ++++++++++
4 files changed, 44 insertions(+), 10 deletions(-)
diff --git a/cpp/src/graphar/high-level/vertices_builder.h
b/cpp/src/graphar/high-level/vertices_builder.h
index 019df6f0..4ddccada 100644
--- a/cpp/src/graphar/high-level/vertices_builder.h
+++ b/cpp/src/graphar/high-level/vertices_builder.h
@@ -23,6 +23,7 @@
#include <cassert>
#include <cstddef>
#include <memory>
+#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
@@ -51,21 +52,30 @@ namespace graphar::builder {
*/
class Vertex {
public:
- Vertex() : empty_(true) {}
+ Vertex() = default;
/**
* @brief Initialize the vertex with a given id.
*
* @param id The id of the vertex.
*/
- explicit Vertex(IdType id) : id_(id), empty_(false) {}
+ explicit Vertex(IdType id) : id_(id) {}
/**
* @brief Get id of the vertex.
*
+ * The id is absent until explicitly set or assigned by VerticesBuilder.
+ *
* @return The id of the vertex.
*/
- IdType GetId() const noexcept { return id_; }
+ IdType GetId() const { return id_.value(); }
+
+ /**
+ * @brief Check if the vertex id has been initialized.
+ *
+ * @return true/false.
+ */
+ bool HasId() const noexcept { return id_.has_value(); }
/**
* @brief Set id of the vertex.
@@ -75,11 +85,11 @@ class Vertex {
void SetId(IdType id) { id_ = id; }
/**
- * @brief Check if the vertex is empty.
+ * @brief Check if the vertex contains no property payload.
*
* @return true/false.
*/
- bool Empty() const noexcept { return empty_; }
+ bool Empty() const noexcept { return properties_.empty(); }
/**
* @brief Add a property to the vertex.
@@ -89,7 +99,6 @@ class Vertex {
*/
// TODO(@acezen): Enable the property to be a vector(list).
void AddProperty(const std::string& name, const std::any& val) {
- empty_ = false;
properties_[name] = val;
}
@@ -100,7 +109,6 @@ class Vertex {
AddProperty(name, val);
return;
}
- empty_ = false;
if (cardinalities_.find(name) != cardinalities_.end()) {
if (cardinalities_[name] != cardinality) {
throw std::runtime_error("Cardinality mismatch for property: " + name);
@@ -211,8 +219,7 @@ class Vertex {
}
private:
- IdType id_;
- bool empty_;
+ std::optional<IdType> id_;
std::unordered_map<std::string, std::any> properties_;
std::unordered_map<std::string, Cardinality> cardinalities_;
};
diff --git a/cpp/test/test_builder.cc b/cpp/test/test_builder.cc
index b97648f2..244f0d8c 100644
--- a/cpp/test/test_builder.cc
+++ b/cpp/test/test_builder.cc
@@ -67,6 +67,18 @@ TEST_CASE_METHOD(GlobalFixture, "Test_vertices_builder") {
builder->SetValidateLevel(ValidateLevel::strong_validate);
REQUIRE(builder->GetValidateLevel() == ValidateLevel::strong_validate);
+ // vertex id and payload state are tracked independently
+ builder::Vertex empty_vertex;
+ REQUIRE_FALSE(empty_vertex.HasId());
+ REQUIRE(empty_vertex.Empty());
+ REQUIRE_THROWS_AS(empty_vertex.GetId(), std::bad_optional_access);
+ empty_vertex.SetId(42);
+ REQUIRE(empty_vertex.HasId());
+ REQUIRE(empty_vertex.GetId() == 42);
+ REQUIRE(empty_vertex.Empty());
+ empty_vertex.AddProperty("id", int64_t{42});
+ REQUIRE_FALSE(empty_vertex.Empty());
+
// check different validate levels
builder::Vertex v;
v.AddProperty("id", "id_of_string");
@@ -84,6 +96,11 @@ TEST_CASE_METHOD(GlobalFixture, "Test_vertices_builder") {
builder->Clear();
REQUIRE(builder->GetNum() == 0);
+ builder::Vertex indexed_vertex(7);
+ REQUIRE(indexed_vertex.HasId());
+ REQUIRE(indexed_vertex.GetId() == 7);
+ REQUIRE(indexed_vertex.Empty());
+
// add vertices
std::ifstream fp(test_data_dir + "/ldbc_sample/person_0_0.csv");
std::string line;
diff --git a/python/src/bindings/high_level_binding.cc
b/python/src/bindings/high_level_binding.cc
index d13fda76..15777c64 100644
--- a/python/src/bindings/high_level_binding.cc
+++ b/python/src/bindings/high_level_binding.cc
@@ -415,4 +415,4 @@ extern "C" void bind_high_level_api(pybind11::module_& m) {
py::arg("dst_type"), py::arg("adj_list_type"), py::arg("num_vertices"),
py::arg("writer_options") = nullptr,
py::arg("validate_level") = graphar::ValidateLevel::no_validate);
-} // namespace graphar
\ No newline at end of file
+} // namespace graphar
diff --git a/python/test/test_high_level_api.py
b/python/test/test_high_level_api.py
index 8ab2bcbb..cc76f48d 100644
--- a/python/test/test_high_level_api.py
+++ b/python/test/test_high_level_api.py
@@ -111,6 +111,16 @@ def test_vertices_builder(sample_graph_vertex):
# Set validate level
builder.SetValidateLevel(ValidateLevel.strong_validate)
+ empty_vertex = BuilderVertex()
+ assert empty_vertex.Empty()
+ with pytest.raises(Exception):
+ empty_vertex.GetId()
+ empty_vertex.SetId(42)
+ assert empty_vertex.GetId() == 42
+ assert empty_vertex.Empty()
+ empty_vertex.AddProperty("id", 42)
+ assert not empty_vertex.Empty()
+
# Prepare vertex data
vertex_count = 3
property_names = ["id", "firstName", "lastName", "gender"]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]