From 01185de23baa9bb3896eebee0c7f06d53299ae50 Mon Sep 17 00:00:00 2001 From: Aysha Afrah Ziya Date: Wed, 7 Oct 2026 14:22:08 +0530 Subject: [PATCH] compare SimpleString content with memcmp instead of strncmp strncmp stops at the first NUL byte, so two different strings of equal length that agree up to an embedded NUL compared equal, while operator< ordered the same pair with memcmp. Embedded NUL bytes reach a blackboard string through ImportBlackboardFromJSON, where a JSON escape decodes to a real NUL, and the scripting == and != operators compare through SimpleString. --- .../behaviortree_cpp/utils/simple_string.hpp | 7 ++++-- tests/gtest_simple_string.cpp | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/behaviortree_cpp/utils/simple_string.hpp b/include/behaviortree_cpp/utils/simple_string.hpp index 809860eaa..0a4b438a8 100644 --- a/include/behaviortree_cpp/utils/simple_string.hpp +++ b/include/behaviortree_cpp/utils/simple_string.hpp @@ -110,13 +110,16 @@ class SimpleString bool operator==(const SimpleString& other) const { const size_t N = size(); - return other.size() == N && std::strncmp(data(), other.data(), N) == 0; + // memcmp, not strncmp: the content may hold embedded NUL bytes, and strncmp + // stops at the first one, reporting two different strings of equal length as + // equal. It is also what operator< below compares with. + return other.size() == N && std::memcmp(data(), other.data(), N) == 0; } bool operator!=(const SimpleString& other) const { const size_t N = size(); - return other.size() != N || std::strncmp(data(), other.data(), N) != 0; + return other.size() != N || std::memcmp(data(), other.data(), N) != 0; } bool operator<=(const SimpleString& other) const diff --git a/tests/gtest_simple_string.cpp b/tests/gtest_simple_string.cpp index 579951d97..fc103e529 100644 --- a/tests/gtest_simple_string.cpp +++ b/tests/gtest_simple_string.cpp @@ -377,6 +377,31 @@ TEST(SimpleStringTest, EmptyStringComparison) EXPECT_TRUE(nonEmpty >= empty1); } +// Test comparison of strings that hold embedded NUL bytes +TEST(SimpleStringTest, ComparisonWithEmbeddedNull) +{ + const SimpleString s1(std::string("a\0b", 3)); + const SimpleString s2(std::string("a\0c", 3)); + const SimpleString s3(std::string("a\0b", 3)); + + EXPECT_FALSE(s1 == s2); + EXPECT_TRUE(s1 != s2); + EXPECT_TRUE(s1 < s2); + EXPECT_FALSE(s1 > s2); + + EXPECT_TRUE(s1 == s3); + EXPECT_FALSE(s1 != s3); + + // same thing with the heap representation + const SimpleString l1(std::string("0123456789abcdef\0b", 18)); + const SimpleString l2(std::string("0123456789abcdef\0c", 18)); + + EXPECT_FALSE(l1.isSOO()); + EXPECT_FALSE(l1 == l2); + EXPECT_TRUE(l1 != l2); + EXPECT_TRUE(l1 < l2); +} + // Test that SimpleString size is as expected (16 bytes) TEST(SimpleStringTest, SizeOfSimpleString) {