Merge "Remove PauseTiming/ResumeTiming calls."
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c4b01e6..331fad6 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -115,7 +115,7 @@
         // fork succeeded -- this is executing in the child process
 
         // Close the pipe FD not used by this process
-        TEMP_FAILURE_RETRY(close(pipe_fds[0]));
+        close(pipe_fds[0]);
 
         // Redirect stderr to the pipe FD provided by the parent
         if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) {
@@ -123,7 +123,7 @@
             _exit(127);
             return false;
         }
-        TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+        close(pipe_fds[1]);
 
         if (execv(filename, argv) == -1) {
             PLOG(ERROR) << "Failed to execve " << filename;
@@ -137,7 +137,7 @@
         // fork succeeded -- this is executing in the original/parent process
 
         // Close the pipe FD not used by this process
-        TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+        close(pipe_fds[1]);
 
         // Log the redirected output of the child process.
         // It's unfortunate that there's no standard way to obtain an istream for a file descriptor.
@@ -148,7 +148,7 @@
         if (!android::base::ReadFdToString(child_out_fd, &child_output)) {
             PLOG(ERROR) << "Failed to capture full output of " << filename;
         }
-        TEMP_FAILURE_RETRY(close(child_out_fd));
+        close(child_out_fd);
         if (!child_output.empty()) {
             // Log captured output, line by line, because LOG expects to be invoked for each line
             std::istringstream in(child_output);
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 8b30b76..b8164c5 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -225,11 +225,13 @@
   // Find the return address location.
   if (return_address_undefined) {
     cur_regs->set_pc(0);
-    *finished = true;
   } else {
     cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
-    *finished = false;
   }
+
+  // If the pc was set to zero, consider this the final frame.
+  *finished = (cur_regs->pc() == 0) ? true : false;
+
   cur_regs->set_sp(cfa);
   // Return false if the unwind is not finished or the cfa and pc didn't change.
   return *finished || prev_cfa != cfa || prev_pc != cur_regs->pc();
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 30a1532..170a5cd 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -121,8 +121,10 @@
     }
     regs_arm->set_sp(arm.cfa());
     (*regs_arm)[ARM_REG_SP] = regs_arm->sp();
-    *finished = false;
     return_value = true;
+
+    // If the pc was set to zero, consider this the final frame.
+    *finished = (regs_arm->pc() == 0) ? true : false;
   }
 
   if (arm.status() == ARM_STATUS_NO_UNWIND) {
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index c701a29..7e85bbb 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -340,6 +340,23 @@
   EXPECT_EQ(0x10U, regs.sp());
 }
 
+TYPED_TEST_P(DwarfSectionImplTest, Eval_pc_zero) {
+  DwarfCie cie{.return_address_register = 5};
+  RegsImplFake<TypeParam> regs(10, 9);
+  dwarf_loc_regs_t loc_regs;
+
+  regs.set_pc(0x100);
+  regs.set_sp(0x2000);
+  regs[5] = 0;
+  regs[8] = 0x10;
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+  bool finished;
+  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_TRUE(finished);
+  EXPECT_EQ(0U, regs.pc());
+  EXPECT_EQ(0x10U, regs.sp());
+}
+
 TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address) {
   DwarfCie cie{.return_address_register = 5};
   RegsImplFake<TypeParam> regs(10, 9);
@@ -854,7 +871,7 @@
     Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
     Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
     Eval_invalid_register, Eval_different_reg_locations, Eval_return_address_undefined,
-    Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+    Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
     Eval_same_cfa_same_pc, GetCie_fail_should_not_cache, GetCie_32_version_check,
     GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
     GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index feb24ce..4b621c9 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -401,4 +401,40 @@
   ASSERT_EQ(0x1234U, regs.pc());
 }
 
