gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/fault.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #define _GNU_SOURCE 1
    16  #include <signal.h>
    17  #include <ucontext.h>
    18  #include <unistd.h>
    19  
    20  #include "gtest/gtest.h"
    21  #include "test/util/test_util.h"
    22  
    23  namespace gvisor {
    24  namespace testing {
    25  
    26  namespace {
    27  
    28  __attribute__((noinline)) void Fault(void) {
    29    volatile int* foo = nullptr;
    30    *foo = 0;
    31  }
    32  
    33  int GetPcFromUcontext(ucontext_t* uc, uintptr_t* pc) {
    34  #if defined(__x86_64__)
    35    *pc = uc->uc_mcontext.gregs[REG_RIP];
    36    return 1;
    37  #elif defined(__i386__)
    38    *pc = uc->uc_mcontext.gregs[REG_EIP];
    39    return 1;
    40  #elif defined(__aarch64__)
    41    *pc = uc->uc_mcontext.pc;
    42    return 1;
    43  #else
    44    return 0;
    45  #endif
    46  }
    47  
    48  void sigact_handler(int sig, siginfo_t* siginfo, void* context) {
    49    uintptr_t pc;
    50    if (GetPcFromUcontext(reinterpret_cast<ucontext_t*>(context), &pc)) {
    51      /* Expect Fault() to be at most 64 bytes in size. */
    52      uintptr_t fault_addr = reinterpret_cast<uintptr_t>(&Fault);
    53      EXPECT_GE(pc, fault_addr);
    54      EXPECT_LT(pc, fault_addr + 64);
    55  
    56      // The following file is used to detect tests that exit prematurely. Since
    57      // we need to call exit() here, delete the file by hand.
    58      const char* exit_file = getenv("TEST_PREMATURE_EXIT_FILE");
    59      if (exit_file != nullptr) {
    60        ASSERT_THAT(unlink(exit_file), SyscallSucceeds());
    61      }
    62      exit(0);
    63    }
    64  }
    65  
    66  TEST(FaultTest, InRange) {
    67    // Reset the signal handler to do nothing so that it doesn't freak out
    68    // the test runner when we fire an alarm.
    69    struct sigaction sa = {};
    70    sa.sa_sigaction = sigact_handler;
    71    sigfillset(&sa.sa_mask);
    72    sa.sa_flags = SA_SIGINFO;
    73    ASSERT_THAT(sigaction(SIGSEGV, &sa, nullptr), SyscallSucceeds());
    74  
    75    Fault();
    76  }
    77  
    78  }  // namespace
    79  
    80  }  // namespace testing
    81  }  // namespace gvisor