Commit message: None
CVE: CVE-2018-6942
CWE: CWE-476
Vulnerability description: An issue was discovered in FreeType 2 through 2.9. A NULL pointer dereference in the Ins_GETVARIATION() function within ttinterp.c could lead to DoS via a crafted font file.

Project: savannah

  Current_Ratio( TT_ExecContext  exc )
  {
    if ( !exc->tt_metrics.ratio )
    {
      if ( exc->GS.projVector.y == 0 )
        exc->tt_metrics.ratio = exc->tt_metrics.x_ratio;

      else if ( exc->GS.projVector.x == 0 )
        exc->tt_metrics.ratio = exc->tt_metrics.y_ratio;

      else
      {
        FT_F26Dot6  x, y;


        x = TT_MulFix14( exc->tt_metrics.x_ratio,
                         exc->GS.projVector.x );
        y = TT_MulFix14( exc->tt_metrics.y_ratio,
                         exc->GS.projVector.y );
        exc->tt_metrics.ratio = FT_Hypot( x, y );
      }
    }
    return exc->tt_metrics.ratio;
  }

Project: savannah

  Direct_Move_Orig( TT_ExecContext  exc,
                    TT_GlyphZone    zone,
                    FT_UShort       point,
                    FT_F26Dot6      distance )
  {
    FT_F26Dot6  v;


    v = exc->GS.freeVector.x;

    if ( v != 0 )
      zone->org[point].x = ADD_LONG( zone->org[point].x,
                                     FT_MulDiv( distance,
                                                v,
                                                exc->F_dot_P ) );

    v = exc->GS.freeVector.y;

    if ( v != 0 )
      zone->org[point].y = ADD_LONG( zone->org[point].y,
                                     FT_MulDiv( distance,
                                                v,
                                                exc->F_dot_P ) );
  }

Project: savannah

  Dual_Project( TT_ExecContext  exc,
                FT_Pos          dx,
                FT_Pos          dy )
  {
    return TT_DotFix14( dx, dy,
                        exc->GS.dualVector.x,
                        exc->GS.dualVector.y );
  }

Project: savannah

  Ins_CEILING( FT_Long*  args )
  {
    args[0] = FT_PIX_CEIL( args[0] );
  }

Project: savannah

  Ins_EVEN( TT_ExecContext  exc,
            FT_Long*        args )
  {
    args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 0 );
  }

