<commit_before>/*
Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https ://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

#include <mach/mach_vm.h>
#include <mach-o/dyld_images.h>

#include "macOS/machtarget.h"
#include "common.h"

#define INVALID_PAGE_SIZE ((vm_size_t)(~0))

#ifdef ARM64
  #define ARCH_THREAD_STATE ARM_THREAD_STATE64
#else
  #define ARCH_THREAD_STATE x86_THREAD_STATE64
#endif

MachTarget::MachTarget(pid_t target_pid): pid(target_pid), m_page_size(INVALID_PAGE_SIZE) {
  kern_return_t krt;

  krt = task_for_pid(mach_task_self(), pid, &task);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) calling task_for_pid\n", mach_error_string(krt));
  }

  krt = task_get_exception_ports(task,
                                  EXC_MASK_ALL,
                                  saved_masks,
                                  &saved_exception_types_count,
                                  saved_ports,
                                  saved_behaviors,
                                  saved_flavors);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) saving the exception ports registered in the process\n", mach_error_string(krt));
  }

  krt = mach_port_allocate(mach_task_self(),
                           MACH_PORT_RIGHT_RECEIVE,
                           &exception_port);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) allocating a new port\n", mach_error_string(krt));
  }

  mach_port_insert_right(mach_task_self(),
                         exception_port,
                         exception_port,
                         MACH_MSG_TYPE_MAKE_SEND);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) authorizing a new exception port\n", mach_error_string(krt));
  }

  /* register the exception port with the target process */
  task_set_exception_ports(task,
                           EXC_MASK_ALL,
                           exception_port,
                           EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
                           ARCH_THREAD_STATE);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) registering the exception port with the target process\n", mach_error_string(krt));
  }

}


kern_return_t MachTarget::BasicInfo(mach_task_basic_info *info) {
  if (info == NULL) {
    return KERN_INVALID_ARGUMENT;
  }

  unsigned int count = MACH_TASK_BASIC_INFO_COUNT;
  return task_info(task, MACH_TASK_BASIC_INFO, (task_info_t)info, &count);
}

bool MachTarget::IsExceptionPortValid() {
  return MACH_PORT_VALID(exception_port);
}


bool MachTarget::IsTaskValid() {
  if (task != TASK_NULL) {
    mach_task_basic_info task_info;
    return BasicInfo(&task_info) == KERN_SUCCESS;
  }

  return false;
}

void MachTarget::GetRegionSubmapInfo(mach_vm_address_t *region_address,
                                     mach_vm_size_t *region_size,
                                     vm_region_submap_info_data_64_t *info) {
  kern_return_t krt;
  uint32_t depth = ~0;
  mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
  krt = mach_vm_region_recurse(task,
                               region_address,
                               region_size,
                               &depth,
                               (vm_region_recurse_info_t)info,
                               &count);

  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) retrieving region information\n", mach_error_string(krt));
  }
}

kern_return_t MachTarget::WaitForException(uint32_t timeout, mach_msg_header_t *req, uint32_t size) {
  kern_return_t krt;
  krt = mach_msg(req,  /* receive buffer */
                 MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_INTERRUPT,
                 0,                         /* size of send buffer */
                 size,                      /* size of receive buffer */
                 exception_port,            /* port to receive on */
                 timeout,                   /* wait for timeout seconds */
                 MACH_PORT_NULL);           /* notify port, unused */

  return krt;
}

