TEST_F(MallocDebugConfigTest, overflow) {
  ASSERT_FALSE(InitConfig("backtrace=99999999999999999999"));

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  std::string log_msg(
      "6 malloc_debug malloc_testing: bad value for option 'backtrace': "
      "Math result not representable\n");
  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, rear_guard_max_error) {
  ASSERT_FALSE(InitConfig("rear_guard=20000"));

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  std::string log_msg(
      "6 malloc_debug malloc_testing: bad value for option 'rear_guard', "
      "value must be <= 16384: 20000\n");
  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, no_space) {
  ASSERT_FALSE(InitConfig("backtrace=10front_guard"));

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  std::string log_msg(
      "6 malloc_debug malloc_testing: bad value for option 'backtrace', "
      "non space found after option: front_guard\n");
  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, illegal_value_negative) {
  ASSERT_FALSE(InitConfig("backtrace=-1"));

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  std::string log_msg(
      "6 malloc_debug malloc_testing: bad value for option 'backtrace', "
      "value cannot be negative: -1\n");
  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames_zero) {
  ASSERT_TRUE(InitConfig("free_track_backtrace_num_frames=0"));

  ASSERT_EQ(0U, config->options);
  ASSERT_EQ(0U, config->free_track_backtrace_num_frames);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames_max_error) {
  ASSERT_FALSE(InitConfig("free_track_backtrace_num_frames=400"));

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  std::string log_msg(
      "6 malloc_debug malloc_testing: bad value for option 'free_track_backtrace_num_frames', "
      "value must be <= 256: 400\n");
  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, backtrace_enable_on_signal_max_error) {
  ASSERT_FALSE(InitConfig("backtrace_enable_on_signal=300"));

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  std::string log_msg(
      "6 malloc_debug malloc_testing: bad value for option 'backtrace_enable_on_signal', "
      "value must be <= 256: 300\n");
  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, leak_track_fail) {
  ASSERT_FALSE(InitConfig("leak_track=100"));

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  std::string log_msg(
      "6 malloc_debug malloc_testing: value set for option 'leak_track' "
      "which does not take a value\n");
  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, fill_min_error) {
  ASSERT_FALSE(InitConfig("fill=0"));

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  std::string log_msg(
      "6 malloc_debug malloc_testing: bad value for option 'fill', "
      "value must be >= 1: 0\n");
  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, multiple_options) {
  ASSERT_TRUE(InitConfig("  backtrace=64   front_guard=48"));
  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS | FRONT_GUARD, config->options);
  ASSERT_EQ(64U, config->backtrace_frames);
  ASSERT_EQ(48U, config->front_guard_bytes);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
  backtrace_map_t map;

  map.start = 0xa434000;
  map.end = 0xa435000;
  map.offset = 0x1000;
  map.load_base = 0xd000;
  map.flags = PROT_WRITE;
  map_mock_->AddMap(map);

  map.start = 0xa534000;
  map.end = 0xa535000;
  map.offset = 0x3000;
  map.load_base = 0x2000;
  map.flags = PROT_EXEC;
  map_mock_->AddMap(map);

  map.start = 0xa634000;
  map.end = 0xa635000;
  map.offset = 0;
  map.load_base = 0;
  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
  map.name = "/system/lib/fake.so";
  map_mock_->AddMap(map);

  siginfo_t si;
  si.si_signo = SIGBUS;
  si.si_addr = reinterpret_cast<void*>(0xa533000);
  ptrace_set_fake_getsiginfo(si);
  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);

  std::string tombstone_contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
  const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
