Home | History | Annotate | Download | only in linux
      1 #define _GNU_SOURCE
      2 
      3 #include <stdio.h>
      4 
      5 #include "tests/sys_mman.h"
      6 #include <assert.h>
      7 #include <stdlib.h>
      8 #include <sys/types.h>
      9 #include <unistd.h>
     10 #include <errno.h>
     11 #include <syscall.h>
     12 
     13 
     14 #ifndef REMAP_FIXED
     15 #define MREMAP_FIXED 2
     16 #endif
     17 
     18 
     19 static int PAGE;
     20 
     21 void mapanon_fixed ( void* start, size_t length )
     22 {
     23   void* r = mmap(start, length, PROT_NONE,
     24                  MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0,0);
     25   assert(r != MAP_FAILED);
     26   assert(r == start);
     27 }
     28 
     29 void unmap_and_check ( void* start, size_t length )
     30 {
     31    int r = munmap( start, length );
     32    assert(r == 0);
     33 }
     34 
     35 char* workingarea = NULL;
     36 char* try_dst     = NULL;
     37 
     38 // set up working area so expansion limit is 20*PAGE
     39 //
     40 //   |   10   |   20   |   10   |   60   |
     41 //   |  pre   |  src   |  FREE  |  post  |
     42 //
     43 //  A suitable attempted fixed dst is workingarea + 150*PAGE.
     44 
     45 char* setup ( void* other_stuff, int other_len )
     46 {
     47   if (!workingarea) {
     48      workingarea = mmap(0, 200*PAGE, PROT_NONE,
     49                            MAP_ANONYMOUS|MAP_PRIVATE, 0,0);
     50      assert(workingarea);
     51      try_dst = workingarea + 150*PAGE;
     52      unmap_and_check(workingarea, 200*PAGE);
     53   }
     54 
     55   if (other_stuff) {
     56     unmap_and_check(other_stuff, other_len);
     57   }
     58 
     59   // get rid of the old working area
     60   unmap_and_check( workingarea, 200*PAGE);
     61 
     62   // pre block
     63   mapanon_fixed( workingarea + 0*PAGE, 9*PAGE);
     64 
     65   // the area
     66   mapanon_fixed( workingarea + 10*PAGE, 20*PAGE );
     67 
     68   // upper half
     69   mapanon_fixed( workingarea + 40*PAGE, 60*PAGE );
     70 
     71   return workingarea + 10*PAGE;
     72 }
     73 
     74 /* show the working area */
     75 void show ( void )
     76 {
     77   int i,r __attribute__((unused));
     78   for (i = 0; i < 200; i++) {
     79     r = mprotect( workingarea + i * PAGE, PAGE, PROT_NONE );
     80     // We used to print 'X' or '.' according to the mprotect result, but the
     81     // results are too variable and the test was never reliable.  So now we
     82     // just always print '.'.  At least this test gives mremap a thorough
     83     // working out and so will detect egregious problems like crashes.
     84     //printf("%c", r == 0 ? 'X' : '.');
     85     printf(".");
     86     if (i == 49 || i == 99 || i == 149) printf("\n");
     87   }
     88   printf("\n");
     89 }
     90 
     91 
     92 char* dst = NULL;
     93 char* src = NULL;
     94 char* dst_impossible = NULL;
     95 
     96 
     97 char* identify ( char* p )
     98 {
     99   if (p == dst)            return "dst";
    100   if (p == src)            return "src";
    101   if (p == dst_impossible) return "dst_imp!";
    102   if (p == try_dst)        return "dst_poss";
    103   return "other";
    104 }
    105 
    106 int main ( void )
    107 {
    108   int alocal, maymove, fixed, nsi, dstpossible;
    109   int newsizes[6] = { 19, 20, 21, 29, 30, 31 };
    110 
    111   char* tidythis = NULL;
    112   int  tidylen = 0;
    113   int firsttime = 1;
    114   char buf[100];
    115 
    116   dst_impossible = (char*)(&alocal) + 500 * 1000 * 1000;
    117 
    118   PAGE = sysconf(_SC_PAGESIZE);
    119 
    120   for (maymove = 0; maymove <= 1 ; maymove++) {
    121   for (fixed = 0; fixed <= 1; fixed++) {
    122     printf("\n");
    123   for (nsi = 0; nsi < 6; nsi++) {
    124   for (dstpossible = 0; dstpossible <= 1; dstpossible++) {
    125 
    126     char* r;
    127     int newsize = newsizes[nsi] * PAGE;
    128     int flags = (maymove ? MREMAP_MAYMOVE : 0)  |
    129                 (fixed ? MREMAP_FIXED : 0);
    130     dst = dstpossible ? try_dst : dst_impossible;
    131     src = setup( tidythis, tidylen );
    132 
    133     if (firsttime) {
    134        printf("dst_possible   = %p\n", try_dst );
    135        printf("dst_impossible = %p\n", dst_impossible );
    136        printf("           src = %p\n", src);
    137        printf("\n");
    138        sprintf(buf, "cat /proc/%d/maps", getpid());
    139        if (0) system(buf);
    140        firsttime = 0;
    141     }
    142 
    143     printf("maymv %d   fixed %d   newsz %2d   dstpo %d  dst %p ->  ",
    144 	   maymove, fixed, newsizes[nsi], dstpossible, dst );
    145     r = (char*)
    146         syscall(__NR_mremap, src, 20*PAGE, newsize, flags, dst, 0 );
    147     // We used to print the address or error, but that was also unreliable.
    148     //if (r == MAP_FAILED)
    149     //  printf("error %d\n", errno);
    150     //else
    151     //  printf("%p (== %s)\n", r, identify(r));
    152     printf("\n");
    153 
    154     if (1) {
    155        show();
    156        printf("\n");
    157     }
    158 
    159     if (r != MAP_FAILED) {
    160       if (r != src && r != try_dst && r != dst_impossible) {
    161 	tidythis = r;
    162 	tidylen = newsize;
    163       }
    164     }
    165 
    166   }
    167   }
    168   }
    169   }
    170   return 0;
    171 }
    172