** Tags added: kernel-daily-bug

-- 
You received this bug notification because you are a member of Kernel
Packages, which is subscribed to linux in Ubuntu.
https://bugs.launchpad.net/bugs/2034607

Title:
  Bus error after reading or writing a specific number of unique
  locations from/to a shared memory pool.

Status in linux package in Ubuntu:
  Confirmed

Bug description:
  A Bus error always occurs after reading or writing a specific number
  of unique locations from/to a shared memory pool which is created
  using shm_open() and mmap(). It does not matter if the pool memory
  locations are accessed starting at the base of the pool, incrementing
  up through the addresses, or starting at the top of the pool,
  decrementing down through the addresses. The count of unique locations
  accessed before the Bus error occurs is the same repeatable value. The
  count value is close to but not exactly 1/2 of the total system
  memory.

  The count is of unique locations accessed. If an address range less
  than the failure count is accessed repeatedly, the Bus error does not
  occur.

  The unique addresses do not have to be accessed sequentially to cause
  the Bus error. While this aspect has not been tested exhaustively, if
  a range of addresses are jumped over, the Bus error still occurs. Note
  that the failure count is slightly different than if the addresses are
  accessed sequentially.

  This error is consistently repeatable on the following 3 systems:
  Ubuntu 22.04.3 LTS
  gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
  Machine: Amazon EC2
  CPU: AMD EPYC 7571
  Memory: 124.68 GiB

  Distro: Linux Mint 20  base: Ubuntu 20.04
  gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04)
  Machine: Dell System XPS L502X
  CPU: Intel Core i7-2620M
  Total Memory: 8,219,435,008 bytes

  Distro: Linux Mint 21 base: Ubuntu 22.04
  gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
  Machine: Dell Inspiron 5558
  CPU: Intel Core i3-5005U
  Total Memory: 8,229,298,176 bytes

  C++ Test program that demonstrates the issue.
  ---------------------------------------------
  // September 2023 - Gene Weber

  // This test program generates a Bus error core dump after reading or writing 
a specific number
  // of unique locations from/to a shared memory pool. It does not matter if 
the pool memory locations
  // are accessed starting at the base of the pool, incrementing up through the 
addresses, or starting
  // at the top of the pool, decrementing down through the addresses. The count 
of unique locations
  // accessed before the Bus error occurs is the same repeatable value. The 
count value is close to
  // but not exactly 1/2 of the total system memory.
  //
  // The count is of unique locations accessed. If an address range less than 
the failure count is
  // accessed repeatedly, the Bus error does not occur.
  //
  // The unique addresses do not have to be accessed sequentially to cause the 
Bus error. While this
  // has not been tested exhaustively, if a range of addresses are jumped over, 
the Bus error still
  // occurs. Note that the failure count is slightly different than if the 
addresses are accessed
  // sequentially.
  //
  // This test program has command line options to allow testing these 
different scenarios.

  // Compiling with either has the same results:
  // g++ -std=c++11 test.cpp -W -Wall -Wextra -pedantic -pthread -o test -lrt
  // g++ -std=c++20 -O3 test.cpp -W -Wall -Wextra -pedantic -pthread -o test 