"--->Fault address falls at 00000000'0a533000 between mapped regions\n"
"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
#else
"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
"--->Fault address falls at 0a533000 between mapped regions\n"
"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
#endif
  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());

  ASSERT_STREQ("", amfd_data_.c_str());

  // Verify that the log buf is empty, and no error messages.
  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, rear_guard) {
  ASSERT_TRUE(InitConfig("rear_guard=50"));
  ASSERT_EQ(REAR_GUARD, config->options);
  ASSERT_EQ(50U, config->rear_guard_bytes);

  ASSERT_TRUE(InitConfig("rear_guard"));
  ASSERT_EQ(REAR_GUARD, config->options);
  ASSERT_EQ(32U, config->rear_guard_bytes);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, expand_alloc) {
  ASSERT_TRUE(InitConfig("expand_alloc=1234"));
  ASSERT_EQ(EXPAND_ALLOC, config->options);
  ASSERT_EQ(1234U, config->expand_alloc_bytes);

  ASSERT_TRUE(InitConfig("expand_alloc"));
  ASSERT_EQ(EXPAND_ALLOC, config->options);
  ASSERT_EQ(16U, config->expand_alloc_bytes);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames_and_free_track) {
  ASSERT_TRUE(InitConfig("free_track free_track_backtrace_num_frames=123"));
  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
  ASSERT_EQ(123U, config->free_track_backtrace_num_frames);

  ASSERT_TRUE(InitConfig("free_track free_track_backtrace_num_frames"));
  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, fill_on_free) {
  ASSERT_TRUE(InitConfig("fill_on_free=64"));
  ASSERT_EQ(FILL_ON_FREE, config->options);
  ASSERT_EQ(64U, config->fill_on_free_bytes);

  ASSERT_TRUE(InitConfig("fill_on_free"));
  ASSERT_EQ(FILL_ON_FREE, config->options);
  ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, backtrace_enable_on_signal) {
  ASSERT_TRUE(InitConfig("backtrace_enable_on_signal=64"));
  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
  ASSERT_EQ(64U, config->backtrace_frames);

  ASSERT_TRUE(InitConfig("backtrace_enable_on_signal"));
  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
  ASSERT_EQ(16U, config->backtrace_frames);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, guard) {
  ASSERT_TRUE(InitConfig("guard=32"));
  ASSERT_EQ(FRONT_GUARD | REAR_GUARD, config->options);
  ASSERT_EQ(32U, config->front_guard_bytes);
  ASSERT_EQ(32U, config->rear_guard_bytes);

  ASSERT_TRUE(InitConfig("guard"));
  ASSERT_EQ(FRONT_GUARD | REAR_GUARD, config->options);
  ASSERT_EQ(32U, config->front_guard_bytes);
  ASSERT_EQ(32U, config->rear_guard_bytes);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, free_track_and_fill_on_free) {
  ASSERT_TRUE(InitConfig("free_track=1234 fill_on_free=32"));
  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
  ASSERT_EQ(1234U, config->free_track_allocations);
  ASSERT_EQ(32U, config->fill_on_free_bytes);

  ASSERT_TRUE(InitConfig("free_track fill_on_free=60"));
  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
  ASSERT_EQ(100U, config->free_track_allocations);
  ASSERT_EQ(60U, config->fill_on_free_bytes);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, front_guard) {
  ASSERT_TRUE(InitConfig("front_guard=48")) << getFakeLogPrint();
  ASSERT_EQ(FRONT_GUARD, config->options);
  ASSERT_EQ(48U, config->front_guard_bytes);

  ASSERT_TRUE(InitConfig("front_guard")) << getFakeLogPrint();
  ASSERT_EQ(FRONT_GUARD, config->options);
  ASSERT_EQ(32U, config->front_guard_bytes);

  ASSERT_TRUE(InitConfig("front_guard=39")) << getFakeLogPrint();
  ASSERT_EQ(FRONT_GUARD, config->options);
#if defined(__LP64__)
  ASSERT_EQ(48U, config->front_guard_bytes);
#else
  ASSERT_EQ(40U, config->front_guard_bytes);
#endif

  ASSERT_TRUE(InitConfig("front_guard=41")) << getFakeLogPrint();
  ASSERT_EQ(FRONT_GUARD, config->options);
  ASSERT_EQ(48U, config->front_guard_bytes);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, dump_log_file_error) {
  log_.should_retrieve_logcat = true;
  dump_log_file(&log_, 123, "/fake/filename", 10);

  std::string tombstone_contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
  ASSERT_STREQ("", tombstone_contents.c_str());

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
               getFakeLogPrint().c_str());

  ASSERT_STREQ("", amfd_data_.c_str());
}
TEST_F(MallocDebugConfigTest, front_guard) {
  ASSERT_TRUE(InitConfig("front_guard=24"));
  ASSERT_EQ(FRONT_GUARD, config->options);
  ASSERT_EQ(24U, config->front_guard_bytes);

  ASSERT_TRUE(InitConfig("front_guard"));
  ASSERT_EQ(FRONT_GUARD, config->options);
  ASSERT_EQ(32U, config->front_guard_bytes);

  ASSERT_TRUE(InitConfig("front_guard=39"));
  ASSERT_EQ(FRONT_GUARD, config->options);
  ASSERT_EQ(40U, config->front_guard_bytes);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(MallocDebugConfigTest, free_track) {
  ASSERT_TRUE(InitConfig("free_track=1234"));
  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
  ASSERT_EQ(1234U, config->free_track_allocations);
  ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);
  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);

  ASSERT_TRUE(InitConfig("free_track"));
  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
  ASSERT_EQ(100U, config->free_track_allocations);
  ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);
  ASSERT_EQ(16U, config->free_track_backtrace_num_frames);

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, dump_signal_info_error) {
  siginfo_t si;
  si.si_signo = 0;
  ptrace_set_fake_getsiginfo(si);

  dump_signal_info(&log_, 123, SIGSEGV, 10);

  std::string tombstone_contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
  ASSERT_STREQ("", tombstone_contents.c_str());

  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("6 DEBUG cannot get siginfo: Bad address\n\n", getFakeLogPrint().c_str());

  ASSERT_STREQ("", amfd_data_.c_str());
}
// Even though build id is present, it should not be printed in either of
// these cases.
TEST_F(TombstoneTest, single_map_no_build_id) {
  backtrace_map_t map;
#if defined(__LP64__)
  map.start = 0x123456789abcd000UL;
  map.end = 0x123456789abdf000UL;
#else
  map.start = 0x1234000;
  map.end = 0x1235000;
#endif
  map.flags = PROT_WRITE;
  map_mock_->AddMap(map);

  map.name = "/system/lib/libfake.so";
  map_mock_->AddMap(map);

  elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);

  std::string tombstone_contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
  const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