void MachTarget::ReplyToException(mach_msg_header_t *rpl) {
  kern_return_t krt;
  krt = mach_msg(rpl,  /* send buffer */
                MACH_SEND_MSG | MACH_SEND_INTERRUPT,             /* send message */
                rpl->msgh_size,            /* size of send buffer */
                0,                         /* size of receive buffer */
                MACH_PORT_NULL,            /* port to receive on */
                MACH_MSG_TIMEOUT_NONE,     /* wait indefinitely */
                MACH_PORT_NULL);           /* notify port, unused */

  if (krt != MACH_MSG_SUCCESS) {
    FATAL("Error (%s) sending reply to exception port\n", mach_error_string(krt));
  }
}
<commit_msg>Avoid erroring out when replying to a dead process<commit_after>/*
Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https ://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

#include <mach/mach_vm.h>
#include <mach-o/dyld_images.h>

#include "macOS/machtarget.h"
#include "common.h"

#define INVALID_PAGE_SIZE ((vm_size_t)(~0))

#ifdef ARM64
  #define ARCH_THREAD_STATE ARM_THREAD_STATE64
#else
  #define ARCH_THREAD_STATE x86_THREAD_STATE64
#endif

MachTarget::MachTarget(pid_t target_pid): pid(target_pid), m_page_size(INVALID_PAGE_SIZE) {
  kern_return_t krt;

  krt = task_for_pid(mach_task_self(), pid, &task);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) calling task_for_pid\n", mach_error_string(krt));
  }

  krt = task_get_exception_ports(task,
                                  EXC_MASK_ALL,
                                  saved_masks,
                                  &saved_exception_types_count,
                                  saved_ports,
                                  saved_behaviors,
                                  saved_flavors);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) saving the exception ports registered in the process\n", mach_error_string(krt));
  }

  krt = mach_port_allocate(mach_task_self(),
                           MACH_PORT_RIGHT_RECEIVE,
                           &exception_port);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) allocating a new port\n", mach_error_string(krt));
  }

  mach_port_insert_right(mach_task_self(),
                         exception_port,
                         exception_port,
                         MACH_MSG_TYPE_MAKE_SEND);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) authorizing a new exception port\n", mach_error_string(krt));
  }

  /* register the exception port with the target process */
  task_set_exception_ports(task,
                           EXC_MASK_ALL,
                           exception_port,
                           EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
                           ARCH_THREAD_STATE);
  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) registering the exception port with the target process\n", mach_error_string(krt));
  }

}


kern_return_t MachTarget::BasicInfo(mach_task_basic_info *info) {
  if (info == NULL) {
    return KERN_INVALID_ARGUMENT;
  }

  unsigned int count = MACH_TASK_BASIC_INFO_COUNT;
  return task_info(task, MACH_TASK_BASIC_INFO, (task_info_t)info, &count);
}

bool MachTarget::IsExceptionPortValid() {
  return MACH_PORT_VALID(exception_port);
}


bool MachTarget::IsTaskValid() {
  if (task != TASK_NULL) {
    mach_task_basic_info task_info;
    return BasicInfo(&task_info) == KERN_SUCCESS;
  }

  return false;
}

void MachTarget::GetRegionSubmapInfo(mach_vm_address_t *region_address,
                                     mach_vm_size_t *region_size,
                                     vm_region_submap_info_data_64_t *info) {
  kern_return_t krt;
  uint32_t depth = ~0;
  mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
  krt = mach_vm_region_recurse(task,
                               region_address,
                               region_size,
                               &depth,
                               (vm_region_recurse_info_t)info,
                               &count);

  if (krt != KERN_SUCCESS) {
    FATAL("Error (%s) retrieving region information\n", mach_error_string(krt));
  }
}

kern_return_t MachTarget::WaitForException(uint32_t timeout, mach_msg_header_t *req, uint32_t size) {
  kern_return_t krt;
  krt = mach_msg(req,  /* receive buffer */
                 MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_INTERRUPT,
                 0,                         /* size of send buffer */
                 size,                      /* size of receive buffer */
                 exception_port,            /* port to receive on */
                 timeout,                   /* wait for timeout seconds */
                 MACH_PORT_NULL);           /* notify port, unused */

  return krt;
}

void MachTarget::ReplyToException(mach_msg_header_t *rpl) {
  kern_return_t krt;
  krt = mach_msg(rpl,  /* send buffer */
                MACH_SEND_MSG | MACH_SEND_INTERRUPT,             /* send message */
                rpl->msgh_size,            /* size of send buffer */
                0,                         /* size of receive buffer */
                MACH_PORT_NULL,            /* port to receive on */
                MACH_MSG_TIMEOUT_NONE,     /* wait indefinitely */
                MACH_PORT_NULL);           /* notify port, unused */

  if (krt != MACH_MSG_SUCCESS) {
    // the target could be terminated at this point, check if that's the case
    if(!IsTaskValid() || !IsExceptionPortValid()) return;

    FATAL("Error (%s) sending reply to exception port\n", mach_error_string(krt));
  }
}

{'fraction_non_alphanumeric': 0.08592269799166351, 'fraction_numerical': 0.005683971201212581, 'mean_word_length': 2.110489098408957, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3701370', 'n_tokens_mistral': 3320, 'n_tokens_neox': 3188, 'n_words': 748}