Project: savannah

  Ins_FLIPRGON( TT_ExecContext  exc,
                FT_Long*        args )
  {
    FT_UShort  I, K, L;


#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    /* See `ttinterp.h' for details on backward compatibility mode. */
    if ( SUBPIXEL_HINTING_MINIMAL    &&
         exc->backward_compatibility &&
         exc->iupx_called            &&
         exc->iupy_called            )
      return;
#endif

    K = (FT_UShort)args[1];
    L = (FT_UShort)args[0];

    if ( BOUNDS( K, exc->pts.n_points ) ||
         BOUNDS( L, exc->pts.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    for ( I = L; I <= K; I++ )
      exc->pts.tags[I] |= FT_CURVE_TAG_ON;
  }

Project: savannah

  Ins_Goto_CodeRange( TT_ExecContext  exc,
                      FT_Int          aRange,
                      FT_Long         aIP )
  {
    TT_CodeRange*  range;


    if ( aRange < 1 || aRange > 3 )
    {
      exc->error = FT_THROW( Bad_Argument );
      return FAILURE;
    }

    range = &exc->codeRangeTable[aRange - 1];

    if ( !range->base )     /* invalid coderange */
    {
      exc->error = FT_THROW( Invalid_CodeRange );
      return FAILURE;
    }

    /* NOTE: Because the last instruction of a program may be a CALL */
    /*       which will return to the first byte *after* the code    */
    /*       range, we test for aIP <= Size, instead of aIP < Size.  */

    if ( aIP > range->size )
    {
      exc->error = FT_THROW( Code_Overflow );
      return FAILURE;
    }

    exc->code     = range->base;
    exc->codeSize = range->size;
    exc->IP       = aIP;
    exc->curRange = aRange;

    return SUCCESS;
  }

Project: savannah

  Ins_MPPEM( TT_ExecContext  exc,
             FT_Long*        args )
  {
    args[0] = exc->func_cur_ppem( exc );
  }

Project: savannah

  Ins_NOT( FT_Long*  args )
  {
    args[0] = !args[0];
  }

Project: savannah

  Ins_NPUSHB( TT_ExecContext  exc,
              FT_Long*        args )
  {
    FT_UShort  L, K;


    L = (FT_UShort)exc->code[exc->IP + 1];

    if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
    {
      exc->error = FT_THROW( Stack_Overflow );
      return;
    }

    for ( K = 1; K <= L; K++ )
      args[K - 1] = exc->code[exc->IP + K + 1];

    exc->new_top += L;
  }

Project: savannah

  Ins_OR( FT_Long*  args )
  {
    args[0] = ( args[0] || args[1] );
  }

Project: savannah

  Ins_ROFF( TT_ExecContext  exc )
  {
    exc->GS.round_state = TT_Round_Off;
    exc->func_round     = (TT_Round_Func)Round_None;
  }

Project: savannah

  Ins_SHZ( TT_ExecContext  exc,
           FT_Long*        args )
  {
    TT_GlyphZoneRec  zp;
    FT_UShort        refp;
    FT_F26Dot6       dx,
                     dy;

    FT_UShort        limit, i;


    if ( BOUNDS( args[0], 2 ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
      return;

    /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points.     */
    /*      Twilight zone has no real contours, so use `n_points'. */
    /*      Normal zone's `n_points' includes phantoms, so must    */
    /*      use end of last contour.                               */
    if ( exc->GS.gep2 == 0 )
      limit = (FT_UShort)exc->zp2.n_points;
    else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 )
      limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 );
    else
      limit = 0;

    /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
    for ( i = 0; i < limit; i++ )
    {
      if ( zp.cur != exc->zp2.cur || refp != i )
        Move_Zp2_Point( exc, i, dx, dy, FALSE );
    }
  }

Project: savannah

  Ins_UNKNOWN( TT_ExecContext  exc )
  {
    TT_DefRecord*  def   = exc->IDefs;
    TT_DefRecord*  limit = def + exc->numIDefs;


    for ( ; def < limit; def++ )
    {
      if ( (FT_Byte)def->opc == exc->opcode && def->active )
      {
        TT_CallRec*  call;


        if ( exc->callTop >= exc->callSize )
        {
          exc->error = FT_THROW( Stack_Overflow );
          return;
        }

        call = exc->callStack + exc->callTop++;

        call->Caller_Range = exc->curRange;
        call->Caller_IP    = exc->IP + 1;
        call->Cur_Count    = 1;
        call->Def          = def;

        Ins_Goto_CodeRange( exc, def->range, def->start );

        exc->step_ins = FALSE;
        return;
      }
    }

    exc->error = FT_THROW( Invalid_Opcode );
  }

Project: savannah

  Move_Zp2_Point( TT_ExecContext  exc,
                  FT_UShort       point,
                  FT_F26Dot6      dx,
                  FT_F26Dot6      dy,
                  FT_Bool         touch )
  {
    if ( exc->GS.freeVector.x != 0 )
    {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
      if ( !( SUBPIXEL_HINTING_MINIMAL    &&
              exc->backward_compatibility ) )
#endif
        exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx );

      if ( touch )
        exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
    }

    if ( exc->GS.freeVector.y != 0 )
    {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
      if ( !( SUBPIXEL_HINTING_MINIMAL    &&
              exc->backward_compatibility &&
              exc->iupx_called            &&
              exc->iupy_called            ) )
#endif
        exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy );

      if ( touch )
        exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
    }
  }

Project: savannah

  TT_Goto_CodeRange( TT_ExecContext  exec,
                     FT_Int          range,
                     FT_Long         IP )
  {
    TT_CodeRange*  coderange;


    FT_ASSERT( range >= 1 && range <= 3 );

    coderange = &exec->codeRangeTable[range - 1];

    FT_ASSERT( coderange->base );

    /* NOTE: Because the last instruction of a program may be a CALL */
    /*       which will return to the first byte *after* the code    */
    /*       range, we test for IP <= Size instead of IP < Size.     */
    /*                                                               */
    FT_ASSERT( IP <= coderange->size );

    exec->code     = coderange->base;
    exec->codeSize = coderange->size;
    exec->IP       = IP;
    exec->curRange = range;
  }