  cff_decoder_parse_charstrings( CFF_Decoder*  decoder,
                                 FT_Byte*      charstring_base,
                                 FT_ULong      charstring_len )
  {
    FT_Error           error;
    CFF_Decoder_Zone*  zone;
    FT_Byte*           ip;
    FT_Byte*           limit;
    CFF_Builder*       builder = &decoder->builder;
    FT_Pos             x, y;
    FT_Fixed           seed;
    FT_Fixed*          stack;
    FT_Int             charstring_type =
                         decoder->cff->top_font.font_dict.charstring_type;

    T2_Hints_Funcs     hinter;

    /* set default width */
    decoder->num_hints  = 0;
    decoder->read_width = 1;

    /* compute random seed from stack address of parameter */
    seed = (FT_Fixed)( ( (FT_PtrDist)(char*)&seed              ^
                         (FT_PtrDist)(char*)&decoder           ^
                         (FT_PtrDist)(char*)&charstring_base ) &
                         FT_ULONG_MAX ) ;
    seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL;
    if ( seed == 0 )
      seed = 0x7384;

    /* initialize the decoder */
    decoder->top  = decoder->stack;
    decoder->zone = decoder->zones;
    zone          = decoder->zones;
    stack         = decoder->top;

    hinter = (T2_Hints_Funcs)builder->hints_funcs;

    builder->path_begun = 0;

    zone->base           = charstring_base;
    limit = zone->limit  = charstring_base + charstring_len;
    ip    = zone->cursor = zone->base;

    error = CFF_Err_Ok;

    x = builder->pos_x;
    y = builder->pos_y;

    /* begin hints recording session, if any */
    if ( hinter )
      hinter->open( hinter->hints );

    /* now execute loop */
    while ( ip < limit )
    {
      CFF_Operator  op;
      FT_Byte       v;

      /********************************************************************/
      /*                                                                  */
      /* Decode operator or operand                                       */
      /*                                                                  */
      v = *ip++;
      if ( v >= 32 || v == 28 )
      {
        FT_Int    shift = 16;
        FT_Int32  val;

        /* this is an operand, push it on the stack */
        if ( v == 28 )
        {
          if ( ip + 1 >= limit )
            goto Syntax_Error;
          val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
          ip += 2;
        }
        else if ( v < 247 )
          val = (FT_Int32)v - 139;
        else if ( v < 251 )
        {
          if ( ip >= limit )
            goto Syntax_Error;
          val = ( (FT_Int32)v - 247 ) * 256 + *ip++ + 108;
        }
        else if ( v < 255 )
        {
          if ( ip >= limit )
            goto Syntax_Error;
          val = -( (FT_Int32)v - 251 ) * 256 - *ip++ - 108;
        }
        else
        {
          if ( ip + 3 >= limit )
            goto Syntax_Error;
          val = ( (FT_Int32)ip[0] << 24 ) |
                ( (FT_Int32)ip[1] << 16 ) |
                ( (FT_Int32)ip[2] <<  8 ) |
                            ip[3];
          ip    += 4;
          if ( charstring_type == 2 )
            shift = 0;
        }
        if ( decoder->top - stack >= CFF_MAX_OPERANDS )
          goto Stack_Overflow;

        val           <<= shift;
        *decoder->top++ = val;

#ifdef FT_DEBUG_LEVEL_TRACE
        if ( !( val & 0xFFFFL ) )
          FT_TRACE4(( " %ld", (FT_Int32)( val >> 16 ) ));
        else
          FT_TRACE4(( " %.2f", val / 65536.0 ));
#endif

      }
      else
      {
        /* The specification says that normally arguments are to be taken */
        /* from the bottom of the stack.  However, this seems not to be   */
        /* correct, at least for Acroread 7.0.8 on GNU/Linux: It pops the */
        /* arguments similar to a PS interpreter.                         */

        FT_Fixed*  args     = decoder->top;
        FT_Int     num_args = (FT_Int)( args - decoder->stack );
        FT_Int     req_args;

        /* find operator */
        op = cff_op_unknown;

        switch ( v )
        {
        case 1:
          op = cff_op_hstem;
          break;
        case 3:
          op = cff_op_vstem;
          break;
        case 4:
          op = cff_op_vmoveto;
          break;
        case 5:
          op = cff_op_rlineto;
          break;
        case 6:
          op = cff_op_hlineto;
          break;
        case 7:
          op = cff_op_vlineto;
          break;
        case 8:
          op = cff_op_rrcurveto;
          break;
        case 9:
          op = cff_op_closepath;
          break;
        case 10:
          op = cff_op_callsubr;
          break;
        case 11:
          op = cff_op_return;
          break;
        case 12:
          {
            if ( ip >= limit )
              goto Syntax_Error;
            v = *ip++;

            switch ( v )
            {
            case 0:
              op = cff_op_dotsection;
              break;
            case 1: /* this is actually the Type1 vstem3 operator */
              op = cff_op_vstem;
              break;
            case 2: /* this is actually the Type1 hstem3 operator */
              op = cff_op_hstem;
              break;
            case 3:
              op = cff_op_and;
              break;
            case 4:
              op = cff_op_or;
              break;
            case 5:
              op = cff_op_not;
              break;
            case 6:
              op = cff_op_seac;
              break;
            case 7:
              op = cff_op_sbw;
              break;
            case 8:
              op = cff_op_store;
              break;
            case 9:
              op = cff_op_abs;
              break;
            case 10:
              op = cff_op_add;
              break;
            case 11:
              op = cff_op_sub;
              break;
            case 12:
              op = cff_op_div;
              break;
            case 13:
              op = cff_op_load;
              break;
            case 14:
              op = cff_op_neg;
              break;
            case 15:
              op = cff_op_eq;
              break;
            case 16:
              op = cff_op_callothersubr;
              break;
            case 17:
              op = cff_op_pop;
              break;
            case 18:
              op = cff_op_drop;
              break;
            case 20:
              op = cff_op_put;
              break;
            case 21:
              op = cff_op_get;
              break;
            case 22:
              op = cff_op_ifelse;
              break;
            case 23:
              op = cff_op_random;
              break;
            case 24:
              op = cff_op_mul;
              break;
            case 26:
              op = cff_op_sqrt;
              break;
            case 27:
              op = cff_op_dup;
              break;
            case 28:
              op = cff_op_exch;
              break;
            case 29:
              op = cff_op_index;
              break;
            case 30:
              op = cff_op_roll;
              break;
            case 33:
              op = cff_op_setcurrentpoint;
              break;
            case 34:
              op = cff_op_hflex;
              break;
            case 35:
              op = cff_op_flex;
              break;
            case 36:
              op = cff_op_hflex1;
              break;
            case 37:
              op = cff_op_flex1;
              break;
            default:
              /* decrement ip for syntax error message */
              ip--;
            }
          }
          break;
        case 13:
          op = cff_op_hsbw;
          break;
        case 14:
          op = cff_op_endchar;
          break;
        case 16:
          op = cff_op_blend;
          break;
        case 18:
          op = cff_op_hstemhm;
          break;
        case 19:
          op = cff_op_hintmask;
          break;
        case 20:
          op = cff_op_cntrmask;
          break;
        case 21:
          op = cff_op_rmoveto;
          break;
        case 22:
          op = cff_op_hmoveto;
          break;
        case 23:
          op = cff_op_vstemhm;
          break;
        case 24:
          op = cff_op_rcurveline;
          break;
        case 25:
          op = cff_op_rlinecurve;
          break;
        case 26:
          op = cff_op_vvcurveto;
          break;
        case 27:
          op = cff_op_hhcurveto;
          break;
        case 29:
          op = cff_op_callgsubr;
          break;
        case 30:
          op = cff_op_vhcurveto;
          break;
        case 31:
          op = cff_op_hvcurveto;
          break;
        default:
          break;
        }

        if ( op == cff_op_unknown )
          goto Syntax_Error;

        /* check arguments */
        req_args = cff_argument_counts[op];
        if ( req_args & CFF_COUNT_CHECK_WIDTH )
        {
          if ( num_args > 0 && decoder->read_width )
          {
            /* If `nominal_width' is non-zero, the number is really a      */
            /* difference against `nominal_width'.  Else, the number here  */
            /* is truly a width, not a difference against `nominal_width'. */
            /* If the font does not set `nominal_width', then              */
            /* `nominal_width' defaults to zero, and so we can set         */
            /* `glyph_width' to `nominal_width' plus number on the stack   */
            /* -- for either case.                                         */

            FT_Int  set_width_ok;

            switch ( op )
            {
            case cff_op_hmoveto:
            case cff_op_vmoveto:
              set_width_ok = num_args & 2;
              break;

            case cff_op_hstem:
            case cff_op_vstem:
            case cff_op_hstemhm:
            case cff_op_vstemhm:
            case cff_op_rmoveto:
            case cff_op_hintmask:
            case cff_op_cntrmask:
              set_width_ok = num_args & 1;
              break;

            case cff_op_endchar:
              /* If there is a width specified for endchar, we either have */
              /* 1 argument or 5 arguments.  We like to argue.             */
              set_width_ok = ( num_args == 5 ) || ( num_args == 1 );
              break;

            default:
              set_width_ok = 0;
              break;
            }

            if ( set_width_ok )
            {
              decoder->glyph_width = decoder->nominal_width +
                                       ( stack[0] >> 16 );

              if ( decoder->width_only )
              {
                /* we only want the advance width; stop here */
                break;
              }

              /* Consumed an argument. */
              num_args--;
            }
          }

          decoder->read_width = 0;
          req_args            = 0;
        }

        req_args &= 0x000F;
        if ( num_args < req_args )
          goto Stack_Underflow;
        args     -= req_args;
        num_args -= req_args;

        /* At this point, `args' points to the first argument of the  */
        /* operand in case `req_args' isn't zero.  Otherwise, we have */
        /* to adjust `args' manually.                                 */

        /* Note that we only pop arguments from the stack which we    */
        /* really need and can digest so that we can continue in case */
        /* of superfluous stack elements.                             */

        switch ( op )
        {
        case cff_op_hstem:
        case cff_op_vstem:
        case cff_op_hstemhm:
        case cff_op_vstemhm:
          /* the number of arguments is always even here */
          FT_TRACE4((
              op == cff_op_hstem   ? " hstem\n"   :
            ( op == cff_op_vstem   ? " vstem\n"   :
            ( op == cff_op_hstemhm ? " hstemhm\n" : " vstemhm\n" ) ) ));

          if ( hinter )
            hinter->stems( hinter->hints,
                           ( op == cff_op_hstem || op == cff_op_hstemhm ),
                           num_args / 2,
                           args - ( num_args & ~1 ) );

          decoder->num_hints += num_args / 2;
          args = stack;
          break;

        case cff_op_hintmask:
        case cff_op_cntrmask:
          FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));

          /* implement vstem when needed --                        */
          /* the specification doesn't say it, but this also works */
          /* with the 'cntrmask' operator                          */
          /*                                                       */
          if ( num_args > 0 )
          {
            if ( hinter )
              hinter->stems( hinter->hints,
                             0,
                             num_args / 2,
                             args - ( num_args & ~1 ) );

            decoder->num_hints += num_args / 2;
          }

          if ( hinter )
          {
            if ( op == cff_op_hintmask )
              hinter->hintmask( hinter->hints,
                                builder->current->n_points,
                                decoder->num_hints,
                                ip );
            else
              hinter->counter( hinter->hints,
                               decoder->num_hints,
                               ip );
          }

#ifdef FT_DEBUG_LEVEL_TRACE
          {
            FT_UInt maskbyte;

            FT_TRACE4(( " (maskbytes: " ));

            for ( maskbyte = 0;
                  maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
                  maskbyte++, ip++ )
              FT_TRACE4(( "0x%02X", *ip ));

            FT_TRACE4(( ")\n" ));
          }
#else
          ip += ( decoder->num_hints + 7 ) >> 3;
#endif
          if ( ip >= limit )
            goto Syntax_Error;
          args = stack;
          break;

        case cff_op_rmoveto:
          FT_TRACE4(( " rmoveto\n" ));

          cff_builder_close_contour( builder );
          builder->path_begun = 0;
          x   += args[-2];
          y   += args[-1];
          args = stack;
          break;

        case cff_op_vmoveto:
          FT_TRACE4(( " vmoveto\n" ));

          cff_builder_close_contour( builder );
          builder->path_begun = 0;
          y   += args[-1];
          args = stack;
          break;

        case cff_op_hmoveto:
          FT_TRACE4(( " hmoveto\n" ));

          cff_builder_close_contour( builder );
          builder->path_begun = 0;
          x   += args[-1];
          args = stack;
          break;

        case cff_op_rlineto:
          FT_TRACE4(( " rlineto\n" ));

          if ( cff_builder_start_point ( builder, x, y ) ||
               check_points( builder, num_args / 2 )     )
            goto Fail;

          if ( num_args < 2 )
            goto Stack_Underflow;

          args -= num_args & ~1;
          while ( args < decoder->top )
          {
            x += args[0];
            y += args[1];
            cff_builder_add_point( builder, x, y, 1 );
            args += 2;
          }
          args = stack;
          break;

        case cff_op_hlineto:
        case cff_op_vlineto:
          {
            FT_Int  phase = ( op == cff_op_hlineto );

            FT_TRACE4(( op == cff_op_hlineto ? " hlineto\n"
                                             : " vlineto\n" ));

            if ( num_args < 1 )
              goto Stack_Underflow;

            if ( cff_builder_start_point ( builder, x, y ) ||
                 check_points( builder, num_args )         )
              goto Fail;

            args = stack;
            while ( args < decoder->top )
            {
              if ( phase )
                x += args[0];
              else
                y += args[0];

              if ( cff_builder_add_point1( builder, x, y ) )
                goto Fail;

              args++;
              phase ^= 1;
            }
            args = stack;
          }
          break;

        case cff_op_rrcurveto:
          {
            FT_Int  nargs;

            FT_TRACE4(( " rrcurveto\n" ));

            if ( num_args < 6 )
              goto Stack_Underflow;

            nargs = num_args - num_args % 6;

            if ( cff_builder_start_point ( builder, x, y ) ||
                 check_points( builder, nargs / 2 )     )
              goto Fail;

            args -= nargs;
            while ( args < decoder->top )
            {
              x += args[0];
              y += args[1];
              cff_builder_add_point( builder, x, y, 0 );
              x += args[2];
              y += args[3];
              cff_builder_add_point( builder, x, y, 0 );
              x += args[4];
              y += args[5];
              cff_builder_add_point( builder, x, y, 1 );
              args += 6;
            }
            args = stack;
          }
          break;

        case cff_op_vvcurveto:
          {
            FT_Int  nargs;

            FT_TRACE4(( " vvcurveto\n" ));

            if ( num_args < 4 )
              goto Stack_Underflow;

            /* if num_args isn't of the form 4n or 4n+1, */
            /* we reduce it to 4n+1                      */

            nargs = num_args - num_args % 4;
            if ( num_args - nargs > 0 )
              nargs += 1;

            if ( cff_builder_start_point( builder, x, y ) )
              goto Fail;

            args -= nargs;

            if ( nargs & 1 )
            {
              x += args[0];
              args++;
              nargs--;
            }

            if ( check_points( builder, 3 * ( nargs / 4 ) ) )
              goto Fail;

            while ( args < decoder->top )
            {
              y += args[0];
              cff_builder_add_point( builder, x, y, 0 );
              x += args[1];
              y += args[2];
              cff_builder_add_point( builder, x, y, 0 );
              y += args[3];
              cff_builder_add_point( builder, x, y, 1 );
              args += 4;
            }
            args = stack;
          }
          break;

        case cff_op_hhcurveto:
          {
            FT_Int  nargs;

            FT_TRACE4(( " hhcurveto\n" ));

            if ( num_args < 4 )
              goto Stack_Underflow;

            /* if num_args isn't of the form 4n or 4n+1, */
            /* we reduce it to 4n+1                      */

            nargs = num_args - num_args % 4;
            if ( num_args - nargs > 0 )
              nargs += 1;

            if ( cff_builder_start_point( builder, x, y ) )
              goto Fail;

            args -= nargs;
            if ( nargs & 1 )
            {
              y += args[0];
              args++;
              nargs--;
            }

            if ( check_points( builder, 3 * ( nargs / 4 ) ) )
              goto Fail;

            while ( args < decoder->top )
            {
              x += args[0];
              cff_builder_add_point( builder, x, y, 0 );
              x += args[1];
              y += args[2];
              cff_builder_add_point( builder, x, y, 0 );
              x += args[3];
              cff_builder_add_point( builder, x, y, 1 );
              args += 4;
            }
            args = stack;
          }
          break;

        case cff_op_vhcurveto:
        case cff_op_hvcurveto:
          {
            FT_Int  phase;
            FT_Int  nargs;

            FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto\n"
                                               : " hvcurveto\n" ));

            if ( cff_builder_start_point( builder, x, y ) )
              goto Fail;

            if ( num_args < 4 )
              goto Stack_Underflow;

            /* if num_args isn't of the form 8n, 8n+1, 8n+4, or 8n+5, */
            /* we reduce it to the largest one which fits             */

            nargs = num_args - num_args % 4;
            if ( num_args - nargs > 0 )
              nargs += 1;

            args -= nargs;
            if ( check_points( builder, ( nargs / 4 ) * 3 ) )
              goto Stack_Underflow;

            phase = ( op == cff_op_hvcurveto );

            while ( nargs >= 4 )
            {
              nargs -= 4;
              if ( phase )
              {
                x += args[0];
                cff_builder_add_point( builder, x, y, 0 );
                x += args[1];
                y += args[2];
                cff_builder_add_point( builder, x, y, 0 );
                y += args[3];
                if ( nargs == 1 )
                  x += args[4];
                cff_builder_add_point( builder, x, y, 1 );
              }
              else
              {
                y += args[0];
                cff_builder_add_point( builder, x, y, 0 );
                x += args[1];
                y += args[2];
                cff_builder_add_point( builder, x, y, 0 );
                x += args[3];
                if ( nargs == 1 )
                  y += args[4];
                cff_builder_add_point( builder, x, y, 1 );
              }
              args  += 4;
              phase ^= 1;
            }
            args = stack;
          }
          break;

        case cff_op_rlinecurve:
          {
            FT_Int  num_lines;
            FT_Int  nargs;

            FT_TRACE4(( " rlinecurve\n" ));

            if ( num_args < 8 )
              goto Stack_Underflow;

            nargs     = num_args & ~1;
            num_lines = ( nargs - 6 ) / 2;

            if ( cff_builder_start_point( builder, x, y ) ||
                 check_points( builder, num_lines + 3 )   )
              goto Fail;

            args -= nargs;

            /* first, add the line segments */
            while ( num_lines > 0 )
            {
              x += args[0];
              y += args[1];
              cff_builder_add_point( builder, x, y, 1 );
              args += 2;
              num_lines--;
            }

            /* then the curve */
            x += args[0];
            y += args[1];
            cff_builder_add_point( builder, x, y, 0 );
            x += args[2];
            y += args[3];
            cff_builder_add_point( builder, x, y, 0 );
            x += args[4];
            y += args[5];
            cff_builder_add_point( builder, x, y, 1 );
            args = stack;
          }
          break;

        case cff_op_rcurveline:
          {
            FT_Int  num_curves;
            FT_Int  nargs;

            FT_TRACE4(( " rcurveline\n" ));

            if ( num_args < 8 )
              goto Stack_Underflow;

            nargs      = num_args - 2;
            nargs      = nargs - nargs % 6 + 2;
            num_curves = ( nargs - 2 ) / 6;

            if ( cff_builder_start_point ( builder, x, y ) ||
                 check_points( builder, num_curves * 3 + 2 ) )
              goto Fail;

            args -= nargs;

            /* first, add the curves */
            while ( num_curves > 0 )
            {
              x += args[0];
              y += args[1];
              cff_builder_add_point( builder, x, y, 0 );
              x += args[2];
              y += args[3];
              cff_builder_add_point( builder, x, y, 0 );
              x += args[4];
              y += args[5];
              cff_builder_add_point( builder, x, y, 1 );
              args += 6;
              num_curves--;
            }

            /* then the final line */
            x += args[0];
            y += args[1];
            cff_builder_add_point( builder, x, y, 1 );
            args = stack;
          }
          break;

        case cff_op_hflex1:
          {
            FT_Pos start_y;

            FT_TRACE4(( " hflex1\n" ));

            /* adding five more points: 4 control points, 1 on-curve point */
            /* -- make sure we have enough space for the start point if it */
            /* needs to be added                                           */
            if ( cff_builder_start_point( builder, x, y ) ||
                 check_points( builder, 6 )               )
              goto Fail;

            /* record the starting point's y position for later use */
            start_y = y;

            /* first control point */
            x += args[0];
            y += args[1];
            cff_builder_add_point( builder, x, y, 0 );

            /* second control point */
            x += args[2];
            y += args[3];
            cff_builder_add_point( builder, x, y, 0 );

            /* join point; on curve, with y-value the same as the last */
            /* control point's y-value                                 */
            x += args[4];
            cff_builder_add_point( builder, x, y, 1 );

            /* third control point, with y-value the same as the join */
            /* point's y-value                                        */
            x += args[5];
            cff_builder_add_point( builder, x, y, 0 );

            /* fourth control point */
            x += args[6];
            y += args[7];
            cff_builder_add_point( builder, x, y, 0 );

            /* ending point, with y-value the same as the start   */
            x += args[8];
            y  = start_y;
            cff_builder_add_point( builder, x, y, 1 );

            args = stack;
            break;
          }

        case cff_op_hflex:
          {
            FT_Pos start_y;

            FT_TRACE4(( " hflex\n" ));

            /* adding six more points; 4 control points, 2 on-curve points */
            if ( cff_builder_start_point( builder, x, y ) ||
                 check_points( builder, 6 )               )
              goto Fail;

            /* record the starting point's y-position for later use */
            start_y = y;

            /* first control point */
            x += args[0];
            cff_builder_add_point( builder, x, y, 0 );

            /* second control point */
            x += args[1];
            y += args[2];
            cff_builder_add_point( builder, x, y, 0 );

            /* join point; on curve, with y-value the same as the last */
            /* control point's y-value                                 */
            x += args[3];
            cff_builder_add_point( builder, x, y, 1 );

            /* third control point, with y-value the same as the join */
            /* point's y-value                                        */
            x += args[4];
            cff_builder_add_point( builder, x, y, 0 );

            /* fourth control point */
            x += args[5];
            y  = start_y;
            cff_builder_add_point( builder, x, y, 0 );

            /* ending point, with y-value the same as the start point's */
            /* y-value -- we don't add this point, though               */
            x += args[6];
            cff_builder_add_point( builder, x, y, 1 );

            args = stack;
            break;
          }

        case cff_op_flex1:
          {
            FT_Pos     start_x, start_y; /* record start x, y values for */
                                         /* alter use                    */
            FT_Fixed   dx = 0, dy = 0;   /* used in horizontal/vertical  */
                                         /* algorithm below              */
            FT_Int     horizontal, count;
            FT_Fixed*  temp;

            FT_TRACE4(( " flex1\n" ));

            /* adding six more points; 4 control points, 2 on-curve points */
            if ( cff_builder_start_point( builder, x, y ) ||
                 check_points( builder, 6 )               )
              goto Fail;

            /* record the starting point's x, y position for later use */
            start_x = x;
            start_y = y;

            /* XXX: figure out whether this is supposed to be a horizontal */
            /*      or vertical flex; the Type 2 specification is vague... */

            temp = args;

            /* grab up to the last argument */
            for ( count = 5; count > 0; count-- )
            {
              dx += temp[0];
              dy += temp[1];
              temp += 2;
            }

            if ( dx < 0 )
              dx = -dx;
            if ( dy < 0 )
              dy = -dy;

            /* strange test, but here it is... */
            horizontal = ( dx > dy );

            for ( count = 5; count > 0; count-- )
            {
              x += args[0];
              y += args[1];
              cff_builder_add_point( builder, x, y,
                                     (FT_Bool)( count == 3 ) );
              args += 2;
            }

            /* is last operand an x- or y-delta? */
            if ( horizontal )
            {
              x += args[0];
              y  = start_y;
            }
            else
            {
              x  = start_x;
              y += args[0];
            }

            cff_builder_add_point( builder, x, y, 1 );

            args = stack;
            break;
           }

        case cff_op_flex:
          {
            FT_UInt  count;

            FT_TRACE4(( " flex\n" ));

            if ( cff_builder_start_point( builder, x, y ) ||
                 check_points( builder, 6 )               )
              goto Fail;

            for ( count = 6; count > 0; count-- )
            {
              x += args[0];
              y += args[1];
              cff_builder_add_point( builder, x, y,
                                     (FT_Bool)( count == 4 || count == 1 ) );
              args += 2;
            }

            args = stack;
          }
          break;

        case cff_op_seac:
            FT_TRACE4(( " seac\n" ));

            error = cff_operator_seac( decoder,
                                       args[0], args[1], args[2],
                                       (FT_Int)( args[3] >> 16 ),
                                       (FT_Int)( args[4] >> 16 ) );

            /* add current outline to the glyph slot */
            FT_GlyphLoader_Add( builder->loader );

            /* return now! */
            FT_TRACE4(( "\n" ));
            return error;

        case cff_op_endchar:
          FT_TRACE4(( " endchar\n" ));

          /* We are going to emulate the seac operator. */
          if ( num_args >= 4 )
          {
            /* Save glyph width so that the subglyphs don't overwrite it. */
            FT_Pos  glyph_width = decoder->glyph_width;

            error = cff_operator_seac( decoder,
                                       0L, args[-4], args[-3],
                                       (FT_Int)( args[-2] >> 16 ),
                                       (FT_Int)( args[-1] >> 16 ) );

            decoder->glyph_width = glyph_width;
          }
          else
          {
            if ( !error )
              error = CFF_Err_Ok;

            cff_builder_close_contour( builder );

            /* close hints recording session */
            if ( hinter )
            {
              if ( hinter->close( hinter->hints,
                                  builder->current->n_points ) )
                goto Syntax_Error;

              /* apply hints to the loaded glyph outline now */
              hinter->apply( hinter->hints,
                             builder->current,
                             (PSH_Globals)builder->hints_globals,
                             decoder->hint_mode );
            }

            /* add current outline to the glyph slot */
            FT_GlyphLoader_Add( builder->loader );
          }

          /* return now! */
          FT_TRACE4(( "\n" ));
          return error;

        case cff_op_abs:
          FT_TRACE4(( " abs\n" ));

          if ( args[0] < 0 )
            args[0] = -args[0];
          args++;
          break;

        case cff_op_add:
          FT_TRACE4(( " add\n" ));

          args[0] += args[1];
          args++;
          break;

        case cff_op_sub:
          FT_TRACE4(( " sub\n" ));

          args[0] -= args[1];
          args++;
          break;

        case cff_op_div:
          FT_TRACE4(( " div\n" ));

          args[0] = FT_DivFix( args[0], args[1] );
          args++;
          break;

        case cff_op_neg:
          FT_TRACE4(( " neg\n" ));

          args[0] = -args[0];
          args++;
          break;

        case cff_op_random:
          {
            FT_Fixed  Rand;

            FT_TRACE4(( " rand\n" ));

            Rand = seed;
            if ( Rand >= 0x8000L )
              Rand++;

            args[0] = Rand;
            seed    = FT_MulFix( seed, 0x10000L - seed );
            if ( seed == 0 )
              seed += 0x2873;
            args++;
          }
          break;

        case cff_op_mul:
          FT_TRACE4(( " mul\n" ));

          args[0] = FT_MulFix( args[0], args[1] );
          args++;
          break;

        case cff_op_sqrt:
          FT_TRACE4(( " sqrt\n" ));

          if ( args[0] > 0 )
          {
            FT_Int    count = 9;
            FT_Fixed  root  = args[0];
            FT_Fixed  new_root;

            for (;;)
            {
              new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
              if ( new_root == root || count <= 0 )
                break;
              root = new_root;
            }
            args[0] = new_root;
          }
          else
            args[0] = 0;
          args++;
          break;

        case cff_op_drop:
          /* nothing */
          FT_TRACE4(( " drop\n" ));

          break;

        case cff_op_exch:
          {
            FT_Fixed  tmp;

            FT_TRACE4(( " exch\n" ));

            tmp     = args[0];
            args[0] = args[1];
            args[1] = tmp;
            args   += 2;
          }
          break;

        case cff_op_index:
          {
            FT_Int  idx = (FT_Int)( args[0] >> 16 );

            FT_TRACE4(( " index\n" ));

            if ( idx < 0 )
              idx = 0;
            else if ( idx > num_args - 2 )
              idx = num_args - 2;
            args[0] = args[-( idx + 1 )];
            args++;
          }
          break;

        case cff_op_roll:
          {
            FT_Int  count = (FT_Int)( args[0] >> 16 );
            FT_Int  idx   = (FT_Int)( args[1] >> 16 );

            FT_TRACE4(( " roll\n" ));

            if ( count <= 0 )
              count = 1;

            args -= count;
            if ( args < stack )
              goto Stack_Underflow;

            if ( idx >= 0 )
            {
              while ( idx > 0 )
              {
                FT_Fixed  tmp = args[count - 1];
                FT_Int    i;

                for ( i = count - 2; i >= 0; i-- )
                  args[i + 1] = args[i];
                args[0] = tmp;
                idx--;
              }
            }
            else
            {
              while ( idx < 0 )
              {
                FT_Fixed  tmp = args[0];
                FT_Int    i;

                for ( i = 0; i < count - 1; i++ )
                  args[i] = args[i + 1];
                args[count - 1] = tmp;
                idx++;
              }
            }
            args += count;
          }
          break;

        case cff_op_dup:
          FT_TRACE4(( " dup\n" ));

          args[1] = args[0];
          args += 2;
          break;

        case cff_op_put:
          {
            FT_Fixed  val = args[0];
            FT_Int    idx = (FT_Int)( args[1] >> 16 );

            FT_TRACE4(( " put\n" ));

            if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS )
              decoder->buildchar[idx] = val;
          }
          break;

        case cff_op_get:
          {
            FT_Int    idx = (FT_Int)( args[0] >> 16 );
            FT_Fixed  val = 0;

            FT_TRACE4(( " get\n" ));

            if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS )
              val = decoder->buildchar[idx];

            args[0] = val;
            args++;
          }
          break;

        case cff_op_store:
          FT_TRACE4(( " store\n"));

          goto Unimplemented;

        case cff_op_load:
          FT_TRACE4(( " load\n" ));

          goto Unimplemented;

        case cff_op_dotsection:
          /* this operator is deprecated and ignored by the parser */
          FT_TRACE4(( " dotsection\n" ));
          break;

        case cff_op_closepath:
          /* this is an invalid Type 2 operator; however, there        */
          /* exist fonts which are incorrectly converted from probably */
          /* Type 1 to CFF, and some parsers seem to accept it         */

          FT_TRACE4(( " closepath (invalid op)\n" ));

          args = stack;
          break;

        case cff_op_hsbw:
          /* this is an invalid Type 2 operator; however, there        */
          /* exist fonts which are incorrectly converted from probably */
          /* Type 1 to CFF, and some parsers seem to accept it         */

          FT_TRACE4(( " hsbw (invalid op)\n" ));

          decoder->glyph_width = decoder->nominal_width + ( args[1] >> 16 );

          decoder->builder.left_bearing.x = args[0];
          decoder->builder.left_bearing.y = 0;

          x    = decoder->builder.pos_x + args[0];
          y    = decoder->builder.pos_y;
          args = stack;
          break;

        case cff_op_sbw:
          /* this is an invalid Type 2 operator; however, there        */
          /* exist fonts which are incorrectly converted from probably */
          /* Type 1 to CFF, and some parsers seem to accept it         */

          FT_TRACE4(( " sbw (invalid op)\n" ));

          decoder->glyph_width = decoder->nominal_width + ( args[2] >> 16 );

          decoder->builder.left_bearing.x = args[0];
          decoder->builder.left_bearing.y = args[1];

          x    = decoder->builder.pos_x + args[0];
          y    = decoder->builder.pos_y + args[1];
          args = stack;
          break;

        case cff_op_setcurrentpoint:
          /* this is an invalid Type 2 operator; however, there        */
          /* exist fonts which are incorrectly converted from probably */
          /* Type 1 to CFF, and some parsers seem to accept it         */

          FT_TRACE4(( " setcurrentpoint (invalid op)\n" ));

          x    = decoder->builder.pos_x + args[0];
          y    = decoder->builder.pos_y + args[1];
          args = stack;
          break;

        case cff_op_callothersubr:
          /* this is an invalid Type 2 operator; however, there        */
          /* exist fonts which are incorrectly converted from probably */
          /* Type 1 to CFF, and some parsers seem to accept it         */

          FT_TRACE4(( " callothersubr (invalid op)\n" ));

          /* subsequent `pop' operands should add the arguments,       */
           /* this is the implementation described for `unknown' other  */
           /* subroutines in the Type1 spec.                            */
           args -= 2 + ( args[-2] >> 16 );
          if ( args < stack )
            goto Stack_Underflow;
           break;

         case cff_op_pop:
          /* Type 1 to CFF, and some parsers seem to accept it         */

          FT_TRACE4(( " pop (invalid op)\n" ));

          args++;
          break;

        case cff_op_and:
          {
            FT_Fixed  cond = args[0] && args[1];

            FT_TRACE4(( " and\n" ));

            args[0] = cond ? 0x10000L : 0;
            args++;
          }
          break;

        case cff_op_or:
          {
            FT_Fixed  cond = args[0] || args[1];

            FT_TRACE4(( " or\n" ));

            args[0] = cond ? 0x10000L : 0;
            args++;
          }
          break;

        case cff_op_eq:
          {
            FT_Fixed  cond = !args[0];

            FT_TRACE4(( " eq\n" ));

            args[0] = cond ? 0x10000L : 0;
            args++;
          }
          break;

        case cff_op_ifelse:
          {
            FT_Fixed  cond = ( args[2] <= args[3] );

            FT_TRACE4(( " ifelse\n" ));

            if ( !cond )
              args[0] = args[1];
            args++;
          }
          break;

        case cff_op_callsubr:
          {
            FT_UInt  idx = (FT_UInt)( ( args[0] >> 16 ) +
                                      decoder->locals_bias );

            FT_TRACE4(( " callsubr(%d)\n", idx ));

            if ( idx >= decoder->num_locals )
            {
              FT_ERROR(( "cff_decoder_parse_charstrings:"
                         " invalid local subr index\n" ));
              goto Syntax_Error;
            }

            if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
            {
              FT_ERROR(( "cff_decoder_parse_charstrings:"
                         " too many nested subrs\n" ));
              goto Syntax_Error;
            }

            zone->cursor = ip;  /* save current instruction pointer */

            zone++;
            zone->base   = decoder->locals[idx];
            zone->limit  = decoder->locals[idx + 1];
            zone->cursor = zone->base;

            if ( !zone->base || zone->limit == zone->base )
            {
              FT_ERROR(( "cff_decoder_parse_charstrings:"
                         " invoking empty subrs\n" ));
              goto Syntax_Error;
            }

            decoder->zone = zone;
            ip            = zone->base;
            limit         = zone->limit;
          }
          break;

        case cff_op_callgsubr:
          {
            FT_UInt  idx = (FT_UInt)( ( args[0] >> 16 ) +
                                      decoder->globals_bias );

            FT_TRACE4(( " callgsubr(%d)\n", idx ));

            if ( idx >= decoder->num_globals )
            {
              FT_ERROR(( "cff_decoder_parse_charstrings:"
                         " invalid global subr index\n" ));
              goto Syntax_Error;
            }

            if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
            {
              FT_ERROR(( "cff_decoder_parse_charstrings:"
                         " too many nested subrs\n" ));
              goto Syntax_Error;
            }

            zone->cursor = ip;  /* save current instruction pointer */

            zone++;
            zone->base   = decoder->globals[idx];
            zone->limit  = decoder->globals[idx + 1];
            zone->cursor = zone->base;

            if ( !zone->base || zone->limit == zone->base )
            {
              FT_ERROR(( "cff_decoder_parse_charstrings:"
                         " invoking empty subrs\n" ));
              goto Syntax_Error;
            }

            decoder->zone = zone;
            ip            = zone->base;
            limit         = zone->limit;
          }
          break;

        case cff_op_return:
          FT_TRACE4(( " return\n" ));

          if ( decoder->zone <= decoder->zones )
          {
            FT_ERROR(( "cff_decoder_parse_charstrings:"
                       " unexpected return\n" ));
            goto Syntax_Error;
          }

          decoder->zone--;
          zone  = decoder->zone;
          ip    = zone->cursor;
          limit = zone->limit;
          break;

        default:
        Unimplemented:
          FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));

          if ( ip[-1] == 12 )
            FT_ERROR(( " %d", ip[0] ));
          FT_ERROR(( "\n" ));

          return CFF_Err_Unimplemented_Feature;
        }

      decoder->top = args;

      } /* general operator processing */

    } /* while ip < limit */

    FT_TRACE4(( "..end..\n\n" ));

  Fail:
    return error;

  Syntax_Error:
    FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" ));
    return CFF_Err_Invalid_File_Format;

  Stack_Underflow:
    FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow\n" ));
    return CFF_Err_Too_Few_Arguments;

  Stack_Overflow:
    FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow\n" ));
    return CFF_Err_Stack_Overflow;
  }