"    12345678'9abcd000-12345678'9abdefff -w-         0     12000\n"
"    12345678'9abcd000-12345678'9abdefff -w-         0     12000  /system/lib/libfake.so\n";
#else
"    01234000-01234fff -w-         0      1000\n"
"    01234000-01234fff -w-         0      1000  /system/lib/libfake.so\n";
#endif
  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());

  ASSERT_STREQ("", amfd_data_.c_str());

  // Verify that the log buf is empty, and no error messages.
  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(DumpMapsTest, multiple_maps_check_signal_has_si_addr) {
  backtrace_map_t map;

  map.start = 0xa434000;
  map.end = 0xa435000;
  map.flags = PROT_WRITE;
  map_mock_->AddMap(map);

  for (int i = 1; i < 255; i++) {
    ASSERT_TRUE(ftruncate(log_.tfd, 0) == 0);
    ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);

    siginfo_t si;
    si.si_signo = i;
    si.si_addr = reinterpret_cast<void*>(0x1000);
    ptrace_set_fake_getsiginfo(si);
    dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);

    std::string tombstone_contents;
    ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
    ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
    bool has_addr = false;
    switch (si.si_signo) {
    case SIGBUS:
    case SIGFPE:
    case SIGILL:
    case SIGSEGV:
    case SIGTRAP:
      has_addr = true;
      break;
    }

    const char* expected_addr_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
"    00000000'0a434000-00000000'0a434fff -w-         0      1000\n";
#else
"--->Fault address falls at 00001000 before any mapped regions\n"
"    0a434000-0a434fff -w-         0      1000\n";
#endif
    const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
"    00000000'0a434000-00000000'0a434fff -w-         0      1000\n";
#else
"    0a434000-0a434fff -w-         0      1000\n";
#endif
    if (has_addr) {
      ASSERT_STREQ(expected_addr_dump, tombstone_contents.c_str())
        << "Signal " << si.si_signo << " expected to include an address.";
    } else {
      ASSERT_STREQ(expected_dump, tombstone_contents.c_str())
        << "Signal " << si.si_signo << " is not expected to include an address.";
    }

    // Verify that the log buf is empty, and no error messages.
    ASSERT_STREQ("", getFakeLogBuf().c_str());
    ASSERT_STREQ("", getFakeLogPrint().c_str());
  }
}
TEST_F(DumpMapsTest, multiple_maps) {
  backtrace_map_t map;

  map.start = 0xa234000;
  map.end = 0xa235000;
  map_mock_->AddMap(map);

  map.start = 0xa334000;
  map.end = 0xa335000;
  map.offset = 0xf000;
  map.flags = PROT_READ;
  map_mock_->AddMap(map);

  map.start = 0xa434000;
  map.end = 0xa435000;
  map.offset = 0x1000;
  map.load_base = 0xd000;
  map.flags = PROT_WRITE;
  map_mock_->AddMap(map);

  map.start = 0xa534000;
  map.end = 0xa535000;
  map.offset = 0x3000;
  map.load_base = 0x2000;
  map.flags = PROT_EXEC;
  map_mock_->AddMap(map);

  map.start = 0xa634000;
  map.end = 0xa635000;
  map.offset = 0;
  map.load_base = 0;
  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
  map.name = "/system/lib/fake.so";
  map_mock_->AddMap(map);

  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);

  std::string tombstone_contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
  const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
"    00000000'0a234000-00000000'0a234fff ---         0      1000\n"
"    00000000'0a334000-00000000'0a334fff r--      f000      1000\n"
"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
#else
"    0a234000-0a234fff ---         0      1000\n"
"    0a334000-0a334fff r--      f000      1000\n"
"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
#endif
  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());

  // Verify that the log buf is empty, and no error messages.
  ASSERT_STREQ("", getFakeLogBuf().c_str());
  ASSERT_STREQ("", getFakeLogPrint().c_str());
}