Enforce unsafe buffers on 2-arg StringViewTemplate constructor.

Prepare for a future compiler which will enforce this by making the
constructor private and forcing callers through a static method that
is enforced. Once the compiler is updated, it is a simple matter to
change, for example, ByteStringView::Create(..., ...) back to
ByteStringView(..., ...).

Change-Id: I6aceebbb7865514f41f801d57225f0ea171c298a
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/119677
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/font/cpdf_cidfont.cpp b/core/fpdfapi/font/cpdf_cidfont.cpp
index 9bcc84e..8e11285 100644
--- a/core/fpdfapi/font/cpdf_cidfont.cpp
+++ b/core/fpdfapi/font/cpdf_cidfont.cpp
@@ -321,7 +321,8 @@
   }
   size_t ret = FX_MultiByteToWideChar(
       UNSAFE_TODO(kCharsetCodePages[static_cast<size_t>(m_pCMap->GetCoding())]),
-      ByteStringView(reinterpret_cast<const char*>(&charcode), charsize),
+      UNSAFE_TODO(ByteStringView::Create(
+          reinterpret_cast<const char*>(&charcode), charsize)),
       pdfium::span_from_ref(unicode));
   return ret == 1 ? unicode : 0;
 #else
@@ -368,7 +369,7 @@
   uint8_t buffer[32];
   size_t ret = FX_WideCharToMultiByte(
       UNSAFE_TODO(kCharsetCodePages[static_cast<size_t>(m_pCMap->GetCoding())]),
-      WideStringView(&unicode, 1),
+      WideStringView(unicode),
       pdfium::as_writable_chars(pdfium::make_span(buffer).first(4u)));
   if (ret == 1)
     return buffer[0];
diff --git a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
index 2ec773e..f416aac 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
@@ -33,7 +33,8 @@
 // Converts a string literal into a `uint8_t` span.
 template <size_t N>
 pdfium::span<const uint8_t> ToSpan(const char (&array)[N]) {
-  return pdfium::as_bytes(ByteStringView(array, N - 1).span());
+  return pdfium::as_bytes(
+      UNSAFE_BUFFERS(ByteStringView::Create(array, N - 1).span()));
 }
 
 // Converts a string literal into a `ByteString`.
diff --git a/core/fxcrt/bytestring_unittest.cpp b/core/fxcrt/bytestring_unittest.cpp
index 95ccfe1..c2b84e6 100644
--- a/core/fxcrt/bytestring_unittest.cpp
+++ b/core/fxcrt/bytestring_unittest.cpp
@@ -1221,12 +1221,16 @@
 TEST(ByteStringView, NotNull) {
   ByteStringView string3("abc");
   ByteStringView string6("abcdef");
-  ByteStringView alternate_string3("abcdef", 3);
+  // SAFETY: known fixed-length string.
+  auto alternate_string3 = UNSAFE_BUFFERS(ByteStringView::Create("abcdef", 3));
   const char abcd[] = "abcd";
   ByteStringView span_string4(
       pdfium::as_bytes(pdfium::make_span(abcd).first(4u)));
-  ByteStringView embedded_nul_string7("abc\0def", 7);
-  ByteStringView illegal_string7("abcdef", 7);
+  // SAFETY: known fixed-length string.
+  auto embedded_nul_string7 =
+      UNSAFE_BUFFERS(ByteStringView::Create("abc\0def", 7));
+  // SAFETY: known fixed-length string.
+  auto illegal_string7 = UNSAFE_BUFFERS(ByteStringView::Create("abcdef", 7));
 
   EXPECT_EQ(3u, string3.GetLength());
   EXPECT_EQ(6u, string6.GetLength());
@@ -1961,8 +1965,9 @@
   // a C++-style string.
   {
     std::ostringstream stream;
-    char stringWithNulls[]{'x', 'y', '\0', 'z'};
-    ByteStringView str(stringWithNulls, 4);
+    char stringWithNulls[] = {'x', 'y', '\0', 'z'};
+    // SAFETY: known array above.
+    auto str = UNSAFE_BUFFERS(ByteStringView::Create(stringWithNulls, 4));
     EXPECT_EQ(4u, str.GetLength());
     stream << str;
     EXPECT_EQ(4u, stream.tellp());
diff --git a/core/fxcrt/string_view_template.h b/core/fxcrt/string_view_template.h
index 76df947..6c1bf44 100644
--- a/core/fxcrt/string_view_template.h
+++ b/core/fxcrt/string_view_template.h
@@ -42,6 +42,22 @@
   using const_iterator = const CharType*;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
+  UNSAFE_BUFFER_USAGE static constexpr StringViewTemplate Create(
+      const CharType* ptr,
+      size_t size) {
+    // SAFETY: required from caller, enforced via UNSAFE_BUFFER_USAGE.
+    return UNSAFE_BUFFERS(StringViewTemplate(ptr, size));
+  }
+
+  template <typename E = typename std::enable_if_t<
+                !std::is_same_v<UnsignedType, CharType>>>
+  UNSAFE_BUFFER_USAGE static constexpr StringViewTemplate Create(
+      const UnsignedType* ptr,
+      size_t size) {
+    // SAFETY: required from caller, enforced via UNSAFE_BUFFER_USAGE.
+    return UNSAFE_BUFFERS(StringViewTemplate(ptr, size));
+  }
+
   constexpr StringViewTemplate() noexcept = default;
   constexpr StringViewTemplate(const StringViewTemplate& src) noexcept =
       default;
@@ -54,20 +70,6 @@
             reinterpret_cast<const UnsignedType*>(ptr),
             ptr ? std::char_traits<CharType>::length(ptr) : 0))) {}
 
