fix: crash when magnet dn isn't utf-8 (#5244)
This commit is contained in:
parent
ca44c9143a
commit
c60bb5b834
|
@ -402,6 +402,7 @@
|
|||
C809AEE7291ECFD000BFDBE1 /* NSDataAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = C809AEE6291ECFD000BFDBE1 /* NSDataAdditions.mm */; };
|
||||
C82B30312953337B0001BD6E /* NSDataAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = C809AEE6291ECFD000BFDBE1 /* NSDataAdditions.mm */; };
|
||||
C841A28129197724009F18E8 /* NSKeyedUnarchiverAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = C841A28029197724009F18E8 /* NSKeyedUnarchiverAdditions.mm */; };
|
||||
C843FC8429C51B9400491854 /* utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = C843FC8329C51B9400491854 /* utils.mm */; };
|
||||
C86BCD9928228A9600F45599 /* SparkleProxy.mm in Sources */ = {isa = PBXBuildFile; fileRef = C86BCD9828228A9600F45599 /* SparkleProxy.mm */; };
|
||||
C87369652809984200573C90 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C87369642809984200573C90 /* UserNotifications.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
C8748D8A29891EA100D9E979 /* suffixes_dafsa.h in Headers */ = {isa = PBXBuildFile; fileRef = C8748D8929891EA100D9E979 /* suffixes_dafsa.h */; };
|
||||
|
@ -1207,6 +1208,7 @@
|
|||
C81E411127F5BABD00652F56 /* CocoaCompatibility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CocoaCompatibility.h; sourceTree = "<group>"; };
|
||||
C841A27F29197724009F18E8 /* NSKeyedUnarchiverAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSKeyedUnarchiverAdditions.h; sourceTree = "<group>"; };
|
||||
C841A28029197724009F18E8 /* NSKeyedUnarchiverAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NSKeyedUnarchiverAdditions.mm; sourceTree = "<group>"; };
|
||||
C843FC8329C51B9400491854 /* utils.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = utils.mm; sourceTree = "<group>"; };
|
||||
C86BCD9828228A9600F45599 /* SparkleProxy.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SparkleProxy.mm; sourceTree = "<group>"; };
|
||||
C87369642809984200573C90 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
|
||||
C8748D8929891EA100D9E979 /* suffixes_dafsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = suffixes_dafsa.h; path = "third-party/suffixes_dafsa.h"; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -1793,6 +1795,7 @@
|
|||
BEFC1DF30C07861A00B0BB3C /* port-forwarding-upnp.h */,
|
||||
BEFC1DF20C07861A00B0BB3C /* utils.cc */,
|
||||
BEFC1DF10C07861A00B0BB3C /* utils.h */,
|
||||
C843FC8329C51B9400491854 /* utils.mm */,
|
||||
A25BFD63167BED3B0039D1AA /* variant-benc.cc */,
|
||||
A25BFD64167BED3B0039D1AA /* variant-common.h */,
|
||||
A25BFD65167BED3B0039D1AA /* variant-json.cc */,
|
||||
|
@ -3082,6 +3085,7 @@
|
|||
A220EC5B118C8A060022B4BE /* tr-lpd.cc in Sources */,
|
||||
C1FEE57A1C3223CC00D62832 /* watchdir.cc in Sources */,
|
||||
A23547E211CD0B090046EAE6 /* cache.cc in Sources */,
|
||||
C843FC8429C51B9400491854 /* utils.mm in Sources */,
|
||||
A284214412DA663E00FBDDBB /* tr-udp.cc in Sources */,
|
||||
C17740D5273A002C00E455D2 /* web-utils.cc in Sources */,
|
||||
A2679294130E00A000CB7464 /* tr-utp.cc in Sources */,
|
||||
|
|
|
@ -150,6 +150,7 @@ target_sources(${TR_NAME}
|
|||
utils-ev.h
|
||||
utils.cc
|
||||
utils.h
|
||||
utils.mm
|
||||
variant-benc.cc
|
||||
variant-common.h
|
||||
variant-converters.cc
|
||||
|
@ -198,6 +199,7 @@ tr_allow_compile_if(
|
|||
watchdir-kqueue.cc
|
||||
[=[[APPLE]]=]
|
||||
tr-assert.mm
|
||||
utils.mm
|
||||
[=[[NOT APPLE]]=]
|
||||
tr-assert.cc
|
||||
[=[[WIN32]]=]
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "announce-list.h"
|
||||
#include "tr-strbuf.h" // tr_urlbuf
|
||||
#include "utils.h" // tr_strv_convert_utf8()
|
||||
|
||||
struct tr_error;
|
||||
struct tr_variant;
|
||||
|
@ -69,7 +70,7 @@ public:
|
|||
|
||||
void setName(std::string_view name)
|
||||
{
|
||||
name_ = name;
|
||||
name_ = tr_strv_convert_utf8(name);
|
||||
}
|
||||
|
||||
void addWebseed(std::string_view webseed);
|
||||
|
|
|
@ -329,11 +329,11 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
|
|||
}
|
||||
else if (pathIs(CommentKey) || pathIs(CommentUtf8Key))
|
||||
{
|
||||
tm_.comment_ = tr_strv_replace_invalid(value);
|
||||
tm_.comment_ = tr_strv_convert_utf8(value);
|
||||
}
|
||||
else if (pathIs(CreatedByKey) || pathIs(CreatedByUtf8Key))
|
||||
{
|
||||
tm_.creator_ = tr_strv_replace_invalid(value);
|
||||
tm_.creator_ = tr_strv_convert_utf8(value);
|
||||
}
|
||||
else if (
|
||||
pathIs(SourceKey) || pathIs(InfoKey, SourceKey) || //
|
||||
|
@ -344,7 +344,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
|
|||
// to have the same use as the 'source' key
|
||||
// http://wiki.bitcomet.com/inside_bitcomet
|
||||
|
||||
tm_.source_ = tr_strv_replace_invalid(value);
|
||||
tm_.source_ = tr_strv_convert_utf8(value);
|
||||
}
|
||||
else if (pathIs(AnnounceKey))
|
||||
{
|
||||
|
@ -360,7 +360,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
|
|||
}
|
||||
else if (pathIs(InfoKey, NameKey) || pathIs(InfoKey, NameUtf8Key))
|
||||
{
|
||||
tm_.name_ = tr_strv_replace_invalid(value);
|
||||
tm_.setName(value);
|
||||
}
|
||||
else if (pathIs(InfoKey, PiecesKey))
|
||||
{
|
||||
|
@ -393,7 +393,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
|
|||
else if (pathIs(MagnetInfoKey, DisplayNameKey))
|
||||
{
|
||||
// compatibility with Transmission <= 3.0
|
||||
tm_.name_ = tr_strv_replace_invalid(value);
|
||||
tm_.setName(value);
|
||||
}
|
||||
else if (pathIs(MagnetInfoKey, InfoHashKey))
|
||||
{
|
||||
|
|
|
@ -268,9 +268,24 @@ double tr_getRatio(uint64_t numerator, uint64_t denominator)
|
|||
|
||||
// ---
|
||||
|
||||
#ifndef __APPLE__
|
||||
|
||||
std::string tr_strv_convert_utf8(std::string_view sv)
|
||||
{
|
||||
return tr_strv_replace_invalid(sv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::string tr_strv_replace_invalid(std::string_view sv, uint32_t replacement)
|
||||
{
|
||||
// stripping characters after first \0
|
||||
if (auto first_null = sv.find('\0'); first_null != std::string::npos)
|
||||
{
|
||||
sv = { std::data(sv), first_null };
|
||||
}
|
||||
auto out = std::string{};
|
||||
out.reserve(std::size(sv));
|
||||
utf8::unchecked::replace_invalid(std::data(sv), std::data(sv) + std::size(sv), std::back_inserter(out), replacement);
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -204,6 +204,8 @@ constexpr bool tr_strvSep(std::string_view* sv, std::string_view* token, char de
|
|||
|
||||
[[nodiscard]] std::string_view tr_strvStrip(std::string_view str);
|
||||
|
||||
[[nodiscard]] std::string tr_strv_convert_utf8(std::string_view sv);
|
||||
|
||||
[[nodiscard]] std::string tr_strv_replace_invalid(std::string_view sv, uint32_t replacement = 0xFFFD /*<2A>*/);
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// macOS implementation of tr_strv_convert_utf8() that autodetects the encoding.
|
||||
// This replaces the generic implementation of the function in utils.cc.
|
||||
|
||||
std::string tr_strv_convert_utf8(std::string_view sv)
|
||||
{
|
||||
// UTF-8 encoding
|
||||
char const* validUTF8 = [[NSString alloc] initWithBytes:std::data(sv) length:std::size(sv) encoding:NSUTF8StringEncoding].UTF8String;
|
||||
if (validUTF8)
|
||||
{
|
||||
return std::string(validUTF8);
|
||||
}
|
||||
|
||||
// autodetection of the encoding (#3434)
|
||||
NSString* convertedString;
|
||||
NSStringEncoding stringEncoding = [NSString
|
||||
stringEncodingForData:[NSData dataWithBytes:std::data(sv) length:std::size(sv)]
|
||||
encodingOptions:@{
|
||||
// We disallow lossy conversion, and will leave it to `utf8::unchecked::replace_invalid`.
|
||||
NSStringEncodingDetectionAllowLossyKey : @NO,
|
||||
// We only set the likely language.
|
||||
// If we were to set suggested encodings, then whatever is listed first would take precedence on all others, making for instance kCFStringEncodingDOSJapanese (cp932) and kCFStringEncodingDOSRussian (cp866) taking priority on each other.
|
||||
NSStringEncodingDetectionLikelyLanguageKey : NSLocale.currentLocale.languageCode
|
||||
}
|
||||
convertedString:&convertedString
|
||||
usedLossyConversion:nil];
|
||||
if (stringEncoding)
|
||||
{
|
||||
validUTF8 = convertedString.UTF8String;
|
||||
if (validUTF8)
|
||||
{
|
||||
return std::string(validUTF8);
|
||||
}
|
||||
}
|
||||
|
||||
// invalid encoding
|
||||
return tr_strv_replace_invalid(sv);
|
||||
}
|
|
@ -151,15 +151,15 @@ TEST_F(UtilsTest, strvReplaceInvalid)
|
|||
EXPECT_EQ(out, tr_strv_replace_invalid(out));
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, strvReplaceInvalidFuzz)
|
||||
TEST_F(UtilsTest, strvConvertUtf8Fuzz)
|
||||
{
|
||||
auto buf = std::vector<char>{};
|
||||
for (size_t i = 0; i < 1000; ++i)
|
||||
{
|
||||
buf.resize(tr_rand_int(4096U));
|
||||
tr_rand_buffer(std::data(buf), std::size(buf));
|
||||
auto const out = tr_strv_replace_invalid({ std::data(buf), std::size(buf) });
|
||||
EXPECT_EQ(out, tr_strv_replace_invalid(out));
|
||||
auto const out = tr_strv_convert_utf8({ std::data(buf), std::size(buf) });
|
||||
EXPECT_EQ(out, tr_strv_convert_utf8(out));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue