Edit

kc3-lang/freetype/src/base/ftsystem.c

Branch :

  • Show log

    Commit

  • Author : Tamir Duberstein
    Date : 2023-02-24 11:48:48
    Hash : 3f2ac7d8
    Message : * src/base/ftsystem.c (ft_ansi_stream_io): Avoid undefined behaviour. Also short-circuit on `offset` to avoid checking `count` a second time when `ft_ansi_stream_io` is used for reading. Per ISO/IEC 9899: If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or apointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined. If a function argument is described as being an array, the pointer actually passed to the function shall have a value such that all address computations and accesses to objects (that would be valid if the pointer did point to the first element of such an array) are in fact valid. Per IEEE Std 1003.1: size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); The `fread` function shall read into the array pointed to by `ptr` up to `nitems` elements whose size is specified by `size` in bytes, from the stream pointed to by `stream`. Since the first argument to `fread` is described as being an array, its behavior is undefined when that argument is a null pointer. Per the documentation on `ft_ansi_stream_io`: If `count' is zero (this is, the function is used for seeking), a non-zero return value indicates an error. Thus the intent is clear, and the call to `fread` can be skipped, avoiding undefined behaviour.

  • src/base/ftsystem.c
  • /****************************************************************************
     *
     * ftsystem.c
     *
     *   ANSI-specific FreeType low-level system interface (body).
     *
     * Copyright (C) 1996-2023 by
     * David Turner, Robert Wilhelm, and Werner Lemberg.
     *
     * This file is part of the FreeType project, and may only be used,
     * modified, and distributed under the terms of the FreeType project
     * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     * this file you indicate that you have read the license and
     * understand and accept it fully.
     *
     */
    
      /**************************************************************************
       *
       * This file contains the default interface used by FreeType to access
       * low-level, i.e. memory management, i/o access as well as thread
       * synchronisation.  It can be replaced by user-specific routines if
       * necessary.
       *
       */
    
    
    #include <ft2build.h>
    #include FT_CONFIG_CONFIG_H
    #include <freetype/internal/ftdebug.h>
    #include <freetype/internal/ftstream.h>
    #include <freetype/ftsystem.h>
    #include <freetype/fterrors.h>
    #include <freetype/fttypes.h>
    
    
      /**************************************************************************
       *
       *                      MEMORY MANAGEMENT INTERFACE
       *
       */
    
      /**************************************************************************
       *
       * It is not necessary to do any error checking for the
       * allocation-related functions.  This will be done by the higher level
       * routines like ft_mem_alloc() or ft_mem_realloc().
       *
       */
    
    
      /**************************************************************************
       *
       * @Function:
       *   ft_alloc
       *
       * @Description:
       *   The memory allocation function.
       *
       * @Input:
       *   memory ::
       *     A pointer to the memory object.
       *
       *   size ::
       *     The requested size in bytes.
       *
       * @Return:
       *   The address of newly allocated block.
       */
      FT_CALLBACK_DEF( void* )
      ft_alloc( FT_Memory  memory,
                long       size )
      {
        FT_UNUSED( memory );
    
        return ft_smalloc( (size_t)size );
      }
    
    
      /**************************************************************************
       *
       * @Function:
       *   ft_realloc
       *
       * @Description:
       *   The memory reallocation function.
       *
       * @Input:
       *   memory ::
       *     A pointer to the memory object.
       *
       *   cur_size ::
       *     The current size of the allocated memory block.
       *
       *   new_size ::
       *     The newly requested size in bytes.
       *
       *   block ::
       *     The current address of the block in memory.
       *
       * @Return:
       *   The address of the reallocated memory block.
       */
      FT_CALLBACK_DEF( void* )
      ft_realloc( FT_Memory  memory,
                  long       cur_size,
                  long       new_size,
                  void*      block )
      {
        FT_UNUSED( memory );
        FT_UNUSED( cur_size );
    
        return ft_srealloc( block, (size_t)new_size );
      }
    
    
      /**************************************************************************
       *
       * @Function:
       *   ft_free
       *
       * @Description:
       *   The memory release function.
       *
       * @Input:
       *   memory ::
       *     A pointer to the memory object.
       *
       *   block ::
       *     The address of block in memory to be freed.
       */
      FT_CALLBACK_DEF( void )
      ft_free( FT_Memory  memory,
               void*      block )
      {
        FT_UNUSED( memory );
    
        ft_sfree( block );
      }
    
    
      /**************************************************************************
       *
       *                    RESOURCE MANAGEMENT INTERFACE
       *
       */
    
    #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
    
      /**************************************************************************
       *
       * The macro FT_COMPONENT is used in trace mode.  It is an implicit
       * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
       * messages during execution.
       */
    #undef  FT_COMPONENT
    #define FT_COMPONENT  io
    
      /* We use the macro STREAM_FILE for convenience to extract the       */
      /* system-specific stream handle from a given FreeType stream object */
    #define STREAM_FILE( stream )  ( (FT_FILE*)stream->descriptor.pointer )
    
    
      /**************************************************************************
       *
       * @Function:
       *   ft_ansi_stream_close
       *
       * @Description:
       *   The function to close a stream.
       *
       * @Input:
       *   stream ::
       *     A pointer to the stream object.
       */
      FT_CALLBACK_DEF( void )
      ft_ansi_stream_close( FT_Stream  stream )
      {
        ft_fclose( STREAM_FILE( stream ) );
    
        stream->descriptor.pointer = NULL;
        stream->size               = 0;
        stream->base               = NULL;
      }
    
    
      /**************************************************************************
       *
       * @Function:
       *   ft_ansi_stream_io
       *
       * @Description:
       *   The function to open a stream.
       *
       * @Input:
       *   stream ::
       *     A pointer to the stream object.
       *
       *   offset ::
       *     The position in the data stream to start reading.
       *
       *   buffer ::
       *     The address of buffer to store the read data.
       *
       *   count ::
       *     The number of bytes to read from the stream.
       *
       * @Return:
       *   The number of bytes actually read.  If `count' is zero (this is,
       *   the function is used for seeking), a non-zero return value
       *   indicates an error.
       */
      FT_CALLBACK_DEF( unsigned long )
      ft_ansi_stream_io( FT_Stream       stream,
                         unsigned long   offset,
                         unsigned char*  buffer,
                         unsigned long   count )
      {
        FT_FILE*  file;
    
    
        if ( offset > stream->size && !count )
          return 1;
    
        file = STREAM_FILE( stream );
    
        if ( stream->pos != offset )
          ft_fseek( file, (long)offset, SEEK_SET );
    
        /* Avoid calling `fread` with `buffer=NULL` and `count=0`, */
        /* which is undefined behaviour.                           */
        if ( !count )
          return 0;
    
        return (unsigned long)ft_fread( buffer, 1, count, file );
      }
    
    
      /* documentation is in ftstream.h */
    
      FT_BASE_DEF( FT_Error )
      FT_Stream_Open( FT_Stream    stream,
                      const char*  filepathname )
      {
        FT_FILE*  file;
    
    
        if ( !stream )
          return FT_THROW( Invalid_Stream_Handle );
    
        stream->descriptor.pointer = NULL;
        stream->pathname.pointer   = (char*)filepathname;
        stream->base               = NULL;
        stream->pos                = 0;
        stream->read               = NULL;
        stream->close              = NULL;
    
        file = ft_fopen( filepathname, "rb" );
        if ( !file )
        {
          FT_ERROR(( "FT_Stream_Open:"
                     " could not open `%s'\n", filepathname ));
    
          return FT_THROW( Cannot_Open_Resource );
        }
    
        ft_fseek( file, 0, SEEK_END );
        stream->size = (unsigned long)ft_ftell( file );
        if ( !stream->size )
        {
          FT_ERROR(( "FT_Stream_Open:" ));
          FT_ERROR(( " opened `%s' but zero-sized\n", filepathname ));
          ft_fclose( file );
          return FT_THROW( Cannot_Open_Stream );
        }
        ft_fseek( file, 0, SEEK_SET );
    
        stream->descriptor.pointer = file;
        stream->read  = ft_ansi_stream_io;
        stream->close = ft_ansi_stream_close;
    
        FT_TRACE1(( "FT_Stream_Open:" ));
        FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n",
                    filepathname, stream->size ));
    
        return FT_Err_Ok;
      }
    
    #endif /* !FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */
    
    #ifdef FT_DEBUG_MEMORY
    
      extern FT_Int
      ft_mem_debug_init( FT_Memory  memory );
    
      extern void
      ft_mem_debug_done( FT_Memory  memory );
    
    #endif
    
    
      /* documentation is in ftobjs.h */
    
      FT_BASE_DEF( FT_Memory )
      FT_New_Memory( void )
      {
        FT_Memory  memory;
    
    
        memory = (FT_Memory)ft_smalloc( sizeof ( *memory ) );
        if ( memory )
        {
          memory->user    = NULL;
          memory->alloc   = ft_alloc;
          memory->realloc = ft_realloc;
          memory->free    = ft_free;
    #ifdef FT_DEBUG_MEMORY
          ft_mem_debug_init( memory );
    #endif
        }
    
        return memory;
      }
    
    
      /* documentation is in ftobjs.h */
    
      FT_BASE_DEF( void )
      FT_Done_Memory( FT_Memory  memory )
      {
    #ifdef FT_DEBUG_MEMORY
        ft_mem_debug_done( memory );
    #endif
        ft_sfree( memory );
      }
    
    
    /* END */