Add a test case for another FPDFAttachment_GetFile() failure mode.

FPDFAttachment_GetFile() has almost full test coverage, except in the
case of a malformed attachment without an embedded file (/EF). Create
such a PDF and test FPDFAttachment_* APIs against it.

Bug: chromium:177188
Change-Id: I2a0f1b197dbe3609a753516c239116e0e3a06713
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/70631
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_attachment_embeddertest.cpp b/fpdfsdk/fpdf_attachment_embeddertest.cpp
index 2f79ae5..2b6c8b6 100644
--- a/fpdfsdk/fpdf_attachment_embeddertest.cpp
+++ b/fpdfsdk/fpdf_attachment_embeddertest.cpp
@@ -108,6 +108,30 @@
   EXPECT_FALSE(FPDFDoc_GetAttachment(document(), 0));
 }
 
+TEST_F(FPDFAttachmentEmbedderTest, InvalidAttachmentData) {
+  // Open a file with an attachment that is missing the embedded file (/EF).
+  ASSERT_TRUE(OpenDocument("embedded_attachments_invalid_data.pdf"));
+  ASSERT_EQ(1, FPDFDoc_GetAttachmentCount(document()));
+
+  // Retrieve the first attachment.
+  FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(document(), 0);
+  ASSERT_TRUE(attachment);
+
+  // Check that the name of the attachment is correct.
+  unsigned long length_bytes = FPDFAttachment_GetName(attachment, nullptr, 0);
+  ASSERT_EQ(12u, length_bytes);
+  std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
+  EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), length_bytes));
+  EXPECT_EQ("1.txt", GetPlatformString(buf.data()));
+
+  // Check that is is not possible to retrieve the file data.
+  EXPECT_FALSE(FPDFAttachment_GetFile(attachment, nullptr, 0, &length_bytes));
+
+  // Check that the attachment can be deleted.
+  EXPECT_TRUE(FPDFDoc_DeleteAttachment(document(), 0));
+  EXPECT_EQ(0, FPDFDoc_GetAttachmentCount(document()));
+}
+
 TEST_F(FPDFAttachmentEmbedderTest, AddAttachments) {
   // Open a file with two attachments.
   ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
diff --git a/testing/resources/embedded_attachments_invalid_data.in b/testing/resources/embedded_attachments_invalid_data.in
new file mode 100644
index 0000000..26545a4
--- /dev/null
+++ b/testing/resources/embedded_attachments_invalid_data.in
@@ -0,0 +1,41 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Names 4 0 R
+  /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+  /Type /Pages
+  /Count 1
+  /Kids [3 0 R]
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /MediaBox [0 0 612 792]
+  /Resources <<
+    /ProcSet [/PDF]
+  >>
+>>
+endobj
+{{object 4 0}} <<
+  /EmbeddedFiles 5 0 R
+>>
+endobj
+{{object 5 0}} <<
+  /Names [(1.txt) 6 0 R]
+>>
+endobj
+{{object 6 0}} <<
+  /Type /Filespec
+  /Desc ()
+  /F (1.txt)
+  /UF (1.txt)
+>>
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/embedded_attachments_invalid_data.pdf b/testing/resources/embedded_attachments_invalid_data.pdf
new file mode 100644
index 0000000..8a830e2
--- /dev/null
+++ b/testing/resources/embedded_attachments_invalid_data.pdf
@@ -0,0 +1,54 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+  /Type /Catalog
+  /Names 4 0 R
+  /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+  /Type /Pages
+  /Count 1
+  /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+  /Type /Page
+  /Parent 2 0 R
+  /MediaBox [0 0 612 792]
+  /Resources <<
+    /ProcSet [/PDF]
+  >>
+>>
+endobj
+4 0 obj <<
+  /EmbeddedFiles 5 0 R
+>>
+endobj
+5 0 obj <<
+  /Names [(1.txt) 6 0 R]
+>>
+endobj
+6 0 obj <<
+  /Type /Filespec
+  /Desc ()
+  /F (1.txt)
+  /UF (1.txt)
+>>
+endobj
+xref
+0 7
+0000000000 65535 f 
+0000000015 00000 n 
+0000000083 00000 n 
+0000000146 00000 n 
+0000000264 00000 n 
+0000000308 00000 n 
+0000000354 00000 n 
+trailer <<
+  /Root 1 0 R
+  /Size 7
+>>
+startxref
+431
+%%EOF