Prevent using temporary codec-for-locale UTF8 replacement

Utf8CodecForLocaleReplacer's temporary codec-for-locale replacements
cause race conditions in unrelated code that calls
QTextCodec::codecForLocale(). Implement and use a wrapper function that
calls QTextCodec::codecForLocale() while holding
Utf8CodecForLocaleReplacer's mutex lock to fix it.

f0b66f7507 and this commit fix #1587.

Combine several chained QString::arg() calls into one in
EpwingBook::setErrorString(). A single call is more efficient and
prevents unintended replacement inside previous argument substitutions.
This commit is contained in:
Igor Kushnir 2022-11-24 23:45:59 +02:00 committed by Abs62
parent 0ae3fdf2bd
commit be22bb9ffd
4 changed files with 25 additions and 4 deletions

View file

@ -420,10 +420,10 @@ EpwingBook::~EpwingBook()
void EpwingBook::setErrorString( QString const & func, EB_Error_Code code ) void EpwingBook::setErrorString( QString const & func, EB_Error_Code code )
{ {
QTextCodec * const localeCodec = gdCodecForLocale();
error_string = QString( "EB \"%1\" function error: %2 (%3)" ) error_string = QString( "EB \"%1\" function error: %2 (%3)" )
.arg( func ) .arg( func, localeCodec->toUnicode( eb_error_string( code ) ),
.arg( QTextCodec::codecForLocale()->toUnicode( eb_error_string( code ) ) ) localeCodec->toUnicode( eb_error_message( code ) ) );
.arg( QTextCodec::codecForLocale()->toUnicode( eb_error_message( code ) ) );
if( currentPosition.page != 0 ) if( currentPosition.page != 0 )
error_string += QString( " on page %1, offset %2" ).arg( QString::number( currentPosition.page ) ) error_string += QString( " on page %1, offset %2" ).arg( QString::number( currentPosition.page ) )

View file

@ -2,6 +2,7 @@
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */ * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#include <QMutex> #include <QMutex>
#include <QMutexLocker>
#include <QTextCodec> #include <QTextCodec>
#include <QString> #include <QString>
#include "gddebug.hh" #include "gddebug.hh"
@ -13,6 +14,17 @@ namespace {
class Utf8CodecForLocaleReplacer class Utf8CodecForLocaleReplacer
{ {
public: public:
static QTextCodec * originalCodecForLocale()
{
if( !shouldReplaceCodecForLocale() )
return QTextCodec::codecForLocale();
// codecForLocaleMutex is locked while the UTF8 codec replaces the original codec.
// Thus calling QTextCodec::codecForLocale() while holding a lock is guaranteed to
// return the original codec, not its temporary UTF8 replacement.
QMutexLocker _( &codecForLocaleMutex );
return QTextCodec::codecForLocale();
}
Utf8CodecForLocaleReplacer(): Utf8CodecForLocaleReplacer():
replaceCodecForLocale( shouldReplaceCodecForLocale() ), localeCodec( 0 ) replaceCodecForLocale( shouldReplaceCodecForLocale() ), localeCodec( 0 )
{ {
@ -68,3 +80,8 @@ void gdDebug(const char *msg, ...)
} }
va_end(ap); va_end(ap);
} }
QTextCodec * gdCodecForLocale()
{
return Utf8CodecForLocaleReplacer::originalCodecForLocale();
}

View file

@ -3,6 +3,8 @@
#include <QFile> #include <QFile>
class QTextCodec;
#ifdef NO_CONSOLE #ifdef NO_CONSOLE
#define GD_DPRINTF(...) do {} while( 0 ) #define GD_DPRINTF(...) do {} while( 0 )
#define GD_FDPRINTF(...) do {} while( 0 ) #define GD_FDPRINTF(...) do {} while( 0 )
@ -27,6 +29,8 @@ void gdDebug(const char *, ...)
#endif #endif
; ;
QTextCodec * gdCodecForLocale();
extern QFile * logFilePtr; extern QFile * logFilePtr;
#endif // __GDDEBUG_HH_INCLUDED__ #endif // __GDDEBUG_HH_INCLUDED__

View file

@ -133,7 +133,7 @@ bool IndexedZip::indexFile( BtreeIndexing::IndexedWords &zipFileNames, quint32 *
// File seems to be a valid zip file // File seems to be a valid zip file
QTextCodec * localeCodec = QTextCodec::codecForLocale(); QTextCodec * const localeCodec = gdCodecForLocale();
ZipFile::CentralDirEntry entry; ZipFile::CentralDirEntry entry;