Make cxfa_fmlexer.cpp resilient to null strings

As currently written, the calculation of m_end will underflow
when passed a {nullptr, 0} pair as input, and m_end becomes
essentially unbounded.

Change-Id: Id3249b201c446555d9aa4fa04e6a3c94a357cd99
Reviewed-on: https://pdfium-review.googlesource.com/30230
Reviewed-by: dsinclair <dsinclair@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/fm2js/cxfa_fmlexer.cpp b/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
index 3559fb7..72fe0f2 100644
--- a/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
@@ -130,7 +130,7 @@
 
 CXFA_FMLexer::CXFA_FMLexer(const WideStringView& wsFormCalc)
     : m_cursor(wsFormCalc.unterminated_c_str()),
-      m_end(m_cursor + wsFormCalc.GetLength() - 1),
+      m_end(m_cursor + wsFormCalc.GetLength()),
       m_lexer_error(false) {}
 
 CXFA_FMLexer::~CXFA_FMLexer() {}
@@ -139,7 +139,7 @@
   if (m_lexer_error)
     return CXFA_FMToken();
 
-  while (m_cursor <= m_end && *m_cursor) {
+  while (m_cursor < m_end && *m_cursor) {
     if (!IsFormCalcCharacter(*m_cursor)) {
       RaiseError();
       return CXFA_FMToken();
@@ -170,7 +170,7 @@
         return AdvanceForNumber();
       case '=':
         ++m_cursor;
-        if (m_cursor > m_end)
+        if (m_cursor >= m_end)
           return CXFA_FMToken(TOKassign);
 
         if (!IsFormCalcCharacter(*m_cursor)) {
@@ -184,7 +184,7 @@
         return CXFA_FMToken(TOKassign);
       case '<':
         ++m_cursor;
-        if (m_cursor > m_end)
+        if (m_cursor >= m_end)
           return CXFA_FMToken(TOKlt);
 
         if (!IsFormCalcCharacter(*m_cursor)) {
@@ -202,7 +202,7 @@
         return CXFA_FMToken(TOKlt);
       case '>':
         ++m_cursor;
-        if (m_cursor > m_end)
+        if (m_cursor >= m_end)
           return CXFA_FMToken(TOKgt);
 
         if (!IsFormCalcCharacter(*m_cursor)) {
@@ -246,7 +246,7 @@
         return CXFA_FMToken(TOKmul);
       case '/': {
         ++m_cursor;
-        if (m_cursor > m_end)
+        if (m_cursor >= m_end)
           return CXFA_FMToken(TOKdiv);
 
         if (!IsFormCalcCharacter(*m_cursor)) {
@@ -261,7 +261,7 @@
       }
       case '.':
         ++m_cursor;
-        if (m_cursor > m_end)
+        if (m_cursor >= m_end)
           return CXFA_FMToken(TOKdot);
 
         if (!IsFormCalcCharacter(*m_cursor)) {
@@ -323,7 +323,7 @@
 
   const wchar_t* start = m_cursor;
   ++m_cursor;
-  while (m_cursor <= m_end && *m_cursor) {
+  while (m_cursor < m_end && *m_cursor) {
     if (!IsFormCalcCharacter(*m_cursor))
       break;
 
@@ -331,7 +331,7 @@
       // Check for escaped "s, i.e. "".
       ++m_cursor;
       // If the end of the input has been reached it was not escaped.
-      if (m_cursor > m_end) {
+      if (m_cursor >= m_end) {
         token.m_string =
             WideStringView(start, static_cast<size_t>(m_cursor - start));
         return token;
@@ -357,7 +357,7 @@
 CXFA_FMToken CXFA_FMLexer::AdvanceForIdentifier() {
   const wchar_t* start = m_cursor;
   ++m_cursor;
-  while (m_cursor <= m_end && *m_cursor) {
+  while (m_cursor < m_end && *m_cursor) {
     if (!IsFormCalcCharacter(*m_cursor)) {
       RaiseError();
       return CXFA_FMToken();
@@ -377,7 +377,7 @@
 
 void CXFA_FMLexer::AdvanceForComment() {
   m_cursor++;
-  while (m_cursor <= m_end && *m_cursor) {
+  while (m_cursor < m_end && *m_cursor) {
     if (!IsFormCalcCharacter(*m_cursor)) {
       RaiseError();
       return;
diff --git a/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
index 00dc494..248b9fe 100644
--- a/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
@@ -10,6 +10,13 @@
 #include "testing/test_support.h"
 #include "third_party/base/ptr_util.h"
 
+TEST(CXFA_FMLexerTest, NullString) {
+  WideStringView null_string;
+  CXFA_FMLexer lexer(null_string);
+  CXFA_FMToken token = lexer.NextToken();
+  EXPECT_EQ(TOKeof, token.m_type);
+}
+
 TEST(CXFA_FMLexerTest, EmptyString) {
   CXFA_FMLexer lexer(L"");
   CXFA_FMToken token = lexer.NextToken();