4444#include " valueflow.h"
4545#include " version.h"
4646
47+ #ifdef HAVE_RULES
48+ #include " regex.h"
49+ #endif
50+
4751#include < algorithm>
4852#include < cassert>
4953#include < cstdio>
6670#include < vector>
6771
6872#include " json.h"
69-
70- #include < simplecpp.h>
71-
7273#include " xml.h"
7374
74- #ifdef HAVE_RULES
75- #ifdef _WIN32
76- #define PCRE_STATIC
77- #endif
78- #include < pcre.h>
79- #endif
75+ #include < simplecpp.h>
8076
8177class SymbolDatabase ;
8278
@@ -1440,135 +1436,6 @@ bool CppCheck::hasRule(const std::string &tokenlist) const
14401436 });
14411437}
14421438
1443- static const char * pcreErrorCodeToString (const int pcreExecRet)
1444- {
1445- switch (pcreExecRet) {
1446- case PCRE_ERROR_NULL:
1447- return " Either code or subject was passed as NULL, or ovector was NULL "
1448- " and ovecsize was not zero (PCRE_ERROR_NULL)" ;
1449- case PCRE_ERROR_BADOPTION:
1450- return " An unrecognized bit was set in the options argument (PCRE_ERROR_BADOPTION)" ;
1451- case PCRE_ERROR_BADMAGIC:
1452- return " PCRE stores a 4-byte \" magic number\" at the start of the compiled code, "
1453- " to catch the case when it is passed a junk pointer and to detect when a "
1454- " pattern that was compiled in an environment of one endianness is run in "
1455- " an environment with the other endianness. This is the error that PCRE "
1456- " gives when the magic number is not present (PCRE_ERROR_BADMAGIC)" ;
1457- case PCRE_ERROR_UNKNOWN_NODE:
1458- return " While running the pattern match, an unknown item was encountered in the "
1459- " compiled pattern. This error could be caused by a bug in PCRE or by "
1460- " overwriting of the compiled pattern (PCRE_ERROR_UNKNOWN_NODE)" ;
1461- case PCRE_ERROR_NOMEMORY:
1462- return " If a pattern contains back references, but the ovector that is passed "
1463- " to pcre_exec() is not big enough to remember the referenced substrings, "
1464- " PCRE gets a block of memory at the start of matching to use for this purpose. "
1465- " If the call via pcre_malloc() fails, this error is given. The memory is "
1466- " automatically freed at the end of matching. This error is also given if "
1467- " pcre_stack_malloc() fails in pcre_exec(). "
1468- " This can happen only when PCRE has been compiled with "
1469- " --disable-stack-for-recursion (PCRE_ERROR_NOMEMORY)" ;
1470- case PCRE_ERROR_NOSUBSTRING:
1471- return " This error is used by the pcre_copy_substring(), pcre_get_substring(), "
1472- " and pcre_get_substring_list() functions (see below). "
1473- " It is never returned by pcre_exec() (PCRE_ERROR_NOSUBSTRING)" ;
1474- case PCRE_ERROR_MATCHLIMIT:
1475- return " The backtracking limit, as specified by the match_limit field in a pcre_extra "
1476- " structure (or defaulted) was reached. "
1477- " See the description above (PCRE_ERROR_MATCHLIMIT)" ;
1478- case PCRE_ERROR_CALLOUT:
1479- return " This error is never generated by pcre_exec() itself. "
1480- " It is provided for use by callout functions that want to yield a distinctive "
1481- " error code. See the pcrecallout documentation for details (PCRE_ERROR_CALLOUT)" ;
1482- case PCRE_ERROR_BADUTF8:
1483- return " A string that contains an invalid UTF-8 byte sequence was passed as a subject, "
1484- " and the PCRE_NO_UTF8_CHECK option was not set. If the size of the output vector "
1485- " (ovecsize) is at least 2, the byte offset to the start of the the invalid UTF-8 "
1486- " character is placed in the first element, and a reason code is placed in the "
1487- " second element. The reason codes are listed in the following section. For "
1488- " backward compatibility, if PCRE_PARTIAL_HARD is set and the problem is a truncated "
1489- " UTF-8 character at the end of the subject (reason codes 1 to 5), "
1490- " PCRE_ERROR_SHORTUTF8 is returned instead of PCRE_ERROR_BADUTF8" ;
1491- case PCRE_ERROR_BADUTF8_OFFSET:
1492- return " The UTF-8 byte sequence that was passed as a subject was checked and found to "
1493- " be valid (the PCRE_NO_UTF8_CHECK option was not set), but the value of "
1494- " startoffset did not point to the beginning of a UTF-8 character or the end of "
1495- " the subject (PCRE_ERROR_BADUTF8_OFFSET)" ;
1496- case PCRE_ERROR_PARTIAL:
1497- return " The subject string did not match, but it did match partially. See the "
1498- " pcrepartial documentation for details of partial matching (PCRE_ERROR_PARTIAL)" ;
1499- case PCRE_ERROR_BADPARTIAL:
1500- return " This code is no longer in use. It was formerly returned when the PCRE_PARTIAL "
1501- " option was used with a compiled pattern containing items that were not supported "
1502- " for partial matching. From release 8.00 onwards, there are no restrictions on "
1503- " partial matching (PCRE_ERROR_BADPARTIAL)" ;
1504- case PCRE_ERROR_INTERNAL:
1505- return " An unexpected internal error has occurred. This error could be caused by a bug "
1506- " in PCRE or by overwriting of the compiled pattern (PCRE_ERROR_INTERNAL)" ;
1507- case PCRE_ERROR_BADCOUNT:
1508- return " This error is given if the value of the ovecsize argument is negative "
1509- " (PCRE_ERROR_BADCOUNT)" ;
1510- case PCRE_ERROR_RECURSIONLIMIT:
1511- return " The internal recursion limit, as specified by the match_limit_recursion "
1512- " field in a pcre_extra structure (or defaulted) was reached. "
1513- " See the description above (PCRE_ERROR_RECURSIONLIMIT)" ;
1514- case PCRE_ERROR_DFA_UITEM:
1515- return " PCRE_ERROR_DFA_UITEM" ;
1516- case PCRE_ERROR_DFA_UCOND:
1517- return " PCRE_ERROR_DFA_UCOND" ;
1518- case PCRE_ERROR_DFA_WSSIZE:
1519- return " PCRE_ERROR_DFA_WSSIZE" ;
1520- case PCRE_ERROR_DFA_RECURSE:
1521- return " PCRE_ERROR_DFA_RECURSE" ;
1522- case PCRE_ERROR_NULLWSLIMIT:
1523- return " PCRE_ERROR_NULLWSLIMIT" ;
1524- case PCRE_ERROR_BADNEWLINE:
1525- return " An invalid combination of PCRE_NEWLINE_xxx options was "
1526- " given (PCRE_ERROR_BADNEWLINE)" ;
1527- case PCRE_ERROR_BADOFFSET:
1528- return " The value of startoffset was negative or greater than the length "
1529- " of the subject, that is, the value in length (PCRE_ERROR_BADOFFSET)" ;
1530- case PCRE_ERROR_SHORTUTF8:
1531- return " This error is returned instead of PCRE_ERROR_BADUTF8 when the subject "
1532- " string ends with a truncated UTF-8 character and the PCRE_PARTIAL_HARD option is set. "
1533- " Information about the failure is returned as for PCRE_ERROR_BADUTF8. "
1534- " It is in fact sufficient to detect this case, but this special error code for "
1535- " PCRE_PARTIAL_HARD precedes the implementation of returned information; "
1536- " it is retained for backwards compatibility (PCRE_ERROR_SHORTUTF8)" ;
1537- case PCRE_ERROR_RECURSELOOP:
1538- return " This error is returned when pcre_exec() detects a recursion loop "
1539- " within the pattern. Specifically, it means that either the whole pattern "
1540- " or a subpattern has been called recursively for the second time at the same "
1541- " position in the subject string. Some simple patterns that might do this "
1542- " are detected and faulted at compile time, but more complicated cases, "
1543- " in particular mutual recursions between two different subpatterns, "
1544- " cannot be detected until run time (PCRE_ERROR_RECURSELOOP)" ;
1545- case PCRE_ERROR_JIT_STACKLIMIT:
1546- return " This error is returned when a pattern that was successfully studied "
1547- " using a JIT compile option is being matched, but the memory available "
1548- " for the just-in-time processing stack is not large enough. See the pcrejit "
1549- " documentation for more details (PCRE_ERROR_JIT_STACKLIMIT)" ;
1550- case PCRE_ERROR_BADMODE:
1551- return " This error is given if a pattern that was compiled by the 8-bit library "
1552- " is passed to a 16-bit or 32-bit library function, or vice versa (PCRE_ERROR_BADMODE)" ;
1553- case PCRE_ERROR_BADENDIANNESS:
1554- return " This error is given if a pattern that was compiled and saved is reloaded on a "
1555- " host with different endianness. The utility function pcre_pattern_to_host_byte_order() "
1556- " can be used to convert such a pattern so that it runs on the new host (PCRE_ERROR_BADENDIANNESS)" ;
1557- case PCRE_ERROR_DFA_BADRESTART:
1558- return " PCRE_ERROR_DFA_BADRESTART" ;
1559- #if PCRE_MAJOR >= 8 && PCRE_MINOR >= 32
1560- case PCRE_ERROR_BADLENGTH:
1561- return " This error is given if pcre_exec() is called with a negative value for the length argument (PCRE_ERROR_BADLENGTH)" ;
1562- case PCRE_ERROR_JIT_BADOPTION:
1563- return " This error is returned when a pattern that was successfully studied using a JIT compile "
1564- " option is being matched, but the matching mode (partial or complete match) does not correspond "
1565- " to any JIT compilation mode. When the JIT fast path function is used, this error may be "
1566- " also given for invalid options. See the pcrejit documentation for more details (PCRE_ERROR_JIT_BADOPTION)" ;
1567- #endif
1568- }
1569- return " " ;
1570- }
1571-
15721439void CppCheck::executeRules (const std::string &tokenlist, const TokenList &list)
15731440{
15741441 // There is no rule to execute
@@ -1590,73 +1457,7 @@ void CppCheck::executeRules(const std::string &tokenlist, const TokenList &list)
15901457 mErrorLogger .reportOut (" Processing rule: " + rule.pattern , Color::FgGreen);
15911458 }
15921459
1593- const char *pcreCompileErrorStr = nullptr ;
1594- int erroffset = 0 ;
1595- pcre * const re = pcre_compile (rule.pattern .c_str (),0 ,&pcreCompileErrorStr,&erroffset,nullptr );
1596- if (!re) {
1597- if (pcreCompileErrorStr) {
1598- const std::string msg = " pcre_compile failed: " + std::string (pcreCompileErrorStr);
1599- const ErrorMessage errmsg ({},
1600- " " ,
1601- Severity::error,
1602- msg,
1603- " pcre_compile" ,
1604- Certainty::normal);
1605-
1606- mErrorLogger .reportErr (errmsg);
1607- }
1608- continue ;
1609- }
1610-
1611- // Optimize the regex, but only if PCRE_CONFIG_JIT is available
1612- #ifdef PCRE_CONFIG_JIT
1613- const char *pcreStudyErrorStr = nullptr ;
1614- pcre_extra * const pcreExtra = pcre_study (re, PCRE_STUDY_JIT_COMPILE, &pcreStudyErrorStr);
1615- // pcre_study() returns NULL for both errors and when it can not optimize the regex.
1616- // The last argument is how one checks for errors.
1617- // It is NULL if everything works, and points to an error string otherwise.
1618- if (pcreStudyErrorStr) {
1619- const std::string msg = " pcre_study failed: " + std::string (pcreStudyErrorStr);
1620- const ErrorMessage errmsg ({},
1621- " " ,
1622- Severity::error,
1623- msg,
1624- " pcre_study" ,
1625- Certainty::normal);
1626-
1627- mErrorLogger .reportErr (errmsg);
1628- // pcre_compile() worked, but pcre_study() returned an error. Free the resources allocated by pcre_compile().
1629- pcre_free (re);
1630- continue ;
1631- }
1632- #else
1633- const pcre_extra * const pcreExtra = nullptr ;
1634- #endif
1635-
1636- int pos = 0 ;
1637- int ovector[30 ]= {0 };
1638- while (pos < static_cast <int >(str.size ())) {
1639- const int pcreExecRet = pcre_exec (re, pcreExtra, str.c_str (), static_cast <int >(str.size ()), pos, 0 , ovector, 30 );
1640- if (pcreExecRet < 0 ) {
1641- const std::string errorMessage = pcreErrorCodeToString (pcreExecRet);
1642- if (!errorMessage.empty ()) {
1643- const ErrorMessage errmsg ({},
1644- " " ,
1645- Severity::error,
1646- std::string (" pcre_exec failed: " ) + errorMessage,
1647- " pcre_exec" ,
1648- Certainty::normal);
1649-
1650- mErrorLogger .reportErr (errmsg);
1651- }
1652- break ;
1653- }
1654- const auto pos1 = static_cast <unsigned int >(ovector[0 ]);
1655- const auto pos2 = static_cast <unsigned int >(ovector[1 ]);
1656-
1657- // jump to the end of the match for the next pcre_exec
1658- pos = static_cast <int >(pos2);
1659-
1460+ auto f = [&](int pos1, int pos2) {
16601461 // determine location..
16611462 int fileIndex = 0 ;
16621463 int line = 0 ;
@@ -1685,15 +1486,19 @@ void CppCheck::executeRules(const std::string &tokenlist, const TokenList &list)
16851486
16861487 // Report error
16871488 mErrorLogger .reportErr (errmsg);
1688- }
1489+ };
16891490
1690- pcre_free (re);
1691- #ifdef PCRE_CONFIG_JIT
1692- // Free up the EXTRA PCRE value (may be NULL at this point)
1693- if (pcreExtra) {
1694- pcre_free_study (pcreExtra);
1491+ const std::string err = rule.regex .match (str, f);
1492+ if (!err.empty ()) {
1493+ const ErrorMessage errmsg (std::list<ErrorMessage::FileLocation>(),
1494+ emptyString,
1495+ Severity::error,
1496+ err,
1497+ " pcre_exec" ,
1498+ Certainty::normal);
1499+
1500+ mErrorLogger .reportErr (errmsg);
16951501 }
1696- #endif
16971502 }
16981503}
16991504#endif
0 commit comments