From e53451b83ead18fab8935f5a99815614490f9878 Mon Sep 17 00:00:00 2001 From: cfillion Date: Wed, 17 Apr 2024 11:20:36 -0400 Subject: [PATCH] fix out-of-bounds read in genversion at a tagged commit + merge the two git describe parsers --- src/vernum.hpp | 7 ++++++ tests/vernum_test.cpp | 15 +++++++++++ tools/genversion.cpp.in | 55 +++++++++++------------------------------ tools/meson.build | 3 ++- 4 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/vernum.hpp b/src/vernum.hpp index 540100780..015c2b2a9 100644 --- a/src/vernum.hpp +++ b/src/vernum.hpp @@ -85,6 +85,13 @@ class VerNum { return vernum; } + constexpr ValT operator[](const unsigned char seg) const + { + if(seg >= MAX_SEGS) + throw reascript_error { "out of range segment" }; + return (m_value >> ((MAX_SEGS - seg - 1) * SEG_BITS)) & SEG_MASK; + } + private: ValT m_value; }; diff --git a/tests/vernum_test.cpp b/tests/vernum_test.cpp index 1a6c67d02..a6bb1058b 100644 --- a/tests/vernum_test.cpp +++ b/tests/vernum_test.cpp @@ -28,3 +28,18 @@ TEST(VerNumTest, FormatString) { EXPECT_EQ(VerNum { "1.2.3.4" }.toString(), "1.2.3.4"); EXPECT_EQ(VerNum { "016.032.064.128" }.toString(), "16.32.64.128"); } + +static void expectSegments(const VerNum &ver, + const std::array &segs) +{ + for(size_t i {}; i < segs.size(); ++i) + EXPECT_EQ(ver[i], segs[i]); +} + +TEST(VerNumTest, SegmentAccess) { + expectSegments("0", { 0, 0, 0, 0 }); + expectSegments("1", { 1, 0, 0, 0 }); + expectSegments("1.2", { 1, 2, 0, 0 }); + expectSegments("1.2.3", { 1, 2, 3, 0 }); + expectSegments("016.032.064.128", { 16, 32, 64, 128 }); +} diff --git a/tools/genversion.cpp.in b/tools/genversion.cpp.in index 5ea510404..f20662208 100644 --- a/tools/genversion.cpp.in +++ b/tools/genversion.cpp.in @@ -15,51 +15,24 @@ * along with this program. If not, see . */ -#include -#include #include -#include -using Segments = std::array; - -static Segments explode(std::string_view version) -{ - Segments segments; - for(std::string_view &segment : segments) { - const auto sep { std::find_if_not(version.begin(), version.end(), - [](char c) { return std::isdigit(c); }) }; - - // reached the end (version is empty) or segment is empty (consecutive dots) - if(sep == version.begin()) { - segment = "0"; - continue; - } - - // FIXME: C++20 - // segment = { version.begin(), segEnd }; - segment = { version.data(), static_cast(sep - version.begin()) }; - - if(*sep == '.') - version.remove_prefix(segment.size() + 1); - else - version = {}; - } - - return segments; -} +#include "../api/compstr.hpp" +#include "../src/vernum.hpp" int main() { // replaced by the output of `git describe`, eg. "v0.8.6.1-8-g19dcefc" - std::string_view version { "@VCS_TAG@" }; - - if(!version.empty() && version.front() == 'v') - version.remove_prefix(1); - - const Segments segments { explode(version) }; - std::cout << "#define REAIMGUI_VERSION \"" << version << "\"\n" - << "#define REAIMGUI_VERSION_MAJOR " << segments[0] << '\n' - << "#define REAIMGUI_VERSION_MINOR " << segments[1] << '\n' - << "#define REAIMGUI_VERSION_PATCH " << segments[2] << '\n' - << "#define REAIMGUI_VERSION_TWEAK " << segments[3] << '\n'; + static constexpr const char gitDescribe[] { "@VCS_TAG@" }; + constexpr VerNum version { CompStr::version<&gitDescribe> }; + + const char *tagVersion { gitDescribe }; + if(*tagVersion == 'v') + ++tagVersion; + + std::cout << "#define REAIMGUI_VERSION \"" << tagVersion << "\"\n" + << "#define REAIMGUI_VERSION_MAJOR " << version[0] << '\n' + << "#define REAIMGUI_VERSION_MINOR " << version[1] << '\n' + << "#define REAIMGUI_VERSION_PATCH " << version[2] << '\n' + << "#define REAIMGUI_VERSION_TWEAK " << version[3] << '\n'; } diff --git a/tools/meson.build b/tools/meson.build index 689867ecd..3db1a586d 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -16,7 +16,8 @@ endif genversion_src = vcs_tag( command: [find_program('git'), 'describe', '--match=v*', '--dirty=+'], input: 'genversion.cpp.in', output: 'genversion.cpp', fallback: '0.0-nogit') -genversion = executable('genversion', genversion_src, native: native) +genversion = executable('genversion', genversion_src, native: native, + dependencies: [compat_dep]) version = custom_target('version.hpp', command: [genversion], capture: true, output: 'version.hpp')