From d3e3526111097560cf7c002613e2cb1d469b59e0 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer <wellnhofer@aevum.de> Date: Sat, 21 Dec 2024 16:03:46 +0100 Subject: [PATCH] xpath: Use separate static hash table for standard functions

This avoids registering standard functions when creating an XPath context.

Lookup of extension functions is a bit slower now, but ultimately, all function lookups should be moved to the compilation phase.

(cherry picked from commit bf5fcf6e646bb51a0f6a3655a1d64bea97274867)


xpath.c | 170 ++++++++++++++++++++++++++++++++------------------------
1 file changed, 98 insertions(+), 72 deletions(-)

diff –git a/xpath.c b/xpath.c index 485d7747..21711653 100644 — a/xpath.c +++ b/xpath.c @@ -136,11 +136,48 @@

#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)

-/************************************************************************

    • *

    • Floating point stuff *

    • *

  • ************************************************************************/

+static void +xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs); + +static const struct { + const char *name; + xmlXPathFunction func; +} xmlXPathStandardFunctions[] = { + { “boolean”, xmlXPathBooleanFunction }, + { “ceiling”, xmlXPathCeilingFunction }, + { “count”, xmlXPathCountFunction }, + { “concat”, xmlXPathConcatFunction }, + { “contains”, xmlXPathContainsFunction }, + { “id”, xmlXPathIdFunction }, + { “false”, xmlXPathFalseFunction }, + { “floor”, xmlXPathFloorFunction }, + { “last”, xmlXPathLastFunction }, + { “lang”, xmlXPathLangFunction }, + { “local-name”, xmlXPathLocalNameFunction }, + { “not”, xmlXPathNotFunction }, + { “name”, xmlXPathNameFunction }, + { “namespace-uri”, xmlXPathNamespaceURIFunction }, + { “normalize-space”, xmlXPathNormalizeFunction }, + { “number”, xmlXPathNumberFunction }, + { “position”, xmlXPathPositionFunction }, + { “round”, xmlXPathRoundFunction }, + { “string”, xmlXPathStringFunction }, + { “string-length”, xmlXPathStringLengthFunction }, + { “starts-with”, xmlXPathStartsWithFunction }, + { “substring”, xmlXPathSubstringFunction }, + { “substring-before”, xmlXPathSubstringBeforeFunction }, + { “substring-after”, xmlXPathSubstringAfterFunction }, + { “sum”, xmlXPathSumFunction }, + { “true”, xmlXPathTrueFunction }, + { “translate”, xmlXPathTranslateFunction } +}; + +#define NUM_STANDARD_FUNCTIONS \ + (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions)) + +#define SF_HASH_SIZE 64 + +static unsigned char xmlXPathSFHash;

double xmlXPathNAN = 0.0;
double xmlXPathPINF = 0.0;

@@ -156,6 +193,18 @@ xmlXPathInit(void) {

    xmlInitParser();
}

+ATTRIBUTE_NO_SANITIZE_INTEGER +static unsigned +xmlXPathSFComputeHash(const xmlChar *name) { + unsigned hashValue = 5381; + const xmlChar *ptr; + + for (ptr = name; *ptr; ptr++) + hashValue = hashValue * 33 + *ptr; + + return(hashValue); +} +

/**
 * xmlInitXPathInternal:
 *

@@ -164,6 +213,8 @@ xmlXPathInit(void) {

ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
void
xmlInitXPathInternal(void) {

+ size_t i; +

#if defined(NAN) && defined(INFINITY)
    xmlXPathNAN = NAN;
    xmlXPathPINF = INFINITY;

@@ -175,8 +226,34 @@ xmlInitXPathInternal(void) {

    xmlXPathPINF = 1.0 / zero;
    xmlXPathNINF = -xmlXPathPINF;
#endif

+ + /* + * Initialize hash table for standard functions + */ + + for (i = 0; i < SF_HASH_SIZE; i++) + xmlXPathSFHash = UCHAR_MAX; + + for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) { + const char *name = xmlXPathStandardFunctions.name; + int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE; + + while (xmlXPathSFHash != UCHAR_MAX) { + bucketIndex += 1; + if (bucketIndex >= SF_HASH_SIZE) + bucketIndex = 0; + } + + xmlXPathSFHash = i; + }

}

+/************************************************************************ + * * + * Floating point stuff * + * * + ************************************************************************/ +

/**
 * xmlXPathIsNaN:
 * @val:  a double value

@@ -3979,18 +4056,6 @@ xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,

 */
xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  • if (ctxt == NULL)

  • return (NULL);

-

  • if (ctxt->funcLookupFunc != NULL) {

  • xmlXPathFunction ret;

  • xmlXPathFuncLookupFunc f;

-

  • f = ctxt->funcLookupFunc;

  • ret = f(ctxt->funcLookupData, name, NULL);

  • if (ret != NULL)

  • return(ret);

  • } return(xmlXPathFunctionLookupNS(ctxt, name, NULL));

}

@@ -4015,6 +4080,22 @@ xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,

if (name == NULL)
   return(NULL);

+ if (ns_uri == NULL) { + int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE; + + while (xmlXPathSFHash != UCHAR_MAX) { + int funcIndex = xmlXPathSFHash; + + if (strcmp(xmlXPathStandardFunctions.name, + (char *) name) == 0) + return(xmlXPathStandardFunctions.func); + + bucketIndex += 1; + if (bucketIndex >= SF_HASH_SIZE) + bucketIndex = 0; + } + } +

if (ctxt->funcLookupFunc != NULL) {
   xmlXPathFuncLookupFunc f;

@@ -13494,61 +13575,6 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {

void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
{
  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“boolean”,

  • xmlXPathBooleanFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“ceiling”,

  • xmlXPathCeilingFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“count”,

  • xmlXPathCountFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“concat”,

  • xmlXPathConcatFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“contains”,

  • xmlXPathContainsFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“id”,

  • xmlXPathIdFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“false”,

  • xmlXPathFalseFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“floor”,

  • xmlXPathFloorFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“last”,

  • xmlXPathLastFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“lang”,

  • xmlXPathLangFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“local-name”,

  • xmlXPathLocalNameFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“not”,

  • xmlXPathNotFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“name”,

  • xmlXPathNameFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“namespace-uri”,

  • xmlXPathNamespaceURIFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“normalize-space”,

  • xmlXPathNormalizeFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“number”,

  • xmlXPathNumberFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“position”,

  • xmlXPathPositionFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“round”,

  • xmlXPathRoundFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“string”,

  • xmlXPathStringFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“string-length”,

  • xmlXPathStringLengthFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“starts-with”,

  • xmlXPathStartsWithFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“substring”,

  • xmlXPathSubstringFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“substring-before”,

  • xmlXPathSubstringBeforeFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“substring-after”,

  • xmlXPathSubstringAfterFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“sum”,

  • xmlXPathSumFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“true”,

  • xmlXPathTrueFunction);

  • xmlXPathRegisterFunc(ctxt, (const xmlChar *)“translate”,

  • xmlXPathTranslateFunction);

-

xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
    (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
                     xmlXPathEscapeUriFunction);

– 2.47.1