The standard says that it is invalid for more than one grammar element
to be set in a value of type regex_constants::syntax_option_type. This
adds a check in the regex compiler andthrows an exception if an invalid
value is used.

Signed-off-by: Jonathan Wakely <jwak...@redhat.com>

libstdc++-v3/ChangeLog:

        * include/bits/regex_compiler.h (_Compiler::_S_validate): New
        function.
        * include/bits/regex_compiler.tcc (_Compiler::_Compiler): Use
        _S_validate to check flags.
        * include/bits/regex_error.h (_S_grammar): New error code for
        internal use.
        * testsuite/28_regex/basic_regex/ctors/grammar.cc: New test.

Tested x86_64-linux. Committed to trunk.

commit 9ca4c42a3b756e54a92ff8e1ac6c396b680b7839
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Wed Sep 29 13:48:15 2021

    libstdc++: Check for invalid syntax_option_type values in <regex>
    
    The standard says that it is invalid for more than one grammar element
    to be set in a value of type regex_constants::syntax_option_type. This
    adds a check in the regex compiler andthrows an exception if an invalid
    value is used.
    
    Signed-off-by: Jonathan Wakely <jwak...@redhat.com>
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/regex_compiler.h (_Compiler::_S_validate): New
            function.
            * include/bits/regex_compiler.tcc (_Compiler::_Compiler): Use
            _S_validate to check flags.
            * include/bits/regex_error.h (_S_grammar): New error code for
            internal use.
            * testsuite/28_regex/basic_regex/ctors/grammar.cc: New test.

diff --git a/libstdc++-v3/include/bits/regex_compiler.h 
b/libstdc++-v3/include/bits/regex_compiler.h
index 898607d81c6..62a49bf52cf 100644
--- a/libstdc++-v3/include/bits/regex_compiler.h
+++ b/libstdc++-v3/include/bits/regex_compiler.h
@@ -143,6 +143,26 @@ namespace __detail
        return ret;
       }
 
+      static _FlagT
+      _S_validate(_FlagT __f)
+      {
+       using namespace regex_constants;
+       switch (__f & (ECMAScript|basic|extended|awk|grep|egrep))
+         {
+         case ECMAScript:
+         case basic:
+         case extended:
+         case awk:
+         case grep:
+         case egrep:
+           return __f;
+         case _FlagT(0):
+           return __f | ECMAScript;
+         default:
+           std::__throw_regex_error(_S_grammar, "conflicting grammar options");
+         }
+      }
+
       _FlagT              _M_flags;
       _ScannerT           _M_scanner;
       shared_ptr<_RegexT> _M_nfa;
diff --git a/libstdc++-v3/include/bits/regex_compiler.tcc 
b/libstdc++-v3/include/bits/regex_compiler.tcc
index 1bd30972cbb..956262a12c9 100644
--- a/libstdc++-v3/include/bits/regex_compiler.tcc
+++ b/libstdc++-v3/include/bits/regex_compiler.tcc
@@ -65,15 +65,7 @@ namespace __detail
     _Compiler<_TraitsT>::
     _Compiler(const _CharT* __b, const _CharT* __e,
              const typename _TraitsT::locale_type& __loc, _FlagT __flags)
-    : _M_flags((__flags
-               & (regex_constants::ECMAScript
-                  | regex_constants::basic
-                  | regex_constants::extended
-                  | regex_constants::grep
-                  | regex_constants::egrep
-                  | regex_constants::awk))
-              ? __flags
-              : __flags | regex_constants::ECMAScript),
+    : _M_flags(_S_validate(__flags)),
       _M_scanner(__b, __e, _M_flags, __loc),
       _M_nfa(make_shared<_RegexT>(__loc, _M_flags)),
       _M_traits(_M_nfa->_M_traits),
diff --git a/libstdc++-v3/include/bits/regex_error.h 
b/libstdc++-v3/include/bits/regex_error.h
index 722ce26cda3..e7b7b420ec4 100644
--- a/libstdc++-v3/include/bits/regex_error.h
+++ b/libstdc++-v3/include/bits/regex_error.h
@@ -61,7 +61,8 @@ namespace regex_constants
       _S_error_badrepeat,
       _S_error_complexity,
       _S_error_stack,
-      _S_null
+      _S_null,
+      _S_grammar
     };
 
   /** The expression contained an invalid collating element name. */
diff --git a/libstdc++-v3/testsuite/28_regex/basic_regex/ctors/grammar.cc 
b/libstdc++-v3/testsuite/28_regex/basic_regex/ctors/grammar.cc
new file mode 100644
index 00000000000..fd8531c4530
--- /dev/null
+++ b/libstdc++-v3/testsuite/28_regex/basic_regex/ctors/grammar.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++11 } }
+#include <regex>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::regex re{""};
+  VERIFY( re.flags() & std::regex::ECMAScript );
+
+  std::regex re2{"", std::regex::flag_type{}};
+  VERIFY( re2.flags() == std::regex::flag_type() ); // See also PR 83598
+}
+
+void
+test02()
+{
+  // A valid value of type syntax_option_type shall have at most one of the
+  // grammar elements ECMAScript, basic, extended, awk, grep, egrep, set.
+
+  try
+  {
+    std::regex{"", std::regex::ECMAScript|std::regex::basic};
+    VERIFY( false );
+  }
+  catch (const std::regex_error&)
+  {
+  }
+
+  try
+  {
+    std::regex{"", std::regex::extended|std::regex::basic};
+    VERIFY( false );
+  }
+  catch (const std::regex_error&)
+  {
+  }
+
+  try
+  {
+    std::regex{"", std::regex::grep|std::regex::basic};
+    VERIFY( false );
+  }
+  catch (const std::regex_error&)
+  {
+  }
+}
+
+int main()
+{
+  test01();
+  test02();
+}

Reply via email to