From 2ff856f1cb8940bf6af31482058967eda1a54bc0 Mon Sep 17 00:00:00 2001
From: c4pp4
Date: Mon, 26 Oct 2026 01:30:11 +0100
Subject: [PATCH 1/1] Migrate Validator from PCRE to PCRE2

Build against libpcre2-8 because libpcre3 is unmaintained.

Free the compiled pattern in the destructor and before compiling it
again in InitRegExp(), which is also called from the assignment
operators of IntegerValidator, DoubleValidator and HexRegExpValidator
(the old pattern leaked). Return Invalid for a NULL string instead of
calling strlen() on it. Define PCRE2_CODE_UNIT_WIDTH in the installed
Validator.h only if not already defined.

Signed-off-by: c4pp4
---
 Nux/Validator.cpp | 61 +++++++++++++++++++++++++++++++----------------
 Nux/Validator.h   |  7 ++++--
 Nux/nux.pc.in     |  2 +-
 configure.ac      |  2 +-
 4 files changed, 48 insertions(+), 24 deletions(-)

diff --git a/Nux/Validator.cpp b/Nux/Validator.cpp
index 0723930..14b88ba 100644
--- a/Nux/Validator.cpp
+++ b/Nux/Validator.cpp
@@ -27,12 +27,18 @@ namespace nux
 {
 
   Validator::Validator()
+#if !defined(NUX_OS_WINDOWS)
+    : _regexp(nullptr)
+#endif
   {
   }
 
   Validator::~Validator()
   {
-
+#if !defined(NUX_OS_WINDOWS)
+    if (_regexp)
+      pcre2_code_free(_regexp);
+#endif
   }
 
   bool Validator::InitRegExp()
@@ -41,18 +47,29 @@ namespace nux
     regex_ = _regexp_str.c_str();
     return true;
 #else
-    const char *error;
-    int   erroffset;
-    _regexp = pcre_compile(
-      _regexp_str.c_str(),    /* the pattern */
-      PCRE_MULTILINE,
-      &error,         /* for error message */
-      &erroffset,     /* for error offset */
-      0);             /* use default character tables */
+    if (_regexp)
+    {
+      pcre2_code_free(_regexp);
+      _regexp = nullptr;
+    }
+
+    int        errorcode;
+    PCRE2_SIZE erroroffset;
+    _regexp = pcre2_compile(
+      reinterpret_cast<PCRE2_SPTR>(_regexp_str.c_str()),  /* pattern */
+      PCRE2_ZERO_TERMINATED,                              /* pattern length */
+      PCRE2_MULTILINE,                                    /* option bits */
+      &errorcode,                                         /* error code */
+      &erroroffset,                                       /* error offset */
+      nullptr);                                           /* compile context */
 
     if (!_regexp)
     {
-      nuxDebugMsg("[IntegerValidator::IntegerValidator] Invalid regular expression: %s", _regexp_str.c_str());
+      PCRE2_UCHAR buffer[256];
+      pcre2_get_error_message(errorcode, buffer, sizeof(buffer) / sizeof(buffer[0]));
+      nuxDebugMsg("[Validator::InitRegExp] Invalid regular expression '%s' "
+                  "at offset %d: %s",
+                  _regexp_str.c_str(), (int)erroroffset, buffer);
       return false;
     }    
     return true;
@@ -72,20 +89,24 @@ namespace nux
     }
     return Validator::Acceptable;
 #else
-    if (_regexp == 0)
+    if (!_regexp || !str)
       return Validator::Invalid;
 
-    int out_vector [10];
-    unsigned int offset = 0;
-    int len = (int) strlen(str);
+    pcre2_match_data *match_data =
+        pcre2_match_data_create_from_pattern(_regexp, nullptr);
+
+    int rc = pcre2_match(
+        _regexp,                                   /* compiled pattern */
+        reinterpret_cast<PCRE2_SPTR>(str),         /* subject string */
+        PCRE2_ZERO_TERMINATED,                     /* auto-determine length */
+        0,                                         /* start offset */
+        0,                                         /* match options */
+        match_data,                                /* match data block */
+        nullptr);                                  /* match context */
 
-    // See the "PCRE DISCUSSION OF STACK USAGE" and why it maybe necessary to limit the stack usage.
-    pcre_extra extra;
-    extra.flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION;
-    extra.match_limit_recursion = 2000; 
+    pcre2_match_data_free(match_data);
 
-    int rc = pcre_exec(_regexp, &extra, str, len, offset, 0, out_vector, 10);
-    if (rc <= -1)
+    if (rc < 0)
     {
       return Validator::Invalid;
     }
diff --git a/Nux/Validator.h b/Nux/Validator.h
index ed729fc..bc2f885 100644
--- a/Nux/Validator.h
+++ b/Nux/Validator.h
@@ -26,7 +26,10 @@
 #if defined(NUX_OS_WINDOWS)
   #include <regex>
 #else
-  #include <pcre.h>
+  #ifndef PCRE2_CODE_UNIT_WIDTH
+    #define PCRE2_CODE_UNIT_WIDTH 8
+  #endif
+  #include <pcre2.h>
 #endif
 
 namespace nux
@@ -57,7 +60,7 @@ namespace nux
 #if defined(NUX_OS_WINDOWS)
     std::regex regex_;
 #else
-    pcre *_regexp;
+    pcre2_code *_regexp;
 #endif
   };
 }
diff --git a/Nux/nux.pc.in b/Nux/nux.pc.in
index a5f6c14..a0f8c0c 100644
--- a/Nux/nux.pc.in
+++ b/Nux/nux.pc.in
@@ -8,4 +8,4 @@ Description: Nux OpenGL Toolkit
 Version: @VERSION@
 Libs: -L${libdir} -lnux-@NUX_API_VERSION@
 Cflags: -I${includedir}/Nux-@NUX_API_VERSION@
-Requires: glib-2.0 nux-core-@NUX_API_VERSION@ nux-graphics-@NUX_API_VERSION@ @GL_PKGS@ sigc++-2.0 libpcre
+Requires: glib-2.0 nux-core-@NUX_API_VERSION@ nux-graphics-@NUX_API_VERSION@ @GL_PKGS@ sigc++-2.0 libpcre2-8
diff --git a/configure.ac b/configure.ac
index a375300..8b047e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -196,7 +196,7 @@ PKG_CHECK_MODULES(NUX,
                   sigc++-2.0
                   pango
                   pangocairo
-                  libpcre
+                  libpcre2-8
                   )
 AC_SUBST(NUX_CFLAGS)
 AC_SUBST(NUX_LIBS)
-- 
2.55.0

