Base: Fixed segfault on destructing cached string (#20563)

* Base: Fixed segfault on destructing cached string

Xerces default memory manager is deleted before destructing static local
variable and segfault.

---------

Co-authored-by: Chris Hennes <chennes@pioneerlibrarysystem.org>
This commit is contained in:
Kohei Takahashi
2025-05-16 02:23:03 +09:00
committed by GitHub
parent 238957fb16
commit b54898f05f
3 changed files with 58 additions and 3 deletions

View File

@@ -67,6 +67,7 @@
#include <map>
#include <memory>
#include <mutex>
#include <new>
#include <numbers>
#include <queue>
#include <set>
@@ -82,6 +83,7 @@
#include <sstream>
// Xerces
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XercesVersion.hpp>
#include <xercesc/dom/DOM.hpp>
@@ -95,6 +97,7 @@
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/framework/MemoryManager.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/XMLUniDefs.hpp>

View File

@@ -23,6 +23,11 @@
#include "PreCompiled.h"
#ifndef _PreComp_
#include <xercesc/framework/MemoryManager.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#endif
#include "Exception.h"
#include "XMLTools.h"
@@ -128,3 +133,19 @@ void XMLTools::terminate()
{
transcoder.reset();
}
void* XStrMemoryManager::allocate(XMLSize_t size)
{
auto ptr = ::operator new(static_cast<size_t>(size),
static_cast<std::align_val_t>(alignof(XMLCh)),
std::nothrow);
if (ptr == nullptr && size != 0) {
throw XERCES_CPP_NAMESPACE::OutOfMemoryException();
}
return ptr;
}
void XStrMemoryManager::deallocate(void* p)
{
::operator delete(p);
}

View File

@@ -28,6 +28,7 @@
#include <memory>
#include <ostream>
#include <xercesc/util/TransService.hpp>
#include <xercesc/framework/MemoryManager.hpp>
#ifndef XERCES_CPP_NAMESPACE_BEGIN
#define XERCES_CPP_NAMESPACE_QUALIFIER
@@ -58,6 +59,23 @@ private:
static std::unique_ptr<XERCES_CPP_NAMESPACE::XMLTranscoder> transcoder; // NOLINT
};
// Helper class for XStrLiteral macro
// This implementation is almost same as Xerces default memory manager.
class BaseExport XStrMemoryManager final: public XERCES_CPP_NAMESPACE::MemoryManager
{
public:
XStrMemoryManager() = default;
~XStrMemoryManager() = default;
MemoryManager* getExceptionMemoryManager() override
{
return this;
}
void* allocate(XMLSize_t size) override;
void deallocate(void* p) override;
};
//**************************************************************************
//**************************************************************************
// StrXLocal
@@ -149,6 +167,8 @@ class XStr
public:
/// Constructors and Destructor
explicit XStr(const char* const toTranscode);
explicit XStr(const char* const toTranscode,
XERCES_CPP_NAMESPACE_QUALIFIER MemoryManager* memMgr);
~XStr();
@@ -159,24 +179,35 @@ public:
private:
/// This is the Unicode XMLCh format of the string.
XMLCh* fUnicodeForm;
XERCES_CPP_NAMESPACE_QUALIFIER MemoryManager* memMgr;
};
inline XStr::XStr(const char* const toTranscode)
: fUnicodeForm(XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode(toTranscode))
: XStr(toTranscode, XERCES_CPP_NAMESPACE_QUALIFIER XMLPlatformUtils::fgMemoryManager)
{}
inline XStr::XStr(const char* const toTranscode,
XERCES_CPP_NAMESPACE_QUALIFIER MemoryManager* memMgr)
: fUnicodeForm(XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode(toTranscode, memMgr))
, memMgr(memMgr)
{}
inline XStr::~XStr()
{
XERCES_CPP_NAMESPACE_QUALIFIER XMLString::release(&fUnicodeForm);
XERCES_CPP_NAMESPACE_QUALIFIER XMLString::release(&fUnicodeForm, memMgr);
}
// Uses the compiler to create a cache of transcoded string literals so that each subsequent call
// can reuse the data from the lambda's initial creation. Permits the same usage as
// XStr("literal").unicodeForm()
// XStrLiteral macro use local memory manager instance to prevent segfault on releasing cached
// string because xerces default memory manager is already deleted when destructing local static
// variable.
#define XStrLiteral(literal) \
([]() -> const XStr& { \
static const XStr str {literal}; \
static XStrMemoryManager memMgr; \
static const XStr str {literal, &memMgr}; \
return str; \
}())