-lrt

  #include <iostream>
  #include <sys/mman.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <sys/types.h>
  #include <math.h>

  int main(int argc, char** argv) {
      int page_size = 4096;
      
      if (argc != 5) {
          std::cerr << "\nUsage: ./test <total_system_ram_in_bytes> <u/d> <r/w> 
<j/r/x> \n\n";
          std::cerr << "       <total_system_ram_in_bytes> = total from \"free 
-b\".\n";
          std::cerr << "       <u/d> = u to index addresses up from bottom of 
pool, d for down from top.\n";
          std::cerr << "       <r/w> = r to read indexed address, w for 
write.\n";
          std::cerr << "       <j/r/x> = j for jump index by 5% of total, r for 
limit index range to 1/2 of total, x linear indexing.\n\n";
          exit(EXIT_FAILURE);
      }

      uint_fast64_t total_system_ram = strtoull(argv[1], NULL, 10);

      // Set pool_size to a whole number of pages that is ~60% of system memory.
      uint_fast64_t pool_size = total_system_ram * 0.6;
      pool_size = pool_size - (pool_size % page_size);
      std::cout << "pool size = " << pool_size << "\n";

      // Create a mask to print status at intervals of ~1/20 of the pool size.
      uint_fast64_t print_interval = pow(2,ceil(log2(pool_size/20))) - 1;
      // Create a  value to start printing all addresses after a few pages less 
than
      // 1/2 of the pool size has been accessed.
        uint_fast64_t almost_half = (total_system_ram/2) - (3 * page_size);

      // Create a "jump address index" value to use if the jump option is 
selected.
      uint_fast64_t jmp_indx = total_system_ram * 0.05;
      if (*argv[4] == 'j') {
          std::cout << "jump address index by " << jmp_indx << "\n";
      }

      // Create an "address index range" value to use if range limit option is 
selected.
      uint_fast64_t indx_range = pool_size / 2;
      if (*argv[4] == 'r') {
          std::cout << "address index range will be limited to " << indx_range 
<< " locations.\n";
      }

      int fd;
      std::string shmpath = "/foo";

      // Remove any existing shared memory object
      shm_unlink(shmpath.c_str());
      // Create the shared memory object with read-write access.
      fd = shm_open(shmpath.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | 
S_IWUSR);
      
      if (fd == -1) {
          std::cerr << "\nshm_open shmbuf failure. Exiting program.\n\n";
          exit(EXIT_FAILURE);
      }
      
      // Truncate (set) the size.
      if (ftruncate64(fd, pool_size) == -1) {
          std::cerr << "\nftruncate shmbuf failure. Exiting program.\n\n";
          exit(EXIT_FAILURE);
      }
      
      // Map the shared memory object.
      char* pool = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE, 
MAP_SHARED, fd, 0);
      if (pool == MAP_FAILED) {
          std::cerr << "\nmmap pool failure. Exiting program.\n\n";
          exit(EXIT_FAILURE);
      }

      std::cout << "pool base address = " << (uint_fast64_t)pool << "\n";
      std::cout << "pool top address = " << (uint_fast64_t)pool + pool_size << 
"\n";

      char temp = 'a';
      uint_fast64_t indx = 0, prnt_num = 0;

      // Increment a count from 0 to pool_size-1. The count of locations 
accessed seems to be
      // the issue, not the location accessed.
      // Note: All of the control statements and logic in the loop impact the 
performance of
      // this test. This could be 12 unique test programs that run faster, but 
this seemed
      // like a better trade off.
      for (uint_fast64_t count=0; count<pool_size; count++) {

          // If argument 2 is "u" access locations from the bottom of the pool 
up, otherwise
          // access locations from the top of the pool down.
          indx = *argv[2] == 'u' ? count : (pool_size - 1) - count;
          // If argument 4 is "r", limit the address index to a range of 
indx_range locations.
          if (*argv[4] == 'r') {
              indx = *argv[2] == 'u' ? count % indx_range : (pool_size - 1) - 
(count % indx_range);
          }
          // If argument 4 is "j", and roughly 1/4 of the pool has been 
accessed, jump the
          // address index by the amount specified in jmp_indx.
          else if ((*argv[4] == 'j') && (prnt_num > 5)) {
              indx = *argv[2] == 'u' ? indx + jmp_indx : indx - jmp_indx;
          }

          // Print status at intervals using the mask created above.
          if ((count & print_interval) == print_interval) {
              std::cout << "count = " << count << "  Address = " << 
(uint_fast64_t)&pool[indx] << "\n";
              prnt_num++;
          }

          // When a few pages less than 1/2 of system memory has been accessed, 
print all.
          // Dissable if address index range is limited, because no failure 
will occur.
          else if ((count > almost_half) && (*argv[4] != 'r')) {
              std::cout << "count = " << count << "  Address = " << 
(uint_fast64_t)&pool[indx] << "\n";
            }

          // If argument 3 is "r" read the location, otherwise write the 
location.
          if (*argv[3] == 'r') {
              temp = pool[indx];
          }
          else {
              pool[indx] = temp;
          }
      }
      std::cout << "Success!\n";
  }

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2034607/+subscriptions


-- 
Mailing list: https://launchpad.net/~kernel-packages
Post to     : kernel-packages@lists.launchpad.net
Unsubscribe : https://launchpad.net/~kernel-packages
More help   : https://help.launchpad.net/ListHelp

Reply via email to