XvQueryAdaptors(
    Display *dpy,
    Window window,
    unsigned int *p_nAdaptors,
    XvAdaptorInfo **p_pAdaptors)
{
    XExtDisplayInfo *info = xv_find_display(dpy);
    xvQueryAdaptorsReq *req;
    xvQueryAdaptorsReply rep;
     size_t size;
     unsigned int ii, jj;
     char *name;
     XvAdaptorInfo *pas = NULL, *pa;
     XvFormat *pfs, *pf;
     char *buffer = NULL;
        char *buffer;
        char *string;
        xvAdaptorInfo *pa;
        xvFormat *pf;
    } u;

The (1) XvQueryAdaptors and (2) XvQueryEncodings functions in X.org libXv before 1.0.11 allow remote X servers to trigger out-of-bounds memory access operations via vectors involving length specifications in received data.


XvQueryAdaptors(
    Display *dpy,
    Window window,
    unsigned int *p_nAdaptors,
    XvAdaptorInfo **p_pAdaptors)
{
    XExtDisplayInfo *info = xv_find_display(dpy);
    xvQueryAdaptorsReq *req;
    xvQueryAdaptorsReply rep;
     size_t size;
     unsigned int ii, jj;
     char *name;
    char *end;
     XvAdaptorInfo *pas = NULL, *pa;
     XvFormat *pfs, *pf;
     char *buffer = NULL;
        char *buffer;
        char *string;
        xvAdaptorInfo *pa;
        xvFormat *pf;
    } u;


