Limit number of payment periods for FormCalc financial functions.
Extract the code used to validate the number of payment periods in
FormCalc Pmt() into a helper function. Then use it in other applicable
FormCalc functions.
Bug: chromium:1296840
Change-Id: I5350771b685c83d9b5dece8b622f996cd0dfafab
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/90612
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fxjs/xfa/cfxjse_formcalc_context.cpp b/fxjs/xfa/cfxjse_formcalc_context.cpp
index b796b36..3b4cf00 100644
--- a/fxjs/xfa/cfxjse_formcalc_context.cpp
+++ b/fxjs/xfa/cfxjse_formcalc_context.cpp
@@ -1652,6 +1652,17 @@
return resultValues;
}
+// Returns 0 if the provided `arg` is an invalid payment period count.
+int GetValidatedPaymentPeriods(v8::Isolate* isolate, v8::Local<v8::Value> arg) {
+ double periods = ValueToDouble(isolate, arg);
+ if (periods < 1 ||
+ periods > static_cast<double>(std::numeric_limits<int32_t>::max())) {
+ return 0;
+ }
+
+ return static_cast<int>(periods);
+}
+
} // namespace
const FXJSE_CLASS_DESCRIPTOR kFormCalcFM2JSDescriptor = {
@@ -2688,8 +2699,8 @@
double nPrincipal = ValueToDouble(info.GetIsolate(), argOne);
double nPayment = ValueToDouble(info.GetIsolate(), argTwo);
- double nPeriods = ValueToDouble(info.GetIsolate(), argThree);
- if (nPrincipal <= 0 || nPayment <= 0 || nPeriods <= 0) {
+ int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
+ if (nPrincipal <= 0 || nPayment <= 0 || nPeriods == 0) {
pContext->ThrowArgumentMismatchException();
return;
}
@@ -2774,8 +2785,8 @@
double nAmount = ValueToDouble(info.GetIsolate(), argOne);
double nRate = ValueToDouble(info.GetIsolate(), argTwo);
- double nPeriod = ValueToDouble(info.GetIsolate(), argThree);
- if ((nRate < 0) || (nPeriod <= 0) || (nAmount <= 0)) {
+ int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
+ if (nAmount <= 0 || nRate < 0 || nPeriods == 0) {
pContext->ThrowArgumentMismatchException();
return;
}
@@ -2783,12 +2794,12 @@
double dResult = 0;
if (nRate) {
double nTemp = 1;
- for (int i = 0; i < nPeriod; ++i) {
+ for (int i = 0; i < nPeriods; ++i) {
nTemp *= 1 + nRate;
}
dResult = nAmount * (nTemp - 1) / nRate;
} else {
- dResult = nAmount * nPeriod;
+ dResult = nAmount * nPeriods;
}
info.GetReturnValue().Set(dResult);
@@ -2919,14 +2930,13 @@
double nPrincipal = ValueToDouble(info.GetIsolate(), argOne);
double nRate = ValueToDouble(info.GetIsolate(), argTwo);
- double nPeriods = ValueToDouble(info.GetIsolate(), argThree);
- if (nPrincipal <= 0 || nRate <= 0 || nPeriods < 1 ||
- nPeriods > static_cast<double>(std::numeric_limits<int32_t>::max())) {
+ int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
+ if (nPrincipal <= 0 || nRate <= 0 || nPeriods == 0) {
pContext->ThrowArgumentMismatchException();
return;
}
- double nSum = pow(nRate + 1, static_cast<int>(nPeriods));
+ double nSum = pow(nRate + 1, nPeriods);
info.GetReturnValue().Set((nPrincipal * nRate * nSum) / (nSum - 1));
}
@@ -3013,14 +3023,14 @@
double nAmount = ValueToDouble(info.GetIsolate(), argOne);
double nRate = ValueToDouble(info.GetIsolate(), argTwo);
- double nPeriod = ValueToDouble(info.GetIsolate(), argThree);
- if ((nAmount <= 0) || (nRate < 0) || (nPeriod <= 0)) {
+ int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
+ if (nAmount <= 0 || nRate < 0 || nPeriods == 0) {
pContext->ThrowArgumentMismatchException();
return;
}
double nTemp = 1;
- for (int32_t i = 0; i < nPeriod; ++i)
+ for (int32_t i = 0; i < nPeriods; ++i)
nTemp *= 1 + nRate;
nTemp = 1 / nTemp;
@@ -3049,14 +3059,13 @@
float nFuture = ValueToFloat(info.GetIsolate(), argOne);
float nPresent = ValueToFloat(info.GetIsolate(), argTwo);
- float nTotalNumber = ValueToFloat(info.GetIsolate(), argThree);
- if ((nFuture <= 0) || (nPresent < 0) || (nTotalNumber <= 0)) {
+ int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
+ if (nFuture <= 0 || nPresent < 0 || nPeriods == 0) {
pContext->ThrowArgumentMismatchException();
return;
}
- info.GetReturnValue().Set(powf(nFuture / nPresent, 1.0f / nTotalNumber) -
- 1.0f);
+ info.GetReturnValue().Set(powf(nFuture / nPresent, 1.0f / nPeriods) - 1.0f);
}
// static
diff --git a/fxjs/xfa/cfxjse_formcalc_context_embeddertest.cpp b/fxjs/xfa/cfxjse_formcalc_context_embeddertest.cpp
index bf9ba04..6d4b504 100644
--- a/fxjs/xfa/cfxjse_formcalc_context_embeddertest.cpp
+++ b/fxjs/xfa/cfxjse_formcalc_context_embeddertest.cpp
@@ -460,6 +460,8 @@
ExecuteExpectFloatNear("Apr(35000, 269.50, 360)", 0.08515404566f);
ExecuteExpectFloatNear("Apr(210000 * 0.75, 850 + 110, 25 * 26)",
0.07161332404f);
+
+ ExecuteExpectError("Apr(2, 2, 2147483648)");
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, CTerm) {
@@ -479,6 +481,8 @@
ExecuteExpectFloat("FV(400, 0.10 / 12, 30 * 12)", 904195.16991842445f);
ExecuteExpectFloat("FV(1000, 0.075 / 4, 10 * 4)", 58791.96145535981f);
+
+ ExecuteExpectError("FV(2, 2, 2147483648)");
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, IPmt) {
@@ -530,6 +534,9 @@
// TODO(thestig): Investigate this case.
ExecuteExpectFloat("PV(1000, 0.075 / 4, 10 * 4)", 58791.96145535981f);
#endif
+
+ // https://crbug.com/1296840
+ ExecuteExpectError("PV(2, 2, 2147483648)");
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, Rate) {
@@ -537,6 +544,8 @@
ExecuteExpectFloatNear("Rate(12000, 8000, 5)", 0.0844717712f);
ExecuteExpectFloatNear("Rate(10000, 0.25 * 5000, 4 * 12)", 0.04427378243f);
+
+ ExecuteExpectError("Rate(2, 2, 2147483648)");
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, Term) {