Fix unsafe buffer usage in (non-XFA) JS bindings.
-- convert to std::array<>, or
-- avoid indexing with range-based loop, or
-- mark two routines UNSAFE.
Change-Id: I5f2ed1819d139c82e69e89c7502ccfa931d1cdf2
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/118074
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Thomas Sepez <tsepez@google.com>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fxjs/cjs_globalarrays.cpp b/fxjs/cjs_globalarrays.cpp
index 26729e1..dfd9bc2 100644
--- a/fxjs/cjs_globalarrays.cpp
+++ b/fxjs/cjs_globalarrays.cpp
@@ -14,14 +14,13 @@
#define GLOBAL_ARRAY(rt, name, ...) \
{ \
- static const wchar_t* const values[] = {__VA_ARGS__}; \
+ static const wchar_t* const kValues[] = {__VA_ARGS__}; \
v8::Local<v8::Array> array = (rt)->NewArray(); \
v8::Local<v8::Context> ctx = (rt)->GetIsolate()->GetCurrentContext(); \
- for (size_t i = 0; i < std::size(values); ++i) { \
- array \
- ->Set(ctx, pdfium::checked_cast<uint32_t>(i), \
- (rt)->NewString(values[i])) \
- .FromJust(); \
+ uint32_t i = 0; \
+ for (const auto* value : kValues) { \
+ array->Set(ctx, i, (rt)->NewString(value)).FromJust(); \
+ ++i; \
} \
(rt)->SetConstArray((name), array); \
(rt)->DefineGlobalConst( \
diff --git a/fxjs/cjs_publicmethods.cpp b/fxjs/cjs_publicmethods.cpp
index aeaf0ad..9d2b683 100644
--- a/fxjs/cjs_publicmethods.cpp
+++ b/fxjs/cjs_publicmethods.cpp
@@ -9,6 +9,7 @@
#include <math.h>
#include <algorithm>
+#include <array>
#include <iomanip>
#include <iterator>
#include <limits>
@@ -23,6 +24,7 @@
#include "core/fpdfdoc/cpdf_formcontrol.h"
#include "core/fpdfdoc/cpdf_interactiveform.h"
#include "core/fxcrt/check.h"
+#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/fx_extension.h"
#include "core/fxcrt/fx_string_wrappers.h"
#include "core/fxcrt/numerics/safe_conversions.h"
@@ -73,13 +75,13 @@
constexpr double kDoubleCorrect = 0.000000000000001;
#endif
-constexpr const char* kDateFormats[] = {
- "m/d", "m/d/yy", "mm/dd/yy", "mm/yy", "d-mmm",
- "d-mmm-yy", "dd-mmm-yy", "yy-mm-dd", "mmm-yy", "mmmm-yy",
- "mmm d, yyyy", "mmmm d, yyyy", "m/d/yy h:MM tt", "m/d/yy HH:MM"};
+constexpr std::array<const char*, 14> kDateFormats = {
+ {"m/d", "m/d/yy", "mm/dd/yy", "mm/yy", "d-mmm", "d-mmm-yy", "dd-mmm-yy",
+ "yy-mm-dd", "mmm-yy", "mmmm-yy", "mmm d, yyyy", "mmmm d, yyyy",
+ "m/d/yy h:MM tt", "m/d/yy HH:MM"}};
-constexpr const char* kTimeFormats[] = {"HH:MM", "h:MM tt", "HH:MM:ss",
- "h:MM:ss tt"};
+constexpr std::array<const char*, 4> kTimeFormats = {
+ {"HH:MM", "h:MM tt", "HH:MM:ss", "h:MM:ss tt"}};
template <typename T>
T StrTrim(const T& str) {
@@ -263,30 +265,36 @@
bool bDot = false;
bool bKXJS = false;
- wchar_t c;
- while ((c = *p) != L'\0') {
- if (IsDigitSeparatorOrDecimalMark(c)) {
- if (bDot)
- return false;
- bDot = true;
- } else if (c == L'-' || c == L'+') {
- if (p != pTrim)
- return false;
- } else if (c == L'e' || c == L'E') {
- if (bKXJS)
- return false;
+ // TODO(tsepez): fix UNSAFE usage.
+ UNSAFE_BUFFERS({
+ wchar_t c;
+ while ((c = *p) != L'\0') {
+ if (IsDigitSeparatorOrDecimalMark(c)) {
+ if (bDot) {
+ return false;
+ }
+ bDot = true;
+ } else if (c == L'-' || c == L'+') {
+ if (p != pTrim) {
+ return false;
+ }
+ } else if (c == L'e' || c == L'E') {
+ if (bKXJS) {
+ return false;
+ }
+ p++;
+ c = *p;
+ if (c != L'+' && c != L'-') {
+ return false;
+ }
+ bKXJS = true;
+ } else if (!FXSYS_IsDecimalDigit(c)) {
+ return false;
+ }
p++;
- c = *p;
- if (c != L'+' && c != L'-')
- return false;
- bKXJS = true;
- } else if (!FXSYS_IsDecimalDigit(c)) {
- return false;
}
- p++;
- }
-
+ });
return true;
}
@@ -322,22 +330,27 @@
int nIndex = 0;
v8::Local<v8::Array> StrArray = pRuntime->NewArray();
- while (*p) {
- const char* pTemp = strchr(p, ',');
- if (!pTemp) {
+
+ // TODO(tsepez): fix UNSAFE usage.
+ UNSAFE_BUFFERS({
+ while (*p) {
+ const char* pTemp = strchr(p, ',');
+ if (!pTemp) {
+ pRuntime->PutArrayElement(
+ StrArray, nIndex,
+ pRuntime->NewString(StrTrim(ByteString(p)).AsStringView()));
+ break;
+ }
+
pRuntime->PutArrayElement(
StrArray, nIndex,
- pRuntime->NewString(StrTrim(ByteString(p)).AsStringView()));
- break;
+ pRuntime->NewString(
+ StrTrim(ByteString(p, pTemp - p)).AsStringView()));
+
+ nIndex++;
+ p = ++pTemp;
}
-
- pRuntime->PutArrayElement(
- StrArray, nIndex,
- pRuntime->NewString(StrTrim(ByteString(p, pTemp - p)).AsStringView()));
-
- nIndex++;
- p = ++pTemp;
- }
+ });
return StrArray;
}
@@ -352,7 +365,7 @@
int nMin = FX_GetMinFromTime(dt);
int nSec = FX_GetSecFromTime(dt);
- int number[3];
+ std::array<int, 3> number;
size_t nSkip = 0;
size_t nLen = value.GetLength();
diff --git a/fxjs/cjs_publicmethods_unittest.cpp b/fxjs/cjs_publicmethods_unittest.cpp
index a5b9314..4ebf1cc 100644
--- a/fxjs/cjs_publicmethods_unittest.cpp
+++ b/fxjs/cjs_publicmethods_unittest.cpp
@@ -44,9 +44,7 @@
{L"0123", true},
{L"9876123", true},
};
- for (size_t i = 0; i < std::size(test_data); ++i) {
- EXPECT_EQ(test_data[i].expected,
- CJS_PublicMethods::IsNumber(test_data[i].input))
- << "for case " << i;
+ for (const auto& element : test_data) {
+ EXPECT_EQ(element.expected, CJS_PublicMethods::IsNumber(element.input));
}
}
diff --git a/fxjs/cjs_util.cpp b/fxjs/cjs_util.cpp
index a404ee4..9362252 100644
--- a/fxjs/cjs_util.cpp
+++ b/fxjs/cjs_util.cpp
@@ -47,7 +47,7 @@
int value;
};
-const TbConvert TbConvertTable[] = {
+const TbConvert kTbConvertTable[] = {
{L"mmmm", L"%B"}, {L"mmm", L"%b"}, {L"mm", L"%m"}, {L"dddd", L"%A"},
{L"ddd", L"%a"}, {L"dd", L"%d"}, {L"yyyy", L"%Y"}, {L"yy", L"%y"},
{L"HH", L"%H"}, {L"hh", L"%I"}, {L"MM", L"%M"}, {L"ss", L"%S"},
@@ -217,40 +217,40 @@
cFormat.erase(std::remove(cFormat.begin(), cFormat.end(), '%'),
cFormat.end());
- for (size_t i = 0; i < std::size(TbConvertTable); ++i) {
+ for (const auto& conversion : kTbConvertTable) {
size_t nFound = 0;
while (true) {
- nFound = cFormat.find(TbConvertTable[i].lpszJSMark, nFound);
- if (nFound == std::wstring::npos)
+ nFound = cFormat.find(conversion.lpszJSMark, nFound);
+ if (nFound == std::wstring::npos) {
break;
-
- cFormat.replace(nFound, wcslen(TbConvertTable[i].lpszJSMark),
- TbConvertTable[i].lpszCppMark);
+ }
+ cFormat.replace(nFound, wcslen(conversion.lpszJSMark),
+ conversion.lpszCppMark);
}
}
if (year < 0)
return CJS_Result::Failure(JSMessage::kValueError);
- const TbConvertAdditional cTableAd[] = {
+ const TbConvertAdditional table_additional[] = {
{L'm', month}, {L'd', day},
{L'H', hour}, {L'h', hour > 12 ? hour - 12 : hour},
{L'M', min}, {L's', sec},
};
- for (size_t i = 0; i < std::size(cTableAd); ++i) {
+ for (const auto& conversion : table_additional) {
size_t nFound = 0;
while (true) {
- nFound = cFormat.find(cTableAd[i].js_mark, nFound);
- if (nFound == std::wstring::npos)
+ nFound = cFormat.find(conversion.js_mark, nFound);
+ if (nFound == std::wstring::npos) {
break;
-
+ }
if (nFound != 0 && cFormat[nFound - 1] == L'%') {
++nFound;
continue;
}
cFormat.replace(nFound, 1,
- WideString::FormatInteger(cTableAd[i].value).c_str());
+ WideString::FormatInteger(conversion.value).c_str());
}
}
diff --git a/fxjs/cjs_util_unittest.cpp b/fxjs/cjs_util_unittest.cpp
index b925268..34385d8 100644
--- a/fxjs/cjs_util_unittest.cpp
+++ b/fxjs/cjs_util_unittest.cpp
@@ -106,9 +106,9 @@
{L"%10s", CJS_Util::DataType::kString},
};
- for (size_t i = 0; i < std::size(cases); i++) {
- WideString input(cases[i].input_string);
- EXPECT_EQ(cases[i].expected, CJS_Util::ParseDataType(&input))
- << cases[i].input_string;
+ for (const auto& item : cases) {
+ WideString input(item.input_string);
+ EXPECT_EQ(item.expected, CJS_Util::ParseDataType(&input))
+ << item.input_string;
}
}
diff --git a/fxjs/fx_date_helpers.cpp b/fxjs/fx_date_helpers.cpp
index 9601e96..96a3d35 100644
--- a/fxjs/fx_date_helpers.cpp
+++ b/fxjs/fx_date_helpers.cpp
@@ -10,6 +10,7 @@
#include <time.h>
#include <wctype.h>
+#include <array>
#include <iterator>
#include "build/build_config.h"
@@ -20,10 +21,11 @@
namespace fxjs {
namespace {
-constexpr uint16_t daysMonth[12] = {0, 31, 59, 90, 120, 151,
- 181, 212, 243, 273, 304, 334};
-constexpr uint16_t leapDaysMonth[12] = {0, 31, 60, 91, 121, 152,
- 182, 213, 244, 274, 305, 335};
+constexpr std::array<uint16_t, 12> kDaysMonth = {
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}};
+
+constexpr std::array<uint16_t, 12> kLeapDaysMonth = {
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}};
double Mod(double x, double y) {
double r = fmod(x, y);
@@ -74,8 +76,8 @@
}
double TimeFromYearMonth(int y, int m) {
- const uint16_t* pMonth = IsLeapYear(y) ? leapDaysMonth : daysMonth;
- return TimeFromYear(y) + ((double)pMonth[m]) * 86400000;
+ const uint16_t month = IsLeapYear(y) ? kLeapDaysMonth[m] : kDaysMonth[m];
+ return TimeFromYear(y) + static_cast<double>(month) * 86400000;
}
int Day(double t) {
@@ -113,8 +115,8 @@
--day;
// Check for February onwards.
- static constexpr int kCumulativeDaysInMonths[] = {
- 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
+ static constexpr std::array<int, 11> kCumulativeDaysInMonths = {
+ {59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}};
for (size_t i = 0; i < std::size(kCumulativeDaysInMonths); ++i) {
if (day < kCumulativeDaysInMonths[i])
return static_cast<int>(i) + 1;
@@ -168,12 +170,13 @@
} // namespace
-const char* const kMonths[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+const std::array<const char*, 12> kMonths = {{"Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct",
+ "Nov", "Dec"}};
-const char* const kFullMonths[12] = {
- "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"};
+const std::array<const char*, 12> kFullMonths = {
+ {"January", "February", "March", "April", "May", "June", "July", "August",
+ "September", "October", "November", "December"}};
static constexpr size_t KMonthAbbreviationLength = 3; // Anything in |kMonths|.
static constexpr size_t kLongestFullMonthLength = 9; // September
diff --git a/fxjs/fx_date_helpers.h b/fxjs/fx_date_helpers.h
index ca730e5..a3fc55d 100644
--- a/fxjs/fx_date_helpers.h
+++ b/fxjs/fx_date_helpers.h
@@ -9,14 +9,16 @@
#include <stddef.h>
+#include <array>
+
#include "core/fxcrt/widestring.h"
namespace fxjs {
enum class ConversionStatus { kSuccess = 0, kBadFormat, kBadDate };
-extern const char* const kMonths[12];
-extern const char* const kFullMonths[12];
+extern const std::array<const char*, 12> kMonths;
+extern const std::array<const char*, 12> kFullMonths;
double FX_GetDateTime();
int FX_GetYearFromTime(double dt);