intuit_diff_type (bool need_header, mode_t *p_file_type)
{
    file_offset this_line = 0;
    file_offset first_command_line = -1;
    char first_ed_command_letter = 0;
    lin fcl_line = 0; /* Pacify 'gcc -W'.  */
    bool this_is_a_command = false;
    bool stars_this_line = false;
    bool extended_headers = false;
    enum nametype i;
    struct stat st[3];
    int stat_errno[3];
    int version_controlled[3];
    enum diff retval;
    mode_t file_type;
    size_t indent = 0;

    for (i = OLD;  i <= INDEX;  i++)
      if (p_name[i]) {
	  free (p_name[i]);
	  p_name[i] = 0;
        }
    for (i = 0; i < ARRAY_SIZE (invalid_names); i++)
	invalid_names[i] = NULL;
    for (i = OLD; i <= NEW; i++)
      if (p_timestr[i])
	{
	  free(p_timestr[i]);
	  p_timestr[i] = 0;
	}
    for (i = OLD; i <= NEW; i++)
      if (p_sha1[i])
	{
	  free (p_sha1[i]);
	  p_sha1[i] = 0;
	}
    p_git_diff = false;
    for (i = OLD; i <= NEW; i++)
      {
	p_mode[i] = 0;
	p_copy[i] = false;
	p_rename[i] = false;
      }

    /* Ed and normal format patches don't have filename headers.  */
    if (diff_type == ED_DIFF || diff_type == NORMAL_DIFF)
      need_header = false;

    version_controlled[OLD] = -1;
    version_controlled[NEW] = -1;
    version_controlled[INDEX] = -1;
    p_rfc934_nesting = 0;
    p_timestamp[OLD].tv_sec = p_timestamp[NEW].tv_sec = -1;
    p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0;
    Fseek (pfp, p_base, SEEK_SET);
    p_input_line = p_bline - 1;
    for (;;) {
	char *s;
	char *t;
	file_offset previous_line = this_line;
	bool last_line_was_command = this_is_a_command;
	bool stars_last_line = stars_this_line;
	size_t indent_last_line = indent;
	char ed_command_letter;
	bool strip_trailing_cr;
	size_t chars_read;

	indent = 0;
	this_line = file_tell (pfp);
	chars_read = pget_line (0, 0, false, false);
	if (chars_read == (size_t) -1)
	  xalloc_die ();
	if (! chars_read) {
	    if (first_ed_command_letter) {
					/* nothing but deletes!? */
		p_start = first_command_line;
		p_sline = fcl_line;
		retval = ED_DIFF;
		goto scan_exit;
	    }
	    else {
		p_start = this_line;
		p_sline = p_input_line;
		if (extended_headers)
		  {
		    /* Patch contains no hunks; any diff type will do. */
		    retval = UNI_DIFF;
		    goto scan_exit;
		  }
		return NO_DIFF;
	    }
	}
	strip_trailing_cr = 2 <= chars_read && buf[chars_read - 2] == '\r';
	for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
	    if (*s == '\t')
		indent = (indent + 8) & ~7;
	    else
		indent++;
	}
	if (ISDIGIT (*s))
	  {
	    for (t = s + 1; ISDIGIT (*t) || *t == ',';  t++)
	      /* do nothing */ ;
	    if (*t == 'd' || *t == 'c' || *t == 'a')
	      {
		for (t++;  ISDIGIT (*t) || *t == ',';  t++)
		  /* do nothing */ ;
		for (; *t == ' ' || *t == '\t'; t++)
		  /* do nothing */ ;
		if (*t == '\r')
		  t++;
		this_is_a_command = (*t == '\n');
	      }
	  }
	if (! need_header
	    && first_command_line < 0
	    && ((ed_command_letter = get_ed_command_letter (s))
		|| this_is_a_command)) {
	    first_command_line = this_line;
	    first_ed_command_letter = ed_command_letter;
	    fcl_line = p_input_line;
	    p_indent = indent;		/* assume this for now */
	    p_strip_trailing_cr = strip_trailing_cr;
	}
	if (!stars_last_line && strnEQ(s, "*** ", 4))
	  {
	    fetchname (s+4, strippath, &p_name[OLD], &p_timestr[OLD],
		       &p_timestamp[OLD]);
	    need_header = false;
	  }
	else if (strnEQ(s, "+++ ", 4))
	  {
	    /* Swap with NEW below.  */
	    fetchname (s+4, strippath, &p_name[OLD], &p_timestr[OLD],
		       &p_timestamp[OLD]);
	    need_header = false;
	    p_strip_trailing_cr = strip_trailing_cr;
	  }
	else if (strnEQ(s, "Index:", 6))
	  {
	    fetchname (s+6, strippath, &p_name[INDEX], (char **) 0, NULL);
	    need_header = false;
	    p_strip_trailing_cr = strip_trailing_cr;
	  }
	else if (strnEQ(s, "Prereq:", 7))
	  {
	    for (t = s + 7;  ISSPACE ((unsigned char) *t);  t++)
	      /* do nothing */ ;
	    revision = t;
	    for (t = revision;  *t;  t++)
	      if (ISSPACE ((unsigned char) *t))
		{
		  char const *u;
		  for (u = t + 1;  ISSPACE ((unsigned char) *u);  u++)
		    /* do nothing */ ;
		  if (*u)
		    {
		      char numbuf[LINENUM_LENGTH_BOUND + 1];
		      say ("Prereq: with multiple words at line %s of patch\n",
			   format_linenum (numbuf, this_line));
		    }
		  break;
		}
	    if (t == revision)
		revision = 0;
	    else {
		char oldc = *t;
		*t = '\0';
		revision = xstrdup (revision);
		*t = oldc;
	    }
	  }
	else if (strnEQ (s, "diff --git ", 11))
	  {
	    char const *u;

	    if (extended_headers)
	      {
		p_start = this_line;
		p_sline = p_input_line;
		/* Patch contains no hunks; any diff type will do. */
		retval = UNI_DIFF;
		goto scan_exit;
	      }

	    for (i = OLD; i <= NEW; i++)
	      {
		free (p_name[i]);
		p_name[i] = 0;
	      }
	    if (! ((p_name[OLD] = parse_name (s + 11, strippath, &u))
		   && ISSPACE ((unsigned char) *u)
		   && (p_name[NEW] = parse_name (u, strippath, &u))
		   && (u = skip_spaces (u), ! *u)))
	      for (i = OLD; i <= NEW; i++)
		{
		  free (p_name[i]);
		  p_name[i] = 0;
		}
	    p_git_diff = true;
	    need_header = false;
	  }
	else if (p_git_diff && strnEQ (s, "index ", 6))
	  {
	    char const *u, *v;
	    if ((u = skip_hex_digits (s + 6))
		&& u[0] == '.' && u[1] == '.'
		&& (v = skip_hex_digits (u + 2))
		&& (! *v || ISSPACE ((unsigned char) *v)))
	      {
		get_sha1(&p_sha1[OLD], s + 6, u);
		get_sha1(&p_sha1[NEW], u + 2, v);
		p_says_nonexistent[OLD] = sha1_says_nonexistent (p_sha1[OLD]);
		p_says_nonexistent[NEW] = sha1_says_nonexistent (p_sha1[NEW]);
		if (*(v = skip_spaces (v)))
		  p_mode[OLD] = p_mode[NEW] = fetchmode (v);
		extended_headers = true;
	      }
	  }
	else if (p_git_diff && strnEQ (s, "old mode ", 9))
	  {
	    p_mode[OLD] = fetchmode (s + 9);
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "new mode ", 9))
	  {
	    p_mode[NEW] = fetchmode (s + 9);
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "deleted file mode ", 18))
	  {
	    p_mode[OLD] = fetchmode (s + 18);
	    p_says_nonexistent[NEW] = 2;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "new file mode ", 14))
	  {
	    p_mode[NEW] = fetchmode (s + 14);
	    p_says_nonexistent[OLD] = 2;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "rename from ", 12))
	  {
	    /* Git leaves out the prefix in the file name in this header,
	       so we can only ignore the file name.  */
	    p_rename[OLD] = true;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "rename to ", 10))
	  {
	    /* Git leaves out the prefix in the file name in this header,
	       so we can only ignore the file name.  */
	    p_rename[NEW] = true;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "copy from ", 10))
	  {
	    /* Git leaves out the prefix in the file name in this header,
	       so we can only ignore the file name.  */
	    p_copy[OLD] = true;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "copy to ", 8))
	  {
	    /* Git leaves out the prefix in the file name in this header,
	       so we can only ignore the file name.  */
	    p_copy[NEW] = true;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "GIT binary patch", 16))
	  {
	    p_start = this_line;
	    p_sline = p_input_line;
	    retval = GIT_BINARY_DIFF;
	    goto scan_exit;
	  }
	else
	  {
	    for (t = s;  t[0] == '-' && t[1] == ' ';  t += 2)
	      /* do nothing */ ;
	    if (strnEQ(t, "--- ", 4))
	      {
		struct timespec timestamp;
		timestamp.tv_sec = -1;
		fetchname (t+4, strippath, &p_name[NEW], &p_timestr[NEW],
			   &timestamp);
		need_header = false;
		if (timestamp.tv_sec != -1)
		  {
		    p_timestamp[NEW] = timestamp;
		    p_rfc934_nesting = (t - s) >> 1;
		  }
		p_strip_trailing_cr = strip_trailing_cr;
	      }
	  }
	if (need_header)
	  continue;
	if ((diff_type == NO_DIFF || diff_type == ED_DIFF) &&
	  first_command_line >= 0 &&
	  strEQ(s, ".\n") ) {
	    p_start = first_command_line;
	    p_sline = fcl_line;
	    retval = ED_DIFF;
	    goto scan_exit;
	}
	if ((diff_type == NO_DIFF || diff_type == UNI_DIFF)
	    && strnEQ(s, "@@ -", 4)) {

	    /* 'p_name', 'p_timestr', and 'p_timestamp' are backwards;
	       swap them.  */
	    struct timespec ti = p_timestamp[OLD];
	    p_timestamp[OLD] = p_timestamp[NEW];
	    p_timestamp[NEW] = ti;
	    t = p_name[OLD];
	    p_name[OLD] = p_name[NEW];
	    p_name[NEW] = t;
	    t = p_timestr[OLD];
	    p_timestr[OLD] = p_timestr[NEW];
	    p_timestr[NEW] = t;

	    s += 4;
	    if (s[0] == '0' && !ISDIGIT (s[1]))
	      p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD].tv_sec;
	    while (*s != ' ' && *s != '\n')
	      s++;
	    while (*s == ' ')
	      s++;
	    if (s[0] == '+' && s[1] == '0' && !ISDIGIT (s[2]))
	      p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW].tv_sec;
	    p_indent = indent;
	    p_start = this_line;
	    p_sline = p_input_line;
	    retval = UNI_DIFF;
	    if (! ((p_name[OLD] || ! p_timestamp[OLD].tv_sec)
		   && (p_name[NEW] || ! p_timestamp[NEW].tv_sec))
		&& ! p_name[INDEX] && need_header)
	      {
		char numbuf[LINENUM_LENGTH_BOUND + 1];
		say ("missing header for unified diff at line %s of patch\n",
		     format_linenum (numbuf, p_sline));
	      }
	    goto scan_exit;
	}
	stars_this_line = strnEQ(s, "********", 8);
	if ((diff_type == NO_DIFF
	     || diff_type == CONTEXT_DIFF
	     || diff_type == NEW_CONTEXT_DIFF)
	    && stars_last_line && indent_last_line == indent
	    && strnEQ (s, "*** ", 4)) {
	    s += 4;
	    if (s[0] == '0' && !ISDIGIT (s[1]))
	      p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD].tv_sec;
	    /* if this is a new context diff the character just before */
	    /* the newline is a '*'. */
	    while (*s != '\n')
		s++;
	    p_indent = indent;
	    p_strip_trailing_cr = strip_trailing_cr;
	    p_start = previous_line;
	    p_sline = p_input_line - 1;
	    retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);

	    {
	      /* Scan the first hunk to see whether the file contents
		 appear to have been deleted.  */
	      file_offset saved_p_base = p_base;
	      lin saved_p_bline = p_bline;
	      Fseek (pfp, previous_line, SEEK_SET);
	      p_input_line -= 2;
	      if (another_hunk (retval, false)
		  && ! p_repl_lines && p_newfirst == 1)
		p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW].tv_sec;
	      next_intuit_at (saved_p_base, saved_p_bline);
	    }

	    if (! ((p_name[OLD] || ! p_timestamp[OLD].tv_sec)
		   && (p_name[NEW] || ! p_timestamp[NEW].tv_sec))
		&& ! p_name[INDEX] && need_header)
	      {
		char numbuf[LINENUM_LENGTH_BOUND + 1];
		say ("missing header for context diff at line %s of patch\n",
		     format_linenum (numbuf, p_sline));
	      }
	    goto scan_exit;
	}
	if ((diff_type == NO_DIFF || diff_type == NORMAL_DIFF) &&
	  last_line_was_command &&
	  (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
	    p_start = previous_line;
	    p_sline = p_input_line - 1;
	    p_indent = indent;
	    retval = NORMAL_DIFF;
	    goto scan_exit;
	}
    }

  scan_exit:

    /* The old, new, or old and new file types may be defined.  When both
       file types are defined, make sure they are the same, or else assume
       we do not know the file type.  */
    file_type = p_mode[OLD] & S_IFMT;
    if (file_type)
      {
	mode_t new_file_type = p_mode[NEW] & S_IFMT;
	if (new_file_type && file_type != new_file_type)
	  file_type = 0;
      }
    else
      {
	file_type = p_mode[NEW] & S_IFMT;
	if (! file_type)
	  file_type = S_IFREG;
      }
    *p_file_type = file_type;

    /* To intuit 'inname', the name of the file to patch,
       use the algorithm specified by POSIX 1003.1-2001 XCU lines 25680-26599
       (with some modifications if posixly_correct is zero):

       - Take the old and new names from the context header if present,
	 and take the index name from the 'Index:' line if present and
	 if either the old and new names are both absent
	 or posixly_correct is nonzero.
	 Consider the file names to be in the order (old, new, index).
       - If some named files exist, use the first one if posixly_correct
	 is nonzero, the best one otherwise.
       - If patch_get is nonzero, and no named files exist,
	 but an RCS or SCCS master file exists,
	 use the first named file with an RCS or SCCS master.
       - If no named files exist, no RCS or SCCS master was found,
	 some names are given, posixly_correct is zero,
	 and the patch appears to create a file, then use the best name
	 requiring the creation of the fewest directories.
       - Otherwise, report failure by setting 'inname' to 0;
	 this causes our invoker to ask the user for a file name.  */

    i = NONE;

    if (!inname)
      {
	enum nametype i0 = NONE;

	if (! posixly_correct && (p_name[OLD] || p_name[NEW]) && p_name[INDEX])
	  {
	    free (p_name[INDEX]);
	    p_name[INDEX] = 0;
	  }

	for (i = OLD;  i <= INDEX;  i++)
	  if (p_name[i])
	    {
	      if (i0 != NONE && strcmp (p_name[i0], p_name[i]) == 0)
		{
		  /* It's the same name as before; reuse stat results.  */
		  stat_errno[i] = stat_errno[i0];
		  if (! stat_errno[i])
		    st[i] = st[i0];
		}
	      else
		{
		  stat_errno[i] = stat_file (p_name[i], &st[i]);
		  if (! stat_errno[i])
		    {
		      if (lookup_file_id (&st[i]) == DELETE_LATER)
			stat_errno[i] = ENOENT;
		      else if (posixly_correct && name_is_valid (p_name[i]))
			break;
		    }
		}
	      i0 = i;
	    }

	if (! posixly_correct)
	  {
	    /* The best of all existing files. */
	    i = best_name (p_name, stat_errno);

	    if (i == NONE && patch_get)
	      {
		enum nametype nope = NONE;

		for (i = OLD;  i <= INDEX;  i++)
		  if (p_name[i])
		    {
		      char const *cs;
		      char *getbuf;
		      char *diffbuf;
		      bool readonly = (outfile
				       && strcmp (outfile, p_name[i]) != 0);

		      if (nope == NONE || strcmp (p_name[nope], p_name[i]) != 0)
			{
			  cs = (version_controller
			        (p_name[i], readonly, (struct stat *) 0,
				 &getbuf, &diffbuf));
			  version_controlled[i] = !! cs;
			  if (cs)
			    {
			      if (version_get (p_name[i], cs, false, readonly,
					       getbuf, &st[i]))
				stat_errno[i] = 0;
			      else
				version_controlled[i] = 0;

			      free (getbuf);
			      free (diffbuf);

			      if (! stat_errno[i])
				break;
			    }
			}

		      nope = i;
		    }
	      }

	    if (i0 != NONE
		&& (i == NONE || (st[i].st_mode & S_IFMT) == file_type)
		&& maybe_reverse (p_name[i == NONE ? i0 : i], i == NONE,
				  i == NONE || st[i].st_size == 0)
		&& i == NONE)
	      i = i0;

	    if (i == NONE && p_says_nonexistent[reverse])
	      {
		int newdirs[3];
		int newdirs_min = INT_MAX;
		int distance_from_minimum[3];

		for (i = OLD;  i <= INDEX;  i++)
		  if (p_name[i])
		    {
		      newdirs[i] = (prefix_components (p_name[i], false)
				    - prefix_components (p_name[i], true));
		      if (newdirs[i] < newdirs_min)
			newdirs_min = newdirs[i];
		    }

		for (i = OLD;  i <= INDEX;  i++)
		  if (p_name[i])
		    distance_from_minimum[i] = newdirs[i] - newdirs_min;

		/* The best of the filenames which create the fewest directories. */
		i = best_name (p_name, distance_from_minimum);
	      }
	  }
      }

     if ((pch_rename () || pch_copy ())
 	&& ! inname
 	&& ! ((i == OLD || i == NEW) &&
	      p_name[! reverse] &&
 	      name_is_valid (p_name[! reverse])))
       {
 	say ("Cannot %s file without two valid file names\n", pch_rename () ? "rename" : "copy");
      }

    if (i == NONE)
      {
	if (inname)
	  {
	    inerrno = stat_file (inname, &instat);
	    if (inerrno || (instat.st_mode & S_IFMT) == file_type)
	      maybe_reverse (inname, inerrno, inerrno || instat.st_size == 0);
	  }
	else
          inerrno = -1;
      }
    else
      {
	inname = xstrdup (p_name[i]);
	inerrno = stat_errno[i];
	invc = version_controlled[i];
	instat = st[i];
      }

    return retval;
}