+TEST_F(ElfInterfaceArmTest, StepExidx_pc_zero) {
+  ElfInterfaceArmFake interface(&memory_);
+
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(1);
+  memory_.SetData32(0x1000, 0x6000);
+  // Set the pc using a pop r15 command.
+  memory_.SetData32(0x1004, 0x808800b0);
+
+  // pc value of zero.
+  process_memory_.SetData32(0x10000, 0);
+
+  RegsArm regs;
+  regs[ARM_REG_SP] = 0x10000;
+  regs[ARM_REG_LR] = 0x20000;
+  regs.set_sp(regs[ARM_REG_SP]);
+  regs.set_pc(0x1234);
+
+  bool finished;
+  ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
+  ASSERT_TRUE(finished);
+  ASSERT_EQ(0U, regs.pc());
+
+  // Now set the pc from the lr register (pop r14).
+  memory_.SetData32(0x1004, 0x808400b0);
+
+  regs[ARM_REG_SP] = 0x10000;
+  regs[ARM_REG_LR] = 0x20000;
+  regs.set_sp(regs[ARM_REG_SP]);
+  regs.set_pc(0x1234);
+
+  ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
+  ASSERT_TRUE(finished);
+  ASSERT_EQ(0U, regs.pc());
+}
+
 }  // namespace unwindstack
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 5fd9155..e7520a8 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -297,23 +297,22 @@
 
 char16_t* strstr16(const char16_t* src, const char16_t* target)
 {
-    const char16_t needle = *target++;
-    const size_t target_len = strlen16(target);
-    if (needle != '\0') {
-      do {
+    const char16_t needle = *target;
+    if (needle == '\0') return (char16_t*)src;
+
+    const size_t target_len = strlen16(++target);
+    do {
         do {
-          if (*src == '\0') {
-            return nullptr;
-          }
+            if (*src == '\0') {
+                return nullptr;
+            }
         } while (*src++ != needle);
-      } while (strncmp16(src, target, target_len) != 0);
-      src--;
-    }
+    } while (strncmp16(src, target, target_len) != 0);
+    src--;
 
     return (char16_t*)src;
 }
 
-
 int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
 {
     const char16_t* e1 = s1+n1;
diff --git a/libutils/tests/Unicode_test.cpp b/libutils/tests/Unicode_test.cpp
index d23e43a..b92eef8 100644
--- a/libutils/tests/Unicode_test.cpp
+++ b/libutils/tests/Unicode_test.cpp
@@ -15,7 +15,11 @@
  */
 
 #define LOG_TAG "Unicode_test"
-#include <utils/Log.h>
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <log/log.h>
 #include <utils/Unicode.h>
 
 #include <gtest/gtest.h>
@@ -119,6 +123,31 @@
             << "should return the original pointer";
 }
 
+TEST_F(UnicodeTest, strstr16EmptyTarget_bug) {
+    // In the original code when target is an empty string strlen16() would
+    // start reading the memory until a "terminating null" (that is, zero)
+    // character is found.   This happens because "*target++" in the original
+    // code would increment the pointer beyond the actual string.
+    void* memptr;
+    const size_t alignment = sysconf(_SC_PAGESIZE);
+    const size_t size = 2 * alignment;
+    ASSERT_EQ(posix_memalign(&memptr, alignment, size), 0);
+    // Fill allocated memory.
+    memset(memptr, 'A', size);
+    // Create a pointer to an "empty" string on the first page.
+    char16_t* const emptyString = (char16_t* const)((char*)memptr + alignment - 4);
+    *emptyString = (char16_t)0;
+    // Protect the second page to show that strstr16() violates that.
+    ASSERT_EQ(mprotect((char*)memptr + alignment, alignment, PROT_NONE), 0);
+    // Test strstr16(): when bug is present a segmentation fault is raised.
+    ASSERT_EQ(strstr16((char16_t*)memptr, emptyString), (char16_t*)memptr)
+        << "should not read beyond the first char16_t.";
+    // Reset protection of the second page
+    ASSERT_EQ(mprotect((char*)memptr + alignment, alignment, PROT_READ | PROT_WRITE), 0);
+    // Free allocated memory.
+    free(memptr);
+}
+
 TEST_F(UnicodeTest, strstr16SameString) {
     const char16_t* result = strstr16(kSearchString, kSearchString);
     EXPECT_EQ(kSearchString, result)
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index fcd45bd..ff7e762 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -105,7 +105,7 @@
                 android::base::WriteStringToFd(
                     formatEntry_locked(it.first, AID_ROOT), fd);
             }
-            TEMP_FAILURE_RETRY(close(fd));
+            close(fd);
         }
     }
 
@@ -601,7 +601,7 @@
 
     std::string ret = formatEntry_locked(tag, uid, false);
     android::base::WriteStringToFd(ret, fd);
-    TEMP_FAILURE_RETRY(close(fd));
+    close(fd);
 
     size_t size = 0;
     file2watermark_const_iterator iwater;
@@ -625,7 +625,7 @@
 
     std::string ret = formatEntry_locked(tag, uid, false);
     android::base::WriteStringToFd(ret, fd);
-    TEMP_FAILURE_RETRY(close(fd));
+    close(fd);
 
     size_t size = 0;
     file2watermark_const_iterator iwater;