-  UNSAFE_BUFFER_USAGE
-  constexpr StringViewTemplate(const CharType* ptr, size_t size) noexcept
-      // SAFETY: propagated to caller via UNSAFE_BUFFER_USAGE.
-      : m_Span(UNSAFE_BUFFERS(
-            pdfium::make_span(reinterpret_cast<const UnsignedType*>(ptr),
-                              size))) {}
-
-  template <typename E = typename std::enable_if<
-                !std::is_same<UnsignedType, CharType>::value>::type>
-  UNSAFE_BUFFER_USAGE constexpr StringViewTemplate(const UnsignedType* ptr,
-                                                   size_t size) noexcept
-      // SAFETY: propagated to caller via UNSAFE_BUFFER_USAGE.
-      : m_Span(UNSAFE_BUFFERS(pdfium::make_span(ptr, size))) {}
-
   explicit constexpr StringViewTemplate(
       const pdfium::span<const CharType>& other) noexcept {
     if (!other.empty()) {
@@ -291,6 +293,20 @@
   }
 
  protected:
+  UNSAFE_BUFFER_USAGE
+  constexpr StringViewTemplate(const CharType* ptr, size_t size) noexcept
+      // SAFETY: propagated to caller via UNSAFE_BUFFER_USAGE.
+      : m_Span(UNSAFE_BUFFERS(
+            pdfium::make_span(reinterpret_cast<const UnsignedType*>(ptr),
+                              size))) {}
+
+  template <typename E = typename std::enable_if<
+                !std::is_same<UnsignedType, CharType>::value>::type>
+  UNSAFE_BUFFER_USAGE constexpr StringViewTemplate(const UnsignedType* ptr,
+                                                   size_t size) noexcept
+      // SAFETY: propagated to caller via UNSAFE_BUFFER_USAGE.
+      : m_Span(UNSAFE_BUFFERS(pdfium::make_span(ptr, size))) {}
+
   // This is not a raw_span<> because StringViewTemplates must be passed by
   // value without introducing BackupRefPtr churn. Also, repeated re-assignment
   // of substrings of a StringViewTemplate to itself must avoid the same issue.
diff --git a/core/fxcrt/widestring_unittest.cpp b/core/fxcrt/widestring_unittest.cpp
index 7b89ca2..727ffc4 100644
--- a/core/fxcrt/widestring_unittest.cpp
+++ b/core/fxcrt/widestring_unittest.cpp
@@ -2136,8 +2136,9 @@
   // a C++-style string.
   {
     wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
+    // SAFETY: known array above.
+    auto str = UNSAFE_BUFFERS(WideStringView::Create(stringWithNulls, 4));
     std::ostringstream stream;
-    WideStringView str(stringWithNulls, 4);
     EXPECT_EQ(4u, str.GetLength());
     stream << str;
     EXPECT_EQ(4u, stream.tellp());
@@ -2214,8 +2215,9 @@
   // a C++-style string.
   {
     wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
+    // SAFETY: known array above.
+    auto str = UNSAFE_BUFFERS(WideStringView::Create(stringWithNulls, 4));
     std::wostringstream stream;
-    WideStringView str(stringWithNulls, 4);
     EXPECT_EQ(4u, str.GetLength());
     stream << str;
     EXPECT_EQ(4u, stream.tellp());
diff --git a/fxjs/fxv8.cpp b/fxjs/fxv8.cpp
index eafd5e2..95b0dfe 100644
--- a/fxjs/fxv8.cpp
+++ b/fxjs/fxv8.cpp
@@ -6,6 +6,7 @@
 
 #include "fxjs/fxv8.h"
 
+#include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/numerics/safe_conversions.h"
 #include "v8/include/v8-container.h"
 #include "v8/include/v8-date.h"
@@ -120,7 +121,9 @@
 
 WideString ToWideString(v8::Isolate* pIsolate, v8::Local<v8::String> pValue) {
   v8::String::Utf8Value s(pIsolate, pValue);
-  return WideString::FromUTF8(ByteStringView(*s, s.length()));
+  // SAFETY: required from V8.
+  return WideString::FromUTF8(
+      UNSAFE_BUFFERS(ByteStringView::Create(*s, s.length())));
 }
 
 ByteString ToByteString(v8::Isolate* pIsolate, v8::Local<v8::String> pValue) {
diff --git a/fxjs/xfa/cfxjse_class.cpp b/fxjs/xfa/cfxjse_class.cpp
index da8053e..adb3d48 100644
--- a/fxjs/xfa/cfxjse_class.cpp
+++ b/fxjs/xfa/cfxjse_class.cpp
@@ -11,6 +11,7 @@
 
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/check_op.h"
+#include "core/fxcrt/compiler_specific.h"
 #include "fxjs/cjs_result.h"
 #include "fxjs/fxv8.h"
 #include "fxjs/js_resources.h"
@@ -203,7 +204,9 @@
 
   v8::HandleScope scope(info.GetIsolate());
   v8::String::Utf8Value szPropName(info.GetIsolate(), property);
-  ByteStringView szFxPropName(*szPropName, szPropName.length());
+  // SAFETY: required from V8.
+  auto szFxPropName =
+      UNSAFE_BUFFERS(ByteStringView::Create(*szPropName, szPropName.length()));
   if (DynPropQueryAdapter(info.GetIsolate(), pClass, info.Holder(),
                           szFxPropName)) {
     info.GetReturnValue().Set(v8::DontDelete);
@@ -223,7 +226,9 @@
   }
 
   v8::String::Utf8Value szPropName(info.GetIsolate(), property);
-  ByteStringView szFxPropName(*szPropName, szPropName.length());
+  // SAFETY: required from V8.
+  auto szFxPropName =
+      UNSAFE_BUFFERS(ByteStringView::Create(*szPropName, szPropName.length()));
   std::unique_ptr<CFXJSE_Value> pNewValue = DynPropGetterAdapter(
       info.GetIsolate(), pClass, info.Holder(), szFxPropName);
   info.GetReturnValue().Set(pNewValue->DirectGetValue());
@@ -241,7 +246,9 @@
   }
 
   v8::String::Utf8Value szPropName(info.GetIsolate(), property);
-  ByteStringView szFxPropName(*szPropName, szPropName.length());
+  // SAFETY: required from V8.
+  auto szFxPropName =
+      UNSAFE_BUFFERS(ByteStringView::Create(*szPropName, szPropName.length()));
   auto pNewValue = std::make_unique<CFXJSE_Value>(info.GetIsolate(), value);
   DynPropSetterAdapter(info.GetIsolate(), pClass, info.Holder(), szFxPropName,
                        pNewValue.get());
diff --git a/testing/fuzzers/pdf_cfgas_stringformatter_fuzzer.cc b/testing/fuzzers/pdf_cfgas_stringformatter_fuzzer.cc
index 12f6206..ba9d538 100644
--- a/testing/fuzzers/pdf_cfgas_stringformatter_fuzzer.cc
+++ b/testing/fuzzers/pdf_cfgas_stringformatter_fuzzer.cc
@@ -9,6 +9,7 @@
 #include <iterator>
 
 #include "core/fxcrt/cfx_datetime.h"
+#include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/fx_string.h"
 #include "public/fpdfview.h"
 #include "testing/fuzzers/pdfium_fuzzer_util.h"
@@ -43,10 +44,10 @@
 
   size_t pattern_len = size / 2;
   size_t value_len = size - pattern_len;
-  WideString pattern =
-      WideString::FromLatin1(ByteStringView(data, pattern_len));
-  WideString value =
-      WideString::FromLatin1(ByteStringView(data + pattern_len, value_len));
+  WideString pattern = WideString::FromLatin1(
+      UNSAFE_TODO(ByteStringView::Create(data, pattern_len)));
+  WideString value = WideString::FromLatin1(
+      UNSAFE_TODO(ByteStringView::Create(data + pattern_len, value_len)));
 
   auto fmt = std::make_unique<CFGAS_StringFormatter>(pattern);
 
diff --git a/testing/fuzzers/pdf_css_fuzzer.cc b/testing/fuzzers/pdf_css_fuzzer.cc
index f11705c..2f6c200 100644
--- a/testing/fuzzers/pdf_css_fuzzer.cc
+++ b/testing/fuzzers/pdf_css_fuzzer.cc
@@ -7,8 +7,9 @@
 #include "core/fxcrt/fx_string.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  WideString input =
-      WideString::FromUTF8(ByteStringView(data, static_cast<size_t>(size)));
+  // SAFETY: required from fuzzer.
+  WideString input = WideString::FromUTF8(
+      UNSAFE_BUFFERS(ByteStringView::Create(data, static_cast<size_t>(size))));
 
   // If we convert the input into an empty string bail out.
   if (input.IsEmpty())
diff --git a/testing/fuzzers/pdf_formcalc_context_fuzzer.cc b/testing/fuzzers/pdf_formcalc_context_fuzzer.cc
index c1255b0..14ccff1 100644
--- a/testing/fuzzers/pdf_formcalc_context_fuzzer.cc
+++ b/testing/fuzzers/pdf_formcalc_context_fuzzer.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/fx_string.h"
 #include "fpdfsdk/cpdfsdk_helpers.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
@@ -525,7 +526,7 @@
     params.m_bCancelAction = false;
     CFXJSE_Engine::EventParamScope param_scope(script_context, nullptr,
                                                &params);
-    ByteStringView data_view(data_, size_);
+    auto data_view = UNSAFE_TODO(ByteStringView::Create(data_, size_));
     script_context->RunScript(CXFA_Script::Type::Formcalc,
                               WideString::FromUTF8(data_view).AsStringView(),
                               xfa_document->GetRoot());
diff --git a/testing/fuzzers/pdf_formcalc_fuzzer.cc b/testing/fuzzers/pdf_formcalc_fuzzer.cc
index d8a2a895..b03ac0b 100644
--- a/testing/fuzzers/pdf_formcalc_fuzzer.cc
+++ b/testing/fuzzers/pdf_formcalc_fuzzer.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/fx_string.h"
 #include "testing/fuzzers/pdfium_fuzzer_util.h"
 #include "testing/fuzzers/xfa_process_state.h"
@@ -9,7 +10,9 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   auto* state = static_cast<XFAProcessState*>(FPDF_GetFuzzerPerProcessState());
-  WideString input = WideString::FromUTF8(ByteStringView(data, size));
+  // SAFETY: required from fuzzer.
+  WideString input =
+      WideString::FromUTF8(UNSAFE_BUFFERS(ByteStringView::Create(data, size)));
   CXFA_FMLexer lexer(input.AsStringView());
   CXFA_FMParser parser(state->GetHeap(), &lexer);
   parser.Parse();
diff --git a/testing/fuzzers/pdf_formcalc_translate_fuzzer.cc b/testing/fuzzers/pdf_formcalc_translate_fuzzer.cc
index 82b8188..d3c8e63 100644
--- a/testing/fuzzers/pdf_formcalc_translate_fuzzer.cc
+++ b/testing/fuzzers/pdf_formcalc_translate_fuzzer.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/fx_safe_types.h"
 #include "core/fxcrt/fx_string.h"
 #include "fxjs/xfa/cfxjse_formcalc_context.h"
@@ -13,7 +14,9 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   auto* state = static_cast<XFAProcessState*>(FPDF_GetFuzzerPerProcessState());
-  WideString input = WideString::FromUTF8(ByteStringView(data, size));
+  // SAFETY: required from fuzzer.
+  WideString input =
+      WideString::FromUTF8(UNSAFE_BUFFERS(ByteStringView::Create(data, size)));
   CFXJSE_FormCalcContext::Translate(state->GetHeap(), input.AsStringView());
   state->ForceGCAndPump();
   return 0;
diff --git a/xfa/fgas/font/cfgas_defaultfontmanager.cpp b/xfa/fgas/font/cfgas_defaultfontmanager.cpp
index 7ff89d6..ec57a66 100644
--- a/xfa/fgas/font/cfgas_defaultfontmanager.cpp
+++ b/xfa/fgas/font/cfgas_defaultfontmanager.cpp
@@ -45,8 +45,8 @@
       UNSAFE_TODO(pNameText++);
       iLength--;
     }
-    WideString wsReplace =
-        WideString::FromASCII(ByteStringView(pReplace, pNameText - pReplace));
+    WideString wsReplace = WideString::FromASCII(
+        UNSAFE_TODO(ByteStringView::Create(pReplace, pNameText - pReplace)));
     pFont =
         pFontMgr->LoadFont(wsReplace.c_str(), dwStyle, FX_CodePage::kFailure);
     if (pFont)
diff --git a/xfa/fgas/layout/cfgas_rtfbreak_unittest.cpp b/xfa/fgas/layout/cfgas_rtfbreak_unittest.cpp
index 22421f3..43519ab 100644
--- a/xfa/fgas/layout/cfgas_rtfbreak_unittest.cpp
+++ b/xfa/fgas/layout/cfgas_rtfbreak_unittest.cpp
@@ -80,7 +80,9 @@
   rtf_break->SetLineBreakTolerance(1);
   rtf_break->SetFontSize(12);
 
-  WideString input = WideString::FromUTF8(ByteStringView("\xa\x0\xa\xa", 4));
+  // SAFETY: known fixed-length string.
+  WideString input = WideString::FromUTF8(
+      UNSAFE_BUFFERS(ByteStringView::Create("\xa\x0\xa\xa", 4)));
   for (wchar_t ch : input)
     rtf_break->AppendChar(ch);
 
diff --git a/xfa/fgas/layout/cfgas_txtbreak_unittest.cpp b/xfa/fgas/layout/cfgas_txtbreak_unittest.cpp
index ff472ac..6fed525 100644
--- a/xfa/fgas/layout/cfgas_txtbreak_unittest.cpp
+++ b/xfa/fgas/layout/cfgas_txtbreak_unittest.cpp
@@ -37,7 +37,9 @@
   txt_break->SetLineBreakTolerance(1);
   txt_break->SetFontSize(12);
 
-  WideString input = WideString::FromUTF8(ByteStringView("\xa\x0\xa\xa", 4));
+  // SAFETY: known fixed-length string.
+  WideString input = WideString::FromUTF8(
+      UNSAFE_BUFFERS(ByteStringView::Create("\xa\x0\xa\xa", 4)));
   for (wchar_t ch : input)
     txt_break->AppendChar(ch);
 
diff --git a/xfa/fxfa/cxfa_textlayout.cpp b/xfa/fxfa/cxfa_textlayout.cpp
index 575e946..696324c 100644
--- a/xfa/fxfa/cxfa_textlayout.cpp
+++ b/xfa/fxfa/cxfa_textlayout.cpp
@@ -12,6 +12,7 @@
 #include <utility>
 
 #include "core/fxcrt/check.h"
+#include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/css/cfx_csscomputedstyle.h"
 #include "core/fxcrt/css/cfx_cssstyleselector.h"
 #include "core/fxcrt/notreached.h"
@@ -802,10 +803,11 @@
         wsText = WideString(L'\n');
       } else if (wsName.EqualsASCII("li")) {
         bCurLi = true;
-        if (bIsOl)
+        if (bIsOl) {
           wsText = WideString::Format(L"%d.  ", iLiCount);
-        else
-          wsText = 0x00B7 + WideStringView(L"  ", 1);
+        } else {
+          wsText = 0x00B7 + WideStringView(L" ");
+        }
       } else if (!bContentNode) {
         if (iTabCount > 0) {
           while (iTabCount-- > 0)
diff --git a/xfa/fxfa/formcalc/cxfa_fmlexer_unittest.cpp b/xfa/fxfa/formcalc/cxfa_fmlexer_unittest.cpp
index aaeaa43..5224fca 100644
--- a/xfa/fxfa/formcalc/cxfa_fmlexer_unittest.cpp
+++ b/xfa/fxfa/formcalc/cxfa_fmlexer_unittest.cpp
@@ -308,7 +308,8 @@
 }
 
 TEST(CXFA_FMLexerTest, NullData) {
-  CXFA_FMLexer lexer(WideStringView(L"\x2d\x32\x00\x2d\x32", 5));
+  CXFA_FMLexer lexer(
+      UNSAFE_TODO(WideStringView::Create(L"\x2d\x32\x00\x2d\x32", 5)));
   CXFA_FMLexer::Token token = lexer.NextToken();
   EXPECT_EQ(TOKminus, token.GetType());