An issue was discovered in GNU patch through 2.7.6. There is a segmentation fault, associated with a NULL pointer dereference, leading to a denial of service in the intuit_diff_type function in pch.c, aka a "mangled rename" issue.


intuit_diff_type (bool need_header, mode_t *p_file_type)
{
    file_offset this_line = 0;
    file_offset first_command_line = -1;
    char first_ed_command_letter = 0;
    lin fcl_line = 0; /* Pacify 'gcc -W'.  */
    bool this_is_a_command = false;
    bool stars_this_line = false;
    bool extended_headers = false;
    enum nametype i;
    struct stat st[3];
    int stat_errno[3];
    int version_controlled[3];
    enum diff retval;
    mode_t file_type;
    size_t indent = 0;

    for (i = OLD;  i <= INDEX;  i++)
      if (p_name[i]) {
	  free (p_name[i]);
	  p_name[i] = 0;
        }
    for (i = 0; i < ARRAY_SIZE (invalid_names); i++)
	invalid_names[i] = NULL;
    for (i = OLD; i <= NEW; i++)
      if (p_timestr[i])
	{
	  free(p_timestr[i]);
	  p_timestr[i] = 0;
	}
    for (i = OLD; i <= NEW; i++)
      if (p_sha1[i])
	{
	  free (p_sha1[i]);
	  p_sha1[i] = 0;
	}
    p_git_diff = false;
    for (i = OLD; i <= NEW; i++)
      {
	p_mode[i] = 0;
	p_copy[i] = false;
	p_rename[i] = false;
      }

    /* Ed and normal format patches don't have filename headers.  */
    if (diff_type == ED_DIFF || diff_type == NORMAL_DIFF)
      need_header = false;

    version_controlled[OLD] = -1;
    version_controlled[NEW] = -1;
    version_controlled[INDEX] = -1;
    p_rfc934_nesting = 0;
    p_timestamp[OLD].tv_sec = p_timestamp[NEW].tv_sec = -1;
    p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0;
    Fseek (pfp, p_base, SEEK_SET);
    p_input_line = p_bline - 1;
    for (;;) {
	char *s;
	char *t;
	file_offset previous_line = this_line;
	bool last_line_was_command = this_is_a_command;
	bool stars_last_line = stars_this_line;
	size_t indent_last_line = indent;
	char ed_command_letter;
	bool strip_trailing_cr;
	size_t chars_read;

	indent = 0;
	this_line = file_tell (pfp);
	chars_read = pget_line (0, 0, false, false);
	if (chars_read == (size_t) -1)
	  xalloc_die ();
	if (! chars_read) {
	    if (first_ed_command_letter) {
					/* nothing but deletes!? */
		p_start = first_command_line;
		p_sline = fcl_line;
		retval = ED_DIFF;
		goto scan_exit;
	    }
	    else {
		p_start = this_line;
		p_sline = p_input_line;
		if (extended_headers)
		  {
		    /* Patch contains no hunks; any diff type will do. */
		    retval = UNI_DIFF;
		    goto scan_exit;
		  }
		return NO_DIFF;
	    }
	}
	strip_trailing_cr = 2 <= chars_read && buf[chars_read - 2] == '\r';
	for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
	    if (*s == '\t')
		indent = (indent + 8) & ~7;
	    else
		indent++;
	}
	if (ISDIGIT (*s))
	  {
	    for (t = s + 1; ISDIGIT (*t) || *t == ',';  t++)
	      /* do nothing */ ;
	    if (*t == 'd' || *t == 'c' || *t == 'a')
	      {
		for (t++;  ISDIGIT (*t) || *t == ',';  t++)
		  /* do nothing */ ;
		for (; *t == ' ' || *t == '\t'; t++)
		  /* do nothing */ ;
		if (*t == '\r')
		  t++;
		this_is_a_command = (*t == '\n');
	      }
	  }
	if (! need_header
	    && first_command_line < 0
	    && ((ed_command_letter = get_ed_command_letter (s))
		|| this_is_a_command)) {
	    first_command_line = this_line;
	    first_ed_command_letter = ed_command_letter;
	    fcl_line = p_input_line;
	    p_indent = indent;		/* assume this for now */
	    p_strip_trailing_cr = strip_trailing_cr;
	}
	if (!stars_last_line && strnEQ(s, "*** ", 4))
	  {
	    fetchname (s+4, strippath, &p_name[OLD], &p_timestr[OLD],
		       &p_timestamp[OLD]);
	    need_header = false;
	  }
	else if (strnEQ(s, "+++ ", 4))
	  {
	    /* Swap with NEW below.  */
	    fetchname (s+4, strippath, &p_name[OLD], &p_timestr[OLD],
		       &p_timestamp[OLD]);
	    need_header = false;
	    p_strip_trailing_cr = strip_trailing_cr;
	  }
	else if (strnEQ(s, "Index:", 6))
	  {
	    fetchname (s+6, strippath, &p_name[INDEX], (char **) 0, NULL);
	    need_header = false;
	    p_strip_trailing_cr = strip_trailing_cr;
	  }
	else if (strnEQ(s, "Prereq:", 7))
	  {
	    for (t = s + 7;  ISSPACE ((unsigned char) *t);  t++)
	      /* do nothing */ ;
	    revision = t;
	    for (t = revision;  *t;  t++)
	      if (ISSPACE ((unsigned char) *t))
		{
		  char const *u;
		  for (u = t + 1;  ISSPACE ((unsigned char) *u);  u++)
		    /* do nothing */ ;
		  if (*u)
		    {
		      char numbuf[LINENUM_LENGTH_BOUND + 1];
		      say ("Prereq: with multiple words at line %s of patch\n",
			   format_linenum (numbuf, this_line));
		    }
		  break;
		}
	    if (t == revision)
		revision = 0;
	    else {
		char oldc = *t;
		*t = '\0';
		revision = xstrdup (revision);
		*t = oldc;
	    }
	  }
	else if (strnEQ (s, "diff --git ", 11))
	  {
	    char const *u;

	    if (extended_headers)
	      {
		p_start = this_line;
		p_sline = p_input_line;
		/* Patch contains no hunks; any diff type will do. */
		retval = UNI_DIFF;
		goto scan_exit;
	      }

	    for (i = OLD; i <= NEW; i++)
	      {
		free (p_name[i]);
		p_name[i] = 0;
	      }
	    if (! ((p_name[OLD] = parse_name (s + 11, strippath, &u))
		   && ISSPACE ((unsigned char) *u)
		   && (p_name[NEW] = parse_name (u, strippath, &u))
		   && (u = skip_spaces (u), ! *u)))
	      for (i = OLD; i <= NEW; i++)
		{
		  free (p_name[i]);
		  p_name[i] = 0;
		}
	    p_git_diff = true;
	    need_header = false;
	  }
	else if (p_git_diff && strnEQ (s, "index ", 6))
	  {
	    char const *u, *v;
	    if ((u = skip_hex_digits (s + 6))
		&& u[0] == '.' && u[1] == '.'
		&& (v = skip_hex_digits (u + 2))
		&& (! *v || ISSPACE ((unsigned char) *v)))
	      {
		get_sha1(&p_sha1[OLD], s + 6, u);
		get_sha1(&p_sha1[NEW], u + 2, v);
		p_says_nonexistent[OLD] = sha1_says_nonexistent (p_sha1[OLD]);
		p_says_nonexistent[NEW] = sha1_says_nonexistent (p_sha1[NEW]);
		if (*(v = skip_spaces (v)))
		  p_mode[OLD] = p_mode[NEW] = fetchmode (v);
		extended_headers = true;
	      }
	  }
	else if (p_git_diff && strnEQ (s, "old mode ", 9))
	  {
	    p_mode[OLD] = fetchmode (s + 9);
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "new mode ", 9))
	  {
	    p_mode[NEW] = fetchmode (s + 9);
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "deleted file mode ", 18))
	  {
	    p_mode[OLD] = fetchmode (s + 18);
	    p_says_nonexistent[NEW] = 2;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "new file mode ", 14))
	  {
	    p_mode[NEW] = fetchmode (s + 14);
	    p_says_nonexistent[OLD] = 2;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "rename from ", 12))
	  {
	    /* Git leaves out the prefix in the file name in this header,
	       so we can only ignore the file name.  */
	    p_rename[OLD] = true;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "rename to ", 10))
	  {
	    /* Git leaves out the prefix in the file name in this header,
	       so we can only ignore the file name.  */
	    p_rename[NEW] = true;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "copy from ", 10))
	  {
	    /* Git leaves out the prefix in the file name in this header,
	       so we can only ignore the file name.  */
	    p_copy[OLD] = true;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "copy to ", 8))
	  {
	    /* Git leaves out the prefix in the file name in this header,
	       so we can only ignore the file name.  */
	    p_copy[NEW] = true;
	    extended_headers = true;
	  }
	else if (p_git_diff && strnEQ (s, "GIT binary patch", 16))
	  {
	    p_start = this_line;
	    p_sline = p_input_line;
	    retval = GIT_BINARY_DIFF;
	    goto scan_exit;
	  }
	else
	  {
	    for (t = s;  t[0] == '-' && t[1] == ' ';  t += 2)
	      /* do nothing */ ;
	    if (strnEQ(t, "--- ", 4))
	      {
		struct timespec timestamp;
		timestamp.tv_sec = -1;
		fetchname (t+4, strippath, &p_name[NEW], &p_timestr[NEW],
			   &timestamp);
		need_header = false;
		if (timestamp.tv_sec != -1)
		  {
		    p_timestamp[NEW] = timestamp;
		    p_rfc934_nesting = (t - s) >> 1;
		  }
		p_strip_trailing_cr = strip_trailing_cr;
	      }
	  }
	if (need_header)
	  continue;
	if ((diff_type == NO_DIFF || diff_type == ED_DIFF) &&
	  first_command_line >= 0 &&
	  strEQ(s, ".\n") ) {
	    p_start = first_command_line;
	    p_sline = fcl_line;
	    retval = ED_DIFF;
	    goto scan_exit;
	}
	if ((diff_type == NO_DIFF || diff_type == UNI_DIFF)
	    && strnEQ(s, "@@ -", 4)) {

	    /* 'p_name', 'p_timestr', and 'p_timestamp' are backwards;
	       swap them.  */
	    struct timespec ti = p_timestamp[OLD];
	    p_timestamp[OLD] = p_timestamp[NEW];
	    p_timestamp[NEW] = ti;
	    t = p_name[OLD];
	    p_name[OLD] = p_name[NEW];
	    p_name[NEW] = t;
	    t = p_timestr[OLD];
	    p_timestr[OLD] = p_timestr[NEW];
	    p_timestr[NEW] = t;

	    s += 4;
	    if (s[0] == '0' && !ISDIGIT (s[1]))
	      p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD].tv_sec;
	    while (*s != ' ' && *s != '\n')
	      s++;
	    while (*s == ' ')
	      s++;
	    if (s[0] == '+' && s[1] == '0' && !ISDIGIT (s[2]))
	      p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW].tv_sec;
	    p_indent = indent;
	    p_start = this_line;
	    p_sline = p_input_line;
	    retval = UNI_DIFF;
	    if (! ((p_name[OLD] || ! p_timestamp[OLD].tv_sec)
		   && (p_name[NEW] || ! p_timestamp[NEW].tv_sec))
		&& ! p_name[INDEX] && need_header)
	      {
		char numbuf[LINENUM_LENGTH_BOUND + 1];
		say ("missing header for unified diff at line %s of patch\n",
		     format_linenum (numbuf, p_sline));
	      }
	    goto scan_exit;
	}
	stars_this_line = strnEQ(s, "********", 8);
	if ((diff_type == NO_DIFF
	     || diff_type == CONTEXT_DIFF
	     || diff_type == NEW_CONTEXT_DIFF)
	    && stars_last_line && indent_last_line == indent
	    && strnEQ (s, "*** ", 4)) {
	    s += 4;
	    if (s[0] == '0' && !ISDIGIT (s[1]))
	      p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD].tv_sec;
	    /* if this is a new context diff the character just before */
	    /* the newline is a '*'. */
	    while (*s != '\n')
		s++;
	    p_indent = indent;
	    p_strip_trailing_cr = strip_trailing_cr;
	    p_start = previous_line;
	    p_sline = p_input_line - 1;
	    retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);

	    {
	      /* Scan the first hunk to see whether the file contents
		 appear to have been deleted.  */
	      file_offset saved_p_base = p_base;
	      lin saved_p_bline = p_bline;
	      Fseek (pfp, previous_line, SEEK_SET);
	      p_input_line -= 2;
	      if (another_hunk (retval, false)
		  && ! p_repl_lines && p_newfirst == 1)
		p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW].tv_sec;
	      next_intuit_at (saved_p_base, saved_p_bline);
	    }

	    if (! ((p_name[OLD] || ! p_timestamp[OLD].tv_sec)
		   && (p_name[NEW] || ! p_timestamp[NEW].tv_sec))
		&& ! p_name[INDEX] && need_header)
	      {
		char numbuf[LINENUM_LENGTH_BOUND + 1];
		say ("missing header for context diff at line %s of patch\n",
		     format_linenum (numbuf, p_sline));
	      }
	    goto scan_exit;
	}
	if ((diff_type == NO_DIFF || diff_type == NORMAL_DIFF) &&
	  last_line_was_command &&
	  (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
	    p_start = previous_line;
	    p_sline = p_input_line - 1;
	    p_indent = indent;
	    retval = NORMAL_DIFF;
	    goto scan_exit;
	}
    }

  scan_exit:

    /* The old, new, or old and new file types may be defined.  When both
       file types are defined, make sure they are the same, or else assume
       we do not know the file type.  */
    file_type = p_mode[OLD] & S_IFMT;
    if (file_type)
      {
	mode_t new_file_type = p_mode[NEW] & S_IFMT;
	if (new_file_type && file_type != new_file_type)
	  file_type = 0;
      }
    else
      {
	file_type = p_mode[NEW] & S_IFMT;
	if (! file_type)
	  file_type = S_IFREG;
      }
    *p_file_type = file_type;

    /* To intuit 'inname', the name of the file to patch,
       use the algorithm specified by POSIX 1003.1-2001 XCU lines 25680-26599
       (with some modifications if posixly_correct is zero):

       - Take the old and new names from the context header if present,
	 and take the index name from the 'Index:' line if present and
	 if either the old and new names are both absent
	 or posixly_correct is nonzero.
	 Consider the file names to be in the order (old, new, index).
       - If some named files exist, use the first one if posixly_correct
	 is nonzero, the best one otherwise.
       - If patch_get is nonzero, and no named files exist,
	 but an RCS or SCCS master file exists,
	 use the first named file with an RCS or SCCS master.
       - If no named files exist, no RCS or SCCS master was found,
	 some names are given, posixly_correct is zero,
	 and the patch appears to create a file, then use the best name
	 requiring the creation of the fewest directories.
       - Otherwise, report failure by setting 'inname' to 0;
	 this causes our invoker to ask the user for a file name.  */

    i = NONE;

    if (!inname)
      {
	enum nametype i0 = NONE;

	if (! posixly_correct && (p_name[OLD] || p_name[NEW]) && p_name[INDEX])
	  {
	    free (p_name[INDEX]);
	    p_name[INDEX] = 0;
	  }

	for (i = OLD;  i <= INDEX;  i++)
	  if (p_name[i])
	    {
	      if (i0 != NONE && strcmp (p_name[i0], p_name[i]) == 0)
		{
		  /* It's the same name as before; reuse stat results.  */
		  stat_errno[i] = stat_errno[i0];
		  if (! stat_errno[i])
		    st[i] = st[i0];
		}
	      else
		{
		  stat_errno[i] = stat_file (p_name[i], &st[i]);
		  if (! stat_errno[i])
		    {
		      if (lookup_file_id (&st[i]) == DELETE_LATER)
			stat_errno[i] = ENOENT;
		      else if (posixly_correct && name_is_valid (p_name[i]))
			break;
		    }
		}
	      i0 = i;
	    }

	if (! posixly_correct)
	  {
	    /* The best of all existing files. */
	    i = best_name (p_name, stat_errno);

	    if (i == NONE && patch_get)
	      {
		enum nametype nope = NONE;

		for (i = OLD;  i <= INDEX;  i++)
		  if (p_name[i])
		    {
		      char const *cs;
		      char *getbuf;
		      char *diffbuf;
		      bool readonly = (outfile
				       && strcmp (outfile, p_name[i]) != 0);

		      if (nope == NONE || strcmp (p_name[nope], p_name[i]) != 0)
			{
			  cs = (version_controller
			        (p_name[i], readonly, (struct stat *) 0,
				 &getbuf, &diffbuf));
			  version_controlled[i] = !! cs;
			  if (cs)
			    {
			      if (version_get (p_name[i], cs, false, readonly,
					       getbuf, &st[i]))
				stat_errno[i] = 0;
			      else
				version_controlled[i] = 0;

			      free (getbuf);
			      free (diffbuf);

			      if (! stat_errno[i])
				break;
			    }
			}

		      nope = i;
		    }
	      }

	    if (i0 != NONE
		&& (i == NONE || (st[i].st_mode & S_IFMT) == file_type)
		&& maybe_reverse (p_name[i == NONE ? i0 : i], i == NONE,
				  i == NONE || st[i].st_size == 0)
		&& i == NONE)
	      i = i0;

	    if (i == NONE && p_says_nonexistent[reverse])
	      {
		int newdirs[3];
		int newdirs_min = INT_MAX;
		int distance_from_minimum[3];

		for (i = OLD;  i <= INDEX;  i++)
		  if (p_name[i])
		    {
		      newdirs[i] = (prefix_components (p_name[i], false)
				    - prefix_components (p_name[i], true));
		      if (newdirs[i] < newdirs_min)
			newdirs_min = newdirs[i];
		    }

		for (i = OLD;  i <= INDEX;  i++)
		  if (p_name[i])
		    distance_from_minimum[i] = newdirs[i] - newdirs_min;

		/* The best of the filenames which create the fewest directories. */
		i = best_name (p_name, distance_from_minimum);
	      }
	  }
      }

     if ((pch_rename () || pch_copy ())
 	&& ! inname
 	&& ! ((i == OLD || i == NEW) &&
	      p_name[reverse] && p_name[! reverse] &&
	      name_is_valid (p_name[reverse]) &&
 	      name_is_valid (p_name[! reverse])))
       {
 	say ("Cannot %s file without two valid file names\n", pch_rename () ? "rename" : "copy");
      }

    if (i == NONE)
      {
	if (inname)
	  {
	    inerrno = stat_file (inname, &instat);
	    if (inerrno || (instat.st_mode & S_IFMT) == file_type)
	      maybe_reverse (inname, inerrno, inerrno || instat.st_size == 0);
	  }
	else
          inerrno = -1;
      }
    else
      {
	inname = xstrdup (p_name[i]);
	inerrno = stat_errno[i];
	invc = version_controlled[i];
	instat = st[i];
      }

    return retval;
}


  Ins_GETVARIATION( TT_ExecContext  exc,
                    FT_Long*        args )
  {
    FT_UInt    num_axes = exc->face->blend->num_axis;
    FT_Fixed*  coords   = exc->face->blend->normalizedcoords;

    FT_UInt  i;

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

    for ( i = 0; i < num_axes; i++ )
      args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */
   }

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.


  Ins_GETVARIATION( TT_ExecContext  exc,
                    FT_Long*        args )
  {
    FT_UInt    num_axes = exc->face->blend->num_axis;
    FT_Fixed*  coords   = exc->face->blend->normalizedcoords;

    FT_UInt  i;

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

    if ( coords )
    {
      for ( i = 0; i < num_axes; i++ )
        args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */
    }
    else
    {
      for ( i = 0; i < num_axes; i++ )
        args[i] = 0;
    }
   }


