title: Is the "mmap tutorial" incorrect, or does GCC miscompile it?
body: <p>This <a href="https://www.linuxquestions.org/questions/programming-9/mmap-tutorial-c-c-511265/#post2549203" rel="nofollow noreferrer">mmap tutorial</a> from 15 years ago ranks high in Google searches, but it actually runs subtly incorrectly on my Linux system.</p>
  <p><code>mmap_write.c</code>:</p>
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;sys/mman.h&gt;
  
  #define FILEPATH &quot;/tmp/mmapped.bin&quot;
  #define NUMINTS  (1000)
  #define FILESIZE (NUMINTS * sizeof(int))
  
  int main(int argc, char *argv[])
  {
      int i;
      int fd;
      int result;
      int *map;  /* mmapped array of int's */
  
      /* Open a file for writing.
       *  - Creating the file if it doesn't exist.
       *  - Truncating it to 0 size if it already exists. (not really needed)
       *
       * Note: &quot;O_WRONLY&quot; mode is not sufficient when mmaping.
       */
      fd = open(FILEPATH, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
      if (fd == -1) {
      perror(&quot;Error opening file for writing&quot;);
      exit(EXIT_FAILURE);
      }
  
      /* Stretch the file size to the size of the (mmapped) array of ints
       */
      result = lseek(fd, FILESIZE-1, SEEK_SET);
      if (result == -1) {
      close(fd);
      perror(&quot;Error calling lseek() to 'stretch' the file&quot;);
      exit(EXIT_FAILURE);
      }
      
      /* Something needs to be written at the end of the file to
       * have the file actually have the new size.
       * Just writing an empty string at the current file position will do.
       *
       * Note:
       *  - The current position in the file is at the end of the stretched 
       *    file due to the call to lseek().
       *  - An empty string is actually a single '\0' character, so a zero-byte
       *    will be written at the last byte of the file.
       */
      result = write(fd, &quot;&quot;, 1);
      if (result != 1) {
      close(fd);
      perror(&quot;Error writing last byte of the file&quot;);
      exit(EXIT_FAILURE);
      }
  
      /* Now the file is ready to be mmapped.
       */
      map = mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if (map == MAP_FAILED) {
      close(fd);
      perror(&quot;Error mmapping the file&quot;);
      exit(EXIT_FAILURE);
      }
      
      /* Now write int's to the file as if it were memory (an array of ints).
       */
      for (i = 1; i &lt;=NUMINTS; ++i) {
      map[i] = 2 * i; 
      }
  
      /* Don't forget to free the mmapped memory
       */
      if (munmap(map, FILESIZE) == -1) {
      perror(&quot;Error un-mmapping the file&quot;);
      /* Decide here whether to close(fd) and exit() or not. Depends... */
      }
  
      /* Un-mmaping doesn't close the file, so we still need to do that.
       */
      close(fd);
      return 0;
  }
  </code></pre>
  <p><code>mmap_read.c</code>:</p>
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;sys/mman.h&gt;
  
  #define FILEPATH &quot;/tmp/mmapped.bin&quot;
  #define NUMINTS  (1000)
  #define FILESIZE (NUMINTS * sizeof(int))
  
  int main(int argc, char *argv[])
  {
      int i;
      int fd;
      int *map;  /* mmapped array of int's */
  
      fd = open(FILEPATH, O_RDONLY);
      if (fd == -1) {
      perror(&quot;Error opening file for reading&quot;);
      exit(EXIT_FAILURE);
      }
  
      map = mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fd, 0);
      if (map == MAP_FAILED) {
      close(fd);
      perror(&quot;Error mmapping the file&quot;);
      exit(EXIT_FAILURE);
      }
      
      /* Read the file int-by-int from the mmap
       */
      for (i = 1; i &lt;=NUMINTS; ++i) {
      printf(&quot;%d: %d\n&quot;, i, map[i]);
      }
  
      if (munmap(map, FILESIZE) == -1) {
      perror(&quot;Error un-mmapping the file&quot;);
      }
      close(fd);
      return 0;
  }
  </code></pre>
  <p>If the file does not already exist, the output of <code>mmap_read</code> is</p>
  <pre><code>...
  998: 1996
  999: 1998
  1000: 2000
  </code></pre>
  <p>But if it does, the output is</p>
  <pre><code>...
  998: 1996
  999: 1998
  1000: 0
  </code></pre>
  <p>Should the author have flushed the <code>write</code>? Or is GCC miscompiling the code?</p>
  <hr />
  <p><em>Edit:</em> I noticed that it's the prior existence or non-existence of the file that makes a difference, not the compilation flag.</p>