Skip to content

Commit 80ce6b9

Browse files
authored
Merge pull request #2270 from jamescowens/remove_stod
refactor: Replace local dependent string functions with non-locale versions in strencodings.h/cpp
2 parents 8eb9623 + b65ea08 commit 80ce6b9

29 files changed

+355
-118
lines changed

src/bignum.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,12 +369,11 @@ class CBigNum : public CBigNumBase
369369
psz++;
370370

371371
// hex string to bignum
372-
static const signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
373372
*this = 0;
374-
while (isxdigit(*psz))
373+
while (HexDigit(*psz) >= 0)
375374
{
376375
*this <<= 4;
377-
int n = phexdigit[(unsigned char)*psz++];
376+
int n = HexDigit((unsigned char)*psz++);
378377
*this += n;
379378
}
380379
if (fNegative)

src/gridcoin/accrual/snapshot.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -552,11 +552,14 @@ class AccrualSnapshotFile
552552
//!
553553
static uint64_t ParseHeight(const fs::path& snapshot_path)
554554
{
555-
try {
556-
return std::stoull(snapshot_path.stem().string());
557-
} catch (...) {
558-
return 0;
555+
uint64_t height = 0;
556+
557+
if (!ParseUInt64(snapshot_path.stem().string(), &height)) {
558+
LogPrint(BCLog::LogFlags::SB, "WARN: %s: Filename in snapshot path does not contain a valid height number.",
559+
__func__);
559560
}
561+
562+
return height;
560563
}
561564

562565
//!

src/gridcoin/researcher.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ bool UpdateRWSettingsForMode(const ResearcherMode mode, const std::string& email
8787
//!
8888
std::string LowerUnderscore(std::string data)
8989
{
90-
boost::to_lower(data);
90+
data = ToLower(data);
9191
boost::replace_all(data, "_", " ");
9292

9393
return data;
@@ -304,7 +304,7 @@ std::set<std::string> GetTeamWhitelist()
304304
continue;
305305
}
306306

307-
boost::to_lower(team_name);
307+
team_name = ToLower(team_name);
308308

309309
teams.emplace(std::move(team_name));
310310
}
@@ -794,18 +794,23 @@ MiningProject::MiningProject(std::string name,
794794
, m_rac(std::move(rac))
795795
, m_error(Error::NONE)
796796
{
797-
boost::to_lower(m_team);
797+
m_team = ToLower(m_team);
798798
}
799799

800800
MiningProject MiningProject::Parse(const std::string& xml)
801801
{
802+
double rac = 0.0;
803+
804+
if (!ParseDouble(ExtractXML(xml, "<user_expavg_credit>", "</user_expavg_credit>"), &rac)) {
805+
LogPrintf("WARN: %s: Unable to parse user RAC from legacy XML data.", __func__);
806+
}
807+
802808
MiningProject project(
803809
ExtractXML(xml, "<project_name>", "</project_name>"),
804810
Cpid::Parse(ExtractXML(xml, "<external_cpid>", "</external_cpid>")),
805811
ExtractXML(xml, "<team_name>", "</team_name>"),
806812
ExtractXML(xml, "<master_url>", "</master_url>"),
807-
std::strtold(ExtractXML(xml, "<user_expavg_credit>",
808-
"</user_expavg_credit>").c_str(), nullptr));
813+
rac);
809814

810815
if (IsPoolCpid(project.m_cpid) && !gArgs.GetBoolArg("-pooloperator", false)) {
811816
project.m_error = MiningProject::Error::POOL;
@@ -1101,7 +1106,7 @@ std::string Researcher::Email()
11011106
if (gArgs.GetBoolArg("-investor", false)) return email;
11021107

11031108
email = gArgs.GetArg("-email", "");
1104-
boost::to_lower(email);
1109+
email = ToLower(email);
11051110

11061111
return email;
11071112
}
@@ -1348,7 +1353,7 @@ GRC::BeaconError Researcher::BeaconError() const
13481353

13491354
bool Researcher::ChangeMode(const ResearcherMode mode, std::string email)
13501355
{
1351-
boost::to_lower(email);
1356+
email = ToLower(email);
13521357

13531358
if (mode == ResearcherMode::INVESTOR && ConfiguredForInvestorMode()) {
13541359
return true;

src/gridcoin/scraper/http.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,10 @@ namespace
171171
}
172172

173173
constexpr char expected[] = "etag";
174-
constexpr int32_t to_upper = 32;
174+
constexpr int32_t shift_to_upper = 32;
175175

176176
for (size_t i = 0; i < 4; ++i) {
177-
if (header[i] != expected[i] && header[i] != expected[i] - to_upper) {
177+
if (header[i] != expected[i] && header[i] != expected[i] - shift_to_upper) {
178178
return std::string();
179179
}
180180
}

src/gridcoin/scraper/scraper.cpp

Lines changed: 109 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -878,24 +878,59 @@ void ApplyCache(const std::string& key, T& result)
878878
try
879879
{
880880
if (std::is_same<T, double>::value)
881-
result = stod(entry.value);
881+
{
882+
double out = 0.0;
883+
884+
if (!ParseDouble(entry.value, &out))
885+
{
886+
throw std::invalid_argument("Argument is not parseable as a double.");
887+
}
888+
889+
// Have to do the copy here and below, because otherwise the compiler complains about putting &result directly
890+
// above, since this is a template.
891+
result = out;
892+
}
882893
else if (std::is_same<T, int64_t>::value)
883-
result = atoi64(entry.value);
894+
{
895+
int64_t out = 0;
896+
897+
if (!ParseInt64(entry.value, &out))
898+
{
899+
throw std::invalid_argument("Argument is not parseable as an int64_t.");
900+
}
901+
902+
result = out;
903+
}
884904
else if (std::is_same<T, unsigned int>::value)
885-
// Throw away (zero out) negative integer
886-
// This approach limits the range to the non-negative signed int, but that is good enough.
887-
result = (unsigned int)std::max(0, stoi(entry.value));
905+
{
906+
unsigned int out = 0;
907+
908+
if (!ParseUInt(entry.value, &out))
909+
{
910+
throw std::invalid_argument("Argument is not parseable as an unsigned int.");
911+
}
912+
913+
result = out;
914+
}
888915
else if (std::is_same<T, bool>::value)
889916
{
890917
if (entry.value == "false" || entry.value == "0")
918+
{
891919
result = boost::lexical_cast<T>(false);
920+
}
892921
else if (entry.value == "true" || entry.value == "1")
922+
{
893923
result = boost::lexical_cast<T>(true);
924+
}
894925
else
926+
{
895927
throw std::invalid_argument("Argument not true or false");
928+
}
896929
}
897930
else
931+
{
898932
result = boost::lexical_cast<T>(entry.value);
933+
}
899934
}
900935
catch (const std::exception&)
901936
{
@@ -1879,20 +1914,18 @@ bool ProcessProjectTeamFile(const std::string& project, const fs::path& file, co
18791914

18801915
int64_t nTeamID = 0;
18811916

1882-
try
1883-
{
1884-
nTeamID = atoi64(sTeamID);
1885-
}
1886-
catch (const std::exception&)
1917+
if (!ParseInt64(sTeamID, &nTeamID))
18871918
{
1888-
_log(logattribute::ERR, "ProccessProjectTeamFile", tfm::format("Ignoring bad team id for team %s.", sTeamName));
1919+
_log(logattribute::ERR, __func__, tfm::format("Ignoring bad team id for team %s.", sTeamName));
18891920
continue;
18901921
}
18911922

18921923
mTeamIdsForProject[sTeamName] = nTeamID;
18931924
}
18941925
else
1926+
{
18951927
builder.append(line);
1928+
}
18961929
}
18971930

18981931
if (mTeamIdsForProject.empty())
@@ -2284,13 +2317,9 @@ bool ProcessProjectRacFileByCPID(const std::string& project, const fs::path& fil
22842317
const std::string& sTeamID = ExtractXML(data, "<teamid>", "</teamid>");
22852318
int64_t nTeamID = 0;
22862319

2287-
try
2320+
if (!ParseInt64(sTeamID, &nTeamID))
22882321
{
2289-
nTeamID = atoi64(sTeamID);
2290-
}
2291-
catch (const std::exception&)
2292-
{
2293-
_log(logattribute::ERR, "ProcessProjectRacFileByCPID", "Bad team id in user stats file data.");
2322+
_log(logattribute::ERR, __func__, "Bad team id in user stats file data.");
22942323
continue;
22952324
}
22962325

@@ -2550,13 +2579,9 @@ bool LoadTeamIDList(const fs::path& file)
25502579
sProject = iter;
25512580
else
25522581
{
2553-
try
2554-
{
2555-
nTeamID = atoi64(iter);
2556-
}
2557-
catch (std::exception&)
2582+
if (!ParseInt64(iter, &nTeamID))
25582583
{
2559-
_log(logattribute::ERR, "LoadTeamIDList", "Ignoring invalid team id found in team id file.");
2584+
_log(logattribute::ERR, __func__, "Ignoring invalid team id found in team id file.");
25602585
continue;
25612586
}
25622587

@@ -2898,7 +2923,16 @@ bool LoadScraperFileManifest(const fs::path& file)
28982923
nhash.SetHex(vline[0].c_str());
28992924
LoadEntry.hash = nhash;
29002925

2901-
LoadEntry.current = std::stoi(vline[1]);
2926+
// We will use the ParseUInt from strencodings to avoid the locale specific stoi.
2927+
unsigned int parsed_current = 0;
2928+
2929+
if (!ParseUInt(vline[1], &parsed_current))
2930+
{
2931+
_log(logattribute::ERR, __func__, "The \"current\" field not parsed correctly for a manifest entry. Skipping.");
2932+
continue;
2933+
}
2934+
2935+
LoadEntry.current = parsed_current;
29022936

29032937
std::istringstream sstimestamp(vline[2]);
29042938
sstimestamp >> ntimestamp;
@@ -2913,7 +2947,17 @@ bool LoadScraperFileManifest(const fs::path& file)
29132947
{
29142948
// Intended for explorer mode, where files not to be included in CScraperManifest
29152949
// are to be maintained, such as team and host files.
2916-
LoadEntry.excludefromcsmanifest = std::stoi(vline[5]);
2950+
unsigned int parsed_exclude = 0;
2951+
2952+
if (!ParseUInt(vline[5], &parsed_exclude))
2953+
{
2954+
// This shouldn't happen given the conditional above, but to be thorough...
2955+
_log(logattribute::ERR, __func__, "The \"excludefromcsmanifest\" field not parsed correctly for a manifest "
2956+
"entry. Skipping.");
2957+
continue;
2958+
}
2959+
2960+
LoadEntry.excludefromcsmanifest = parsed_exclude;
29172961
}
29182962
else
29192963
{
@@ -3158,10 +3202,46 @@ bool ProcessProjectStatsFromStreamByCPID(const std::string& project, boostio::fi
31583202
const std::string& sRAC = fields[2];
31593203
const std::string& cpid = fields[3];
31603204

3161-
// Replace blank strings with zeros.
3162-
statsentry.statsvalue.dTC = (sTC.empty()) ? 0.0 : std::stod(sTC);
3163-
statsentry.statsvalue.dRAT = (sRAT.empty()) ? 0.0 : std::stod(sRAT);
3164-
statsentry.statsvalue.dRAC = (sRAC.empty()) ? 0.0 : std::stod(sRAC);
3205+
// Replace blank strings with zeros. Continue to next record with a logged error if there is a parsing failure.
3206+
if (sTC.empty())
3207+
{
3208+
statsentry.statsvalue.dTC = 0.0;
3209+
}
3210+
else
3211+
{
3212+
if (!ParseDouble(sTC, &statsentry.statsvalue.dTC))
3213+
{
3214+
_log(logattribute::ERR, __func__, "Cannot parse sTC " + sTC + " for cpid " + cpid);
3215+
continue;
3216+
}
3217+
}
3218+
3219+
if (sRAT.empty())
3220+
{
3221+
statsentry.statsvalue.dRAT = 0.0;
3222+
}
3223+
else
3224+
{
3225+
if (!ParseDouble(sRAT, &statsentry.statsvalue.dRAT))
3226+
{
3227+
_log(logattribute::ERR, __func__, "Cannot parse sRAT " + sRAT + " for cpid " + cpid);
3228+
continue;
3229+
}
3230+
}
3231+
3232+
if (sRAC.empty())
3233+
{
3234+
statsentry.statsvalue.dRAC = 0.0;
3235+
}
3236+
else
3237+
{
3238+
if (!ParseDouble(sRAC, &statsentry.statsvalue.dRAC))
3239+
{
3240+
_log(logattribute::ERR, __func__, "Cannot parse sRAC " + sRAC + " for cpid " + cpid);
3241+
continue;
3242+
}
3243+
}
3244+
31653245
// At the individual (byCPIDbyProject) level the AvgRAC is the same as the RAC.
31663246
statsentry.statsvalue.dAvgRAC = statsentry.statsvalue.dRAC;
31673247
// Mag is dealt with on the second pass... so is left at 0.0 on the first pass.

src/gridcoin/staking/kernel.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ int64_t GetRSAWeightByBlock(const std::string& bb)
140140
constexpr size_t rsa_weight_offset = 13;
141141
constexpr size_t magnitude_offset = 15;
142142

143-
int64_t rsa_weight = 0;
143+
int64_t rsa_weight_sum = 0;
144144

145145
// General-purpose deserialization of claim contexts in the hashBoinc field
146146
// no longer parses out the RSA weight field, so we handle the special case
@@ -154,18 +154,24 @@ int64_t GetRSAWeightByBlock(const std::string& bb)
154154
if (n == cpid_offset && end - offset != 32) {
155155
return 0;
156156
} else if (n == rsa_weight_offset || n == magnitude_offset) {
157-
rsa_weight += std::atoi(bb.substr(offset, end - offset).c_str());
157+
int64_t rsa_weight = 0;
158+
159+
if (!ParseInt64(bb.substr(offset, end - offset), &rsa_weight)) {
160+
error("%s: Unable to parse rsa weight from hashBoinc.", __func__);
161+
}
162+
163+
rsa_weight_sum += rsa_weight;
158164
}
159165

160166
offset = end + 3;
161167
end = bb.find("<|>", offset);
162168
}
163169

164-
if (rsa_weight < 0) {
170+
if (rsa_weight_sum < 0) {
165171
return 0;
166172
}
167173

168-
return rsa_weight;
174+
return rsa_weight_sum;
169175
}
170176
} // anonymous namespace
171177

src/gridcoin/staking/reward.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ CAmount GRC::GetConstantBlockReward(const CBlockIndex* index)
4646
//TODO: refactor the expire checking to subroutine
4747
//Note: time constant is same as GetBeaconPublicKey
4848
if ((index->nTime - oCBReward.timestamp) <= (60 * 24 * 30 * 6 * 60)) {
49-
reward = atoi64(oCBReward.value);
49+
// This is a little slippery, because if we ever change CAmount from a int64_t, this will
50+
// break. It is unlikely to ever change, however, and avoids an extra copy/implicit cast.
51+
if (!ParseInt64(oCBReward.value, &reward)) {
52+
error("%s: Cannot parse constant block reward from protocol entry: %s",
53+
__func__, oCBReward.value);
54+
}
5055
}
5156

5257
reward = std::clamp(reward, MIN_CBR, MAX_CBR);

0 commit comments

Comments
 (0)