void DelayedExecutor::delayedExecute(const QString &udi)
{
    Solid::Device device(udi);

     QString exec = m_service.exec();
     MacroExpander mx(device);
    mx.expandMacros(exec);

     KRun::runCommand(exec, QString(), m_service.icon(), 0);
     deleteLater();
}

An issue was discovered in soliduiserver/deviceserviceaction.cpp in KDE Plasma Workspace before 5.12.0. When a vfat thumbdrive that contains `` or $() in its volume label is plugged in and mounted through the device notifier, it's interpreted as a shell command, leading to a possibility of arbitrary command execution. An example of an offending volume label is "$(touch b)" -- this will create a file called b in the home folder.


void DelayedExecutor::delayedExecute(const QString &udi)
{
    Solid::Device device(udi);

     QString exec = m_service.exec();
     MacroExpander mx(device);
    mx.expandMacrosShellQuote(exec);

     KRun::runCommand(exec, QString(), m_service.icon(), 0);
     deleteLater();
}


uint NotificationsEngine::Notify(const QString &app_name, uint replaces_id,
                                 const QString &app_icon, const QString &summary, const QString &body,
                                 const QStringList &actions, const QVariantMap &hints, int timeout)
{
    uint partOf = 0;
    const QString appRealName = hints[QStringLiteral("x-kde-appname")].toString();
    const QString eventId = hints[QStringLiteral("x-kde-eventId")].toString();
    const bool skipGrouping = hints[QStringLiteral("x-kde-skipGrouping")].toBool();

    if (!replaces_id && m_activeNotifications.values().contains(app_name + summary) && !skipGrouping && !m_alwaysReplaceAppsList.contains(app_name)) {
        partOf = m_activeNotifications.key(app_name + summary).midRef(13).toUInt();
    }

     qDebug() << "Currrent active notifications:" << m_activeNotifications;
     qDebug() << "Guessing partOf as:" << partOf;
     qDebug() << " New Notification: " << summary << body << timeout << "& Part of:" << partOf;
    QString _body;

     if (partOf > 0) {
         const QString source = QStringLiteral("notification %1").arg(partOf);
         Plasma::DataContainer *container = containerForSource(source);
         if (container) {
            _body = container->data()[QStringLiteral("body")].toString();
            if (_body != body) {
                _body.append("\n").append(body);
            } else {
                _body = body;
             }

             replaces_id = partOf;
            CloseNotification(partOf);
        }
    }

    uint id = replaces_id ? replaces_id : m_nextId++;

    if (m_alwaysReplaceAppsList.contains(app_name)) {
        if (m_notificationsFromReplaceableApp.contains(app_name)) {
            id = m_notificationsFromReplaceableApp.value(app_name);
        } else {
            m_notificationsFromReplaceableApp.insert(app_name, id);
        }
    }

    QString appname_str = app_name;
    if (appname_str.isEmpty()) {
        appname_str = i18n("Unknown Application");
    }

    bool isPersistent = timeout == 0;

     const int AVERAGE_WORD_LENGTH = 6;
     const int WORD_PER_MINUTE = 250;
    int count = summary.length() + body.length();

        timeout = 60000 * count / AVERAGE_WORD_LENGTH / WORD_PER_MINUTE;

        timeout = 2000 + qMax(timeout, 3000);
    }

An issue was discovered in KDE Plasma Workspace before 5.12.0. dataengines/notifications/notificationsengine.cpp allows remote attackers to discover client IP addresses via a URL in a notification, as demonstrated by the src attribute of an IMG element.


uint NotificationsEngine::Notify(const QString &app_name, uint replaces_id,
                                 const QString &app_icon, const QString &summary, const QString &body,
                                 const QStringList &actions, const QVariantMap &hints, int timeout)
{
    uint partOf = 0;
    const QString appRealName = hints[QStringLiteral("x-kde-appname")].toString();
    const QString eventId = hints[QStringLiteral("x-kde-eventId")].toString();
    const bool skipGrouping = hints[QStringLiteral("x-kde-skipGrouping")].toBool();

    if (!replaces_id && m_activeNotifications.values().contains(app_name + summary) && !skipGrouping && !m_alwaysReplaceAppsList.contains(app_name)) {
        partOf = m_activeNotifications.key(app_name + summary).midRef(13).toUInt();
    }

     qDebug() << "Currrent active notifications:" << m_activeNotifications;
     qDebug() << "Guessing partOf as:" << partOf;
     qDebug() << " New Notification: " << summary << body << timeout << "& Part of:" << partOf;
    QString bodyFinal = NotificationSanitizer::parse(body);

     if (partOf > 0) {
         const QString source = QStringLiteral("notification %1").arg(partOf);
         Plasma::DataContainer *container = containerForSource(source);
         if (container) {
            const QString previousBody = container->data()[QStringLiteral("body")].toString();
            if (previousBody != bodyFinal) {
                // FIXME: This will just append the entire old XML document to another one, leading to:
                // <?xml>old
<?xml>new
                // It works but is not very clean.
                bodyFinal = previousBody + QStringLiteral("
") + bodyFinal;
             }

             replaces_id = partOf;
            CloseNotification(partOf);
        }
    }

    uint id = replaces_id ? replaces_id : m_nextId++;

    if (m_alwaysReplaceAppsList.contains(app_name)) {
        if (m_notificationsFromReplaceableApp.contains(app_name)) {
            id = m_notificationsFromReplaceableApp.value(app_name);
        } else {
            m_notificationsFromReplaceableApp.insert(app_name, id);
        }
    }

    QString appname_str = app_name;
    if (appname_str.isEmpty()) {
        appname_str = i18n("Unknown Application");
    }

    bool isPersistent = timeout == 0;

     const int AVERAGE_WORD_LENGTH = 6;
     const int WORD_PER_MINUTE = 250;
    int count = summary.length() + body.length() - strlen("<?xml version=\"1.0\">");

        timeout = 60000 * count / AVERAGE_WORD_LENGTH / WORD_PER_MINUTE;

        timeout = 2000 + qMax(timeout, 3000);
    }


uint NotificationsEngine::Notify(const QString &app_name, uint replaces_id,
                                 const QString &app_icon, const QString &summary, const QString &body,
                                 const QStringList &actions, const QVariantMap &hints, int timeout)
{
    uint partOf = 0;
    const QString appRealName = hints[QStringLiteral("x-kde-appname")].toString();
    const QString eventId = hints[QStringLiteral("x-kde-eventId")].toString();
    const bool skipGrouping = hints[QStringLiteral("x-kde-skipGrouping")].toBool();

    if (!replaces_id && m_activeNotifications.values().contains(app_name + summary) && !skipGrouping && !m_alwaysReplaceAppsList.contains(app_name)) {
        partOf = m_activeNotifications.key(app_name + summary).midRef(13).toUInt();
    }

    qDebug() << "Currrent active notifications:" << m_activeNotifications;
    qDebug() << "Guessing partOf as:" << partOf;
    qDebug() << " New Notification: " << summary << body << timeout << "& Part of:" << partOf;
    QString _body;

    if (partOf > 0) {
        const QString source = QStringLiteral("notification %1").arg(partOf);
        Plasma::DataContainer *container = containerForSource(source);
        if (container) {
            _body = container->data()[QStringLiteral("body")].toString();
            if (_body != body) {
                _body.append("\n").append(body);
            } else {
                _body = body;
            }

            replaces_id = partOf;

            CloseNotification(partOf);
        }
    }

    uint id = replaces_id ? replaces_id : m_nextId++;

    if (m_alwaysReplaceAppsList.contains(app_name)) {
        if (m_notificationsFromReplaceableApp.contains(app_name)) {
            id = m_notificationsFromReplaceableApp.value(app_name);
        } else {
            m_notificationsFromReplaceableApp.insert(app_name, id);
        }
    }

    QString appname_str = app_name;
    if (appname_str.isEmpty()) {
        appname_str = i18n("Unknown Application");
    }

    bool isPersistent = timeout == 0;

    const int AVERAGE_WORD_LENGTH = 6;
    const int WORD_PER_MINUTE = 250;
    int count = summary.length() + body.length();

    if (timeout <= 0) {
        timeout = 60000 * count / AVERAGE_WORD_LENGTH / WORD_PER_MINUTE;

        timeout = 2000 + qMax(timeout, 3000);
    }

    const QString source = QStringLiteral("notification %1").arg(id);
     const QString source = QStringLiteral("notification %1").arg(id);

     QString bodyFinal = (partOf == 0 ? body : _body);
    bodyFinal = bodyFinal.trimmed();
    bodyFinal = bodyFinal.replace(QLatin1String("\n"), QLatin1String("
"));
    bodyFinal = bodyFinal.simplified();
    bodyFinal.replace(QRegularExpression(QStringLiteral("
\\s*
(\\s|
)*")), QLatin1String("
"));
    bodyFinal.replace(QRegularExpression(QStringLiteral("&(?!(?:apos|quot|[gl]t|amp);|#)")), QLatin1String("&"));
    bodyFinal.replace(QLatin1String("'"), QChar('\''));

     Plasma::DataEngine::Data notificationData;
     notificationData.insert(QStringLiteral("id"), QString::number(id));
    bodyFinal = bodyFinal.simplified();
    bodyFinal.replace(QRegularExpression(QStringLiteral("
\\s*
(\\s|
)*")), QLatin1String("
"));
    bodyFinal.replace(QRegularExpression(QStringLiteral("&(?!(?:apos|quot|[gl]t|amp);|#)")), QLatin1String("&"));
    bodyFinal.replace(QLatin1String("'"), QChar('\''));

    Plasma::DataEngine::Data notificationData;
    notificationData.insert(QStringLiteral("id"), QString::number(id));
    notificationData.insert(QStringLiteral("eventId"), eventId);
    notificationData.insert(QStringLiteral("appName"), appname_str);
    notificationData.insert(QStringLiteral("appIcon"), app_icon);
    notificationData.insert(QStringLiteral("summary"), summary);
    notificationData.insert(QStringLiteral("body"), bodyFinal);
    notificationData.insert(QStringLiteral("actions"), actions);
    notificationData.insert(QStringLiteral("isPersistent"), isPersistent);
    notificationData.insert(QStringLiteral("expireTimeout"), timeout);

    bool configurable = false;
    if (!appRealName.isEmpty()) {

        if (m_configurableApplications.contains(appRealName)) {
            configurable = m_configurableApplications.value(appRealName);
        } else {
            QScopedPointer<KConfig> config(new KConfig(appRealName + QStringLiteral(".notifyrc"), KConfig::NoGlobals));
            config->addConfigSources(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
                                     QStringLiteral("knotifications5/") + appRealName + QStringLiteral(".notifyrc")));

            const QRegularExpression regexp(QStringLiteral("^Event/([^/]*)$"));
            configurable = !config->groupList().filter(regexp).isEmpty();
            m_configurableApplications.insert(appRealName, configurable);
        }
    }
    notificationData.insert(QStringLiteral("appRealName"), appRealName);
    notificationData.insert(QStringLiteral("configurable"), configurable);

    QImage image;
    if (hints.contains(QStringLiteral("image-data"))) {
        QDBusArgument arg = hints[QStringLiteral("image-data")].value<QDBusArgument>();
        image = decodeNotificationSpecImageHint(arg);
    } else if (hints.contains(QStringLiteral("image_data"))) {
        QDBusArgument arg = hints[QStringLiteral("image_data")].value<QDBusArgument>();
        image = decodeNotificationSpecImageHint(arg);
    } else if (hints.contains(QStringLiteral("image-path"))) {
        QString path = findImageForSpecImagePath(hints[QStringLiteral("image-path")].toString());
        if (!path.isEmpty()) {
            image.load(path);
        }
    } else if (hints.contains(QStringLiteral("image_path"))) {
        QString path = findImageForSpecImagePath(hints[QStringLiteral("image_path")].toString());
        if (!path.isEmpty()) {
            image.load(path);
        }
    } else if (hints.contains(QStringLiteral("icon_data"))) {
        QDBusArgument arg = hints[QStringLiteral("icon_data")].value<QDBusArgument>();
        image = decodeNotificationSpecImageHint(arg);
    }
    notificationData.insert(QStringLiteral("image"), image.isNull() ? QVariant() : image);

    if (hints.contains(QStringLiteral("urgency"))) {
        notificationData.insert(QStringLiteral("urgency"), hints[QStringLiteral("urgency")].toInt());
    }

    setData(source, notificationData);

    m_activeNotifications.insert(source, app_name + summary);

    return id;
}


uint NotificationsEngine::Notify(const QString &app_name, uint replaces_id,
                                 const QString &app_icon, const QString &summary, const QString &body,
                                 const QStringList &actions, const QVariantMap &hints, int timeout)
{
    uint partOf = 0;
    const QString appRealName = hints[QStringLiteral("x-kde-appname")].toString();
    const QString eventId = hints[QStringLiteral("x-kde-eventId")].toString();
    const bool skipGrouping = hints[QStringLiteral("x-kde-skipGrouping")].toBool();

    if (!replaces_id && m_activeNotifications.values().contains(app_name + summary) && !skipGrouping && !m_alwaysReplaceAppsList.contains(app_name)) {
        partOf = m_activeNotifications.key(app_name + summary).midRef(13).toUInt();
    }

    qDebug() << "Currrent active notifications:" << m_activeNotifications;
    qDebug() << "Guessing partOf as:" << partOf;
    qDebug() << " New Notification: " << summary << body << timeout << "& Part of:" << partOf;
    QString _body;

    if (partOf > 0) {
        const QString source = QStringLiteral("notification %1").arg(partOf);
        Plasma::DataContainer *container = containerForSource(source);
        if (container) {
            _body = container->data()[QStringLiteral("body")].toString();
            if (_body != body) {
                _body.append("\n").append(body);
            } else {
                _body = body;
            }

            replaces_id = partOf;

            CloseNotification(partOf);
        }
    }

    uint id = replaces_id ? replaces_id : m_nextId++;

    if (m_alwaysReplaceAppsList.contains(app_name)) {
        if (m_notificationsFromReplaceableApp.contains(app_name)) {
            id = m_notificationsFromReplaceableApp.value(app_name);
        } else {
            m_notificationsFromReplaceableApp.insert(app_name, id);
        }
    }

    QString appname_str = app_name;
    if (appname_str.isEmpty()) {
        appname_str = i18n("Unknown Application");
    }

    bool isPersistent = timeout == 0;

    const int AVERAGE_WORD_LENGTH = 6;
    const int WORD_PER_MINUTE = 250;
    int count = summary.length() + body.length();

    if (timeout <= 0) {
        timeout = 60000 * count / AVERAGE_WORD_LENGTH / WORD_PER_MINUTE;

        timeout = 2000 + qMax(timeout, 3000);
    }

    const QString source = QStringLiteral("notification %1").arg(id);
     const QString source = QStringLiteral("notification %1").arg(id);

     QString bodyFinal = (partOf == 0 ? body : _body);
    bodyFinal = NotificationSanitizer::parse(bodyFinal);

     Plasma::DataEngine::Data notificationData;
     notificationData.insert(QStringLiteral("id"), QString::number(id));
    bodyFinal = bodyFinal.simplified();
    bodyFinal.replace(QRegularExpression(QStringLiteral("
\\s*
(\\s|
)*")), QLatin1String("
"));
    bodyFinal.replace(QRegularExpression(QStringLiteral("&(?!(?:apos|quot|[gl]t|amp);|#)")), QLatin1String("&"));
    bodyFinal.replace(QLatin1String("'"), QChar('\''));

    Plasma::DataEngine::Data notificationData;
    notificationData.insert(QStringLiteral("id"), QString::number(id));
    notificationData.insert(QStringLiteral("eventId"), eventId);
    notificationData.insert(QStringLiteral("appName"), appname_str);
    notificationData.insert(QStringLiteral("appIcon"), app_icon);
    notificationData.insert(QStringLiteral("summary"), summary);
    notificationData.insert(QStringLiteral("body"), bodyFinal);
    notificationData.insert(QStringLiteral("actions"), actions);
    notificationData.insert(QStringLiteral("isPersistent"), isPersistent);
    notificationData.insert(QStringLiteral("expireTimeout"), timeout);

    bool configurable = false;
    if (!appRealName.isEmpty()) {

        if (m_configurableApplications.contains(appRealName)) {
            configurable = m_configurableApplications.value(appRealName);
        } else {
            QScopedPointer<KConfig> config(new KConfig(appRealName + QStringLiteral(".notifyrc"), KConfig::NoGlobals));
            config->addConfigSources(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
                                     QStringLiteral("knotifications5/") + appRealName + QStringLiteral(".notifyrc")));

            const QRegularExpression regexp(QStringLiteral("^Event/([^/]*)$"));
            configurable = !config->groupList().filter(regexp).isEmpty();
            m_configurableApplications.insert(appRealName, configurable);
        }
    }
    notificationData.insert(QStringLiteral("appRealName"), appRealName);
    notificationData.insert(QStringLiteral("configurable"), configurable);

    QImage image;
    if (hints.contains(QStringLiteral("image-data"))) {
        QDBusArgument arg = hints[QStringLiteral("image-data")].value<QDBusArgument>();
        image = decodeNotificationSpecImageHint(arg);
    } else if (hints.contains(QStringLiteral("image_data"))) {
        QDBusArgument arg = hints[QStringLiteral("image_data")].value<QDBusArgument>();
        image = decodeNotificationSpecImageHint(arg);
    } else if (hints.contains(QStringLiteral("image-path"))) {
        QString path = findImageForSpecImagePath(hints[QStringLiteral("image-path")].toString());
        if (!path.isEmpty()) {
            image.load(path);
        }
    } else if (hints.contains(QStringLiteral("image_path"))) {
        QString path = findImageForSpecImagePath(hints[QStringLiteral("image_path")].toString());
        if (!path.isEmpty()) {
            image.load(path);
        }
    } else if (hints.contains(QStringLiteral("icon_data"))) {
        QDBusArgument arg = hints[QStringLiteral("icon_data")].value<QDBusArgument>();
        image = decodeNotificationSpecImageHint(arg);
    }
    notificationData.insert(QStringLiteral("image"), image.isNull() ? QVariant() : image);

    if (hints.contains(QStringLiteral("urgency"))) {
        notificationData.insert(QStringLiteral("urgency"), hints[QStringLiteral("urgency")].toInt());
    }

    setData(source, notificationData);

    m_activeNotifications.insert(source, app_name + summary);

    return id;
}


dns_stricmp(const char* str1, const char* str2)
{
  char c1, c2;
  *----------------------------------------------------------------------------*/

 /* DNS variables */
static struct udp_pcb        *dns_pcb;
 static u8_t                   dns_seqno;
 static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
 static struct dns_req_entry   dns_requests[DNS_MAX_REQUESTS];
        if (c1_upc != c2_upc) {
          /* still not equal */
          /* don't care for < or > */
          return 1;
        }
      } else {
        /* characters are not equal but none is in the alphabet range */
        return 1;
      }

resolv.c in the DNS resolver in uIP, and dns.c in the DNS resolver in lwIP 1.4.1 and earlier, does not use random values for ID fields and source ports of DNS query packets, which makes it easier for man-in-the-middle attackers to conduct cache-poisoning attacks via spoofed reply packets.


dns_stricmp(const char* str1, const char* str2)
{
  char c1, c2;
  *----------------------------------------------------------------------------*/

 /* DNS variables */
static struct udp_pcb        *dns_pcbs[DNS_MAX_SOURCE_PORTS];
#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
static u8_t                   dns_last_pcb_idx;
#endif
 static u8_t                   dns_seqno;
 static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
 static struct dns_req_entry   dns_requests[DNS_MAX_REQUESTS];
        if (c1_upc != c2_upc) {
          /* still not equal */
          /* don't care for < or > */
          return 1;
        }
      } else {
        /* characters are not equal but none is in the alphabet range */
        return 1;
      }