static Image *ReadMATImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
  Image *image, *image2=NULL,
   *rotated_image;
  register Quantum *q;

  unsigned int status;
  MATHeader MATLAB_HDR;
  size_t size;
  size_t CellType;
  QuantumInfo *quantum_info;
  ImageInfo *clone_info;
  int i;
  ssize_t ldblk;
  unsigned char *BImgBuff = NULL;
  double MinVal, MaxVal;
  unsigned z, z2;
  unsigned Frames;
  int logging;
  int sample_size;
  MagickOffsetType filepos=0x80;
  BlobInfo *blob;
  size_t one;

  unsigned int (*ReadBlobXXXLong)(Image *image);
  unsigned short (*ReadBlobXXXShort)(Image *image);
  void (*ReadBlobDoublesXXX)(Image * image, size_t len, double *data);
  void (*ReadBlobFloatsXXX)(Image * image, size_t len, float *data);

  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter");

  /*
     Open image file.
   */
  image = AcquireImage(image_info,exception);

  status = OpenBlob(image_info, image, ReadBinaryBlobMode, exception);
  if (status == MagickFalse)
    {
      image=DestroyImageList(image);
      return((Image *) NULL);
    }
  /*
     Read MATLAB image.
   */
  clone_info=CloneImageInfo(image_info);
  if(ReadBlob(image,124,(unsigned char *) &MATLAB_HDR.identific) != 124)
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
  MATLAB_HDR.Version = ReadBlobLSBShort(image);
  if(ReadBlob(image,2,(unsigned char *) &MATLAB_HDR.EndianIndicator) != 2)
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");

  if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),"  Endian %c%c",
        MATLAB_HDR.EndianIndicator[0],MATLAB_HDR.EndianIndicator[1]);
  if (!strncmp(MATLAB_HDR.EndianIndicator, "IM", 2))
  {
    ReadBlobXXXLong = ReadBlobLSBLong;
    ReadBlobXXXShort = ReadBlobLSBShort;
    ReadBlobDoublesXXX = ReadBlobDoublesLSB;
    ReadBlobFloatsXXX = ReadBlobFloatsLSB;
    image->endian = LSBEndian;
  }
  else if (!strncmp(MATLAB_HDR.EndianIndicator, "MI", 2))
  {
    ReadBlobXXXLong = ReadBlobMSBLong;
    ReadBlobXXXShort = ReadBlobMSBShort;
    ReadBlobDoublesXXX = ReadBlobDoublesMSB;
    ReadBlobFloatsXXX = ReadBlobFloatsMSB;
    image->endian = MSBEndian;
  }
  else
    goto MATLAB_KO;    /* unsupported endian */

  if (strncmp(MATLAB_HDR.identific, "MATLAB", 6))
MATLAB_KO: ThrowReaderException(CorruptImageError,"ImproperImageHeader");

  filepos = TellBlob(image);
  while(!EOFBlob(image)) /* object parser loop */
  {
    Frames = 1;
    (void) SeekBlob(image,filepos,SEEK_SET);
    /* printf("pos=%X\n",TellBlob(image)); */

    MATLAB_HDR.DataType = ReadBlobXXXLong(image);
    if(EOFBlob(image)) break;
    MATLAB_HDR.ObjectSize = ReadBlobXXXLong(image);
    if(EOFBlob(image)) break;
    filepos += MATLAB_HDR.ObjectSize + 4 + 4;

    image2 = image;
#if defined(MAGICKCORE_ZLIB_DELEGATE)
    if(MATLAB_HDR.DataType == miCOMPRESSED)
    {
      image2 = DecompressBlock(image,MATLAB_HDR.ObjectSize,clone_info,exception);
      if(image2==NULL) continue;
      MATLAB_HDR.DataType = ReadBlobXXXLong(image2); /* replace compressed object type. */
    }
#endif

    if(MATLAB_HDR.DataType!=miMATRIX) continue;  /* skip another objects. */

    MATLAB_HDR.unknown1 = ReadBlobXXXLong(image2);
    MATLAB_HDR.unknown2 = ReadBlobXXXLong(image2);

    MATLAB_HDR.unknown5 = ReadBlobXXXLong(image2);
    MATLAB_HDR.StructureClass = MATLAB_HDR.unknown5 & 0xFF;
    MATLAB_HDR.StructureFlag = (MATLAB_HDR.unknown5>>8) & 0xFF;

    MATLAB_HDR.unknown3 = ReadBlobXXXLong(image2);
    if(image!=image2)
      MATLAB_HDR.unknown4 = ReadBlobXXXLong(image2);  /* ??? don't understand why ?? */
    MATLAB_HDR.unknown4 = ReadBlobXXXLong(image2);
    MATLAB_HDR.DimFlag = ReadBlobXXXLong(image2);
    MATLAB_HDR.SizeX = ReadBlobXXXLong(image2);
    MATLAB_HDR.SizeY = ReadBlobXXXLong(image2);

    switch(MATLAB_HDR.DimFlag)
    {
      case  8: z2=z=1; break;      /* 2D matrix*/
      case 12: z2=z = ReadBlobXXXLong(image2);  /* 3D matrix RGB*/
           (void) ReadBlobXXXLong(image2);
         if(z!=3) ThrowReaderException(CoderError, "MultidimensionalMatricesAreNotSupported");
         break;
      case 16: z2=z = ReadBlobXXXLong(image2);  /* 4D matrix animation */
         if(z!=3 && z!=1)
            ThrowReaderException(CoderError, "MultidimensionalMatricesAreNotSupported");
           Frames = ReadBlobXXXLong(image2);
         break;
      default: ThrowReaderException(CoderError, "MultidimensionalMatricesAreNotSupported");
    }

    MATLAB_HDR.Flag1 = ReadBlobXXXShort(image2);
    MATLAB_HDR.NameFlag = ReadBlobXXXShort(image2);

    if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
          "MATLAB_HDR.StructureClass %d",MATLAB_HDR.StructureClass);
    if (MATLAB_HDR.StructureClass != mxCHAR_CLASS &&
        MATLAB_HDR.StructureClass != mxSINGLE_CLASS &&    /* float + complex float */
        MATLAB_HDR.StructureClass != mxDOUBLE_CLASS &&    /* double + complex double */
        MATLAB_HDR.StructureClass != mxINT8_CLASS &&
        MATLAB_HDR.StructureClass != mxUINT8_CLASS &&    /* uint8 + uint8 3D */
        MATLAB_HDR.StructureClass != mxINT16_CLASS &&
        MATLAB_HDR.StructureClass != mxUINT16_CLASS &&    /* uint16 + uint16 3D */
        MATLAB_HDR.StructureClass != mxINT32_CLASS &&
        MATLAB_HDR.StructureClass != mxUINT32_CLASS &&    /* uint32 + uint32 3D */
        MATLAB_HDR.StructureClass != mxINT64_CLASS &&
        MATLAB_HDR.StructureClass != mxUINT64_CLASS)    /* uint64 + uint64 3D */
      ThrowReaderException(CoderError,"UnsupportedCellTypeInTheMatrix");

    switch (MATLAB_HDR.NameFlag)
    {
      case 0:
        size = ReadBlobXXXLong(image2);  /* Object name string size */
        size = 4 * (ssize_t) ((size + 3 + 1) / 4);
        (void) SeekBlob(image2, size, SEEK_CUR);
        break;
      case 1:
      case 2:
      case 3:
      case 4:
        (void) ReadBlob(image2, 4, (unsigned char *) &size); /* Object name string */
        break;
      default:
        goto MATLAB_KO;
    }

    CellType = ReadBlobXXXLong(image2);    /* Additional object type */
    if (logging)
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "MATLAB_HDR.CellType: %.20g",(double) CellType);

    (void) ReadBlob(image2, 4, (unsigned char *) &size);     /* data size */

    NEXT_FRAME:
    switch (CellType)
    {
      case miINT8:
      case miUINT8:
        sample_size = 8;
        if(MATLAB_HDR.StructureFlag & FLAG_LOGICAL)
          image->depth = 1;
        else
          image->depth = 8;         /* Byte type cell */
        ldblk = (ssize_t) MATLAB_HDR.SizeX;
        break;
      case miINT16:
      case miUINT16:
        sample_size = 16;
        image->depth = 16;        /* Word type cell */
        ldblk = (ssize_t) (2 * MATLAB_HDR.SizeX);
        break;
      case miINT32:
      case miUINT32:
        sample_size = 32;
        image->depth = 32;        /* Dword type cell */
        ldblk = (ssize_t) (4 * MATLAB_HDR.SizeX);
        break;
      case miINT64:
      case miUINT64:
        sample_size = 64;
        image->depth = 64;        /* Qword type cell */
        ldblk = (ssize_t) (8 * MATLAB_HDR.SizeX);
        break;
      case miSINGLE:
        sample_size = 32;
        image->depth = 32;        /* double type cell */
        (void) SetImageOption(clone_info,"quantum:format","floating-point");
        if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
  {              /* complex float type cell */
  }
        ldblk = (ssize_t) (4 * MATLAB_HDR.SizeX);
        break;
      case miDOUBLE:
        sample_size = 64;
        image->depth = 64;        /* double type cell */
        (void) SetImageOption(clone_info,"quantum:format","floating-point");
DisableMSCWarning(4127)
        if (sizeof(double) != 8)
RestoreMSCWarning
          ThrowReaderException(CoderError, "IncompatibleSizeOfDouble");
        if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
  {                         /* complex double type cell */
  }
        ldblk = (ssize_t) (8 * MATLAB_HDR.SizeX);
        break;
      default:
        ThrowReaderException(CoderError, "UnsupportedCellTypeInTheMatrix");
    }
    (void) sample_size;
    image->columns = MATLAB_HDR.SizeX;
    image->rows = MATLAB_HDR.SizeY;
    quantum_info=AcquireQuantumInfo(clone_info,image);
    if (quantum_info == (QuantumInfo *) NULL)
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    one=1;
    image->colors = one << image->depth;
    if (image->columns == 0 || image->rows == 0)
      goto MATLAB_KO;
    /* Image is gray when no complex flag is set and 2D Matrix */
    if ((MATLAB_HDR.DimFlag == 8) &&
        ((MATLAB_HDR.StructureFlag & FLAG_COMPLEX) == 0))
      {
        image->type=GrayscaleType;
        SetImageColorspace(image,GRAYColorspace,exception);
      }

    /*
      If ping is true, then only set image size and colors without
      reading any image data.
    */
    if (image_info->ping)
    {
      size_t temp = image->columns;
      image->columns = image->rows;
      image->rows = temp;
      goto done_reading; /* !!!!!! BAD  !!!! */
    }
    status=SetImageExtent(image,image->columns,image->rows,exception);
    if (status == MagickFalse)
      return(DestroyImageList(image));

  /* ----- Load raster data ----- */
    BImgBuff = (unsigned char *) AcquireQuantumMemory((size_t) (ldblk),sizeof(double));    /* Ldblk was set in the check phase */
    if (BImgBuff == NULL)
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");

    MinVal = 0;
    MaxVal = 0;
    if (CellType==miDOUBLE || CellType==miSINGLE)        /* Find Min and Max Values for floats */
    {
      CalcMinMax(image2, image_info->endian,  MATLAB_HDR.SizeX, MATLAB_HDR.SizeY, CellType, ldblk, BImgBuff, &quantum_info->minimum, &quantum_info->maximum);
    }

    /* Main loop for reading all scanlines */
    if(z==1) z=0; /* read grey scanlines */
    /* else read color scanlines */
    do
    {
      for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
      {
        q=GetAuthenticPixels(image,0,MATLAB_HDR.SizeY-i-1,image->columns,1,exception);
        if (q == (Quantum *) NULL)
  {
    if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
              "  MAT set image pixels returns unexpected NULL on a row %u.", (unsigned)(MATLAB_HDR.SizeY-i-1));
    goto done_reading;    /* Skip image rotation, when cannot set image pixels    */
  }
        if(ReadBlob(image2,ldblk,(unsigned char *)BImgBuff) != (ssize_t) ldblk)
  {
    if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
             "  MAT cannot read scanrow %u from a file.", (unsigned)(MATLAB_HDR.SizeY-i-1));
    goto ExitLoop;
  }
        if((CellType==miINT8 || CellType==miUINT8) && (MATLAB_HDR.StructureFlag & FLAG_LOGICAL))
        {
          FixLogical((unsigned char *)BImgBuff,ldblk);
          if(ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,z2qtype[z],BImgBuff,exception) <= 0)
    {
ImportQuantumPixelsFailed:
      if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
              "  MAT failed to ImportQuantumPixels for a row %u", (unsigned)(MATLAB_HDR.SizeY-i-1));
      break;
    }
        }
        else
        {
          if(ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,z2qtype[z],BImgBuff,exception) <= 0)
      goto ImportQuantumPixelsFailed;

          if (z<=1 &&       /* fix only during a last pass z==0 || z==1 */
          (CellType==miINT8 || CellType==miINT16 || CellType==miINT32 || CellType==miINT64))
      FixSignedValues(image,q,MATLAB_HDR.SizeX);
        }

        if (!SyncAuthenticPixels(image,exception))
  {
    if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
            "  MAT failed to sync image pixels for a row %u", (unsigned)(MATLAB_HDR.SizeY-i-1));
    goto ExitLoop;
  }
      }
    } while(z-- >= 2);
    quantum_info=DestroyQuantumInfo(quantum_info);
ExitLoop:

    /* Read complex part of numbers here */
    if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
    {        /* Find Min and Max Values for complex parts of floats */
      CellType = ReadBlobXXXLong(image2);    /* Additional object type */
      i = ReadBlobXXXLong(image2);           /* size of a complex part - toss away*/

      if (CellType==miDOUBLE || CellType==miSINGLE)
      {
        CalcMinMax(image2,  image_info->endian, MATLAB_HDR.SizeX, MATLAB_HDR.SizeY, CellType, ldblk, BImgBuff, &MinVal, &MaxVal);
      }

      if (CellType==miDOUBLE)
        for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
  {
          ReadBlobDoublesXXX(image2, ldblk, (double *)BImgBuff);
          InsertComplexDoubleRow(image, (double *)BImgBuff, i, MinVal, MaxVal,
            exception);
  }

      if (CellType==miSINGLE)
        for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
  {
          ReadBlobFloatsXXX(image2, ldblk, (float *)BImgBuff);
          InsertComplexFloatRow(image,(float *)BImgBuff,i,MinVal,MaxVal,
            exception);
  }
    }

      /* Image is gray when no complex flag is set and 2D Matrix AGAIN!!! */
    if ((MATLAB_HDR.DimFlag == 8) &&
        ((MATLAB_HDR.StructureFlag & FLAG_COMPLEX) == 0))
      image->type=GrayscaleType;
    if (image->depth == 1)
      image->type=BilevelType;

    if(image2==image)
        image2 = NULL;    /* Remove shadow copy to an image before rotation. */

      /*  Rotate image. */
    rotated_image = RotateImage(image, 90.0, exception);
    if (rotated_image != (Image *) NULL)
    {
        /* Remove page offsets added by RotateImage */
      rotated_image->page.x=0;
      rotated_image->page.y=0;

      blob = rotated_image->blob;
      rotated_image->blob = image->blob;
      rotated_image->colors = image->colors;
      image->blob = blob;
      AppendImageToList(&image,rotated_image);
      DeleteImageFromList(&image);
    }

done_reading:

    if(image2!=NULL)
      if(image2!=image)
      {
        DeleteImageFromList(&image2);
  if(clone_info)
  {
          if(clone_info->file)
    {
            fclose(clone_info->file);
            clone_info->file = NULL;
            (void) remove_utf8(clone_info->filename);
    }
        }
      }

      /* Allocate next image structure. */
    AcquireNextImage(image_info,image,exception);
    if (image->next == (Image *) NULL) break;
    image=SyncNextImageInList(image);
    image->columns=image->rows=0;
    image->colors=0;

      /* row scan buffer is no longer needed */
    RelinquishMagickMemory(BImgBuff);
    BImgBuff = NULL;

    if(--Frames>0)
    {
      z = z2;
      if(image2==NULL) image2 = image;
      goto NEXT_FRAME;
    }
    if ((image2!=NULL) && (image2!=image))   /* Does shadow temporary decompressed image exist? */
      {
/*  CloseBlob(image2); */
        DeleteImageFromList(&image2);
        if(clone_info)
        {
          if(clone_info->file)
          {
            fclose(clone_info->file);
            clone_info->file = NULL;
            (void) remove_utf8(clone_info->filename);
          }
        }
        }
  }

  clone_info=DestroyImageInfo(clone_info);
  RelinquishMagickMemory(BImgBuff);
  CloseBlob(image);

  {
    Image *p;
    ssize_t scene=0;

    /*
      Rewind list, removing any empty images while rewinding.
    */
    p=image;
    image=NULL;
    while (p != (Image *) NULL)
      {
        Image *tmp=p;
        if ((p->rows == 0) || (p->columns == 0)) {
          p=p->previous;
          DeleteImageFromList(&tmp);
        } else {
          image=p;
          p=p->previous;
        }
      }

    /*
      Fix scene numbers
    */
    for (p=image; p != (Image *) NULL; p=p->next)
      p->scene=scene++;
  }

  if(clone_info != NULL)  /* cleanup garbage file from compression */
  {
    if(clone_info->file)
    {
      fclose(clone_info->file);
      clone_info->file = NULL;
      (void) remove_utf8(clone_info->filename);
    }
    DestroyImageInfo(clone_info);
    clone_info = NULL;
  }
  if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return");
  if(image==NULL)
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
  return (image);
}


TfLiteTensor* GetVariableInput(TfLiteContext* context, const TfLiteNode* node,
                               int index) {
  TfLiteTensor* tensor = GetMutableInput(context, node, index);
  return tensor->is_variable ? tensor : nullptr;
}

Fix a null pointer exception in SVDF

This is due to not checking that `GetVariableInput` returns non-null tensor.

Also fix a potential null pointer exception in `GetVariableInput`.

PiperOrigin-RevId: 385160147
Change-Id: Iadf3f0705b036a9014d27caa5a8bbd91f4c4c401


TfLiteTensor* GetVariableInput(TfLiteContext* context, const TfLiteNode* node,
                               int index) {
  TfLiteTensor* tensor = GetMutableInput(context, node, index);
  if (tensor == nullptr) return nullptr;
  return tensor->is_variable ? tensor : nullptr;
}


parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
{
  parser_loop_statement_t loop;

  JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FOR);
  lexer_next_token (context_p);

#if JERRY_ESNEXT
  bool is_for_await = false;

  if (context_p->token.type == LEXER_KEYW_AWAIT)
  {
    if (JERRY_UNLIKELY (context_p->token.lit_location.status_flags & LEXER_LIT_LOCATION_HAS_ESCAPE))
    {
      parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
    }
    lexer_next_token (context_p);
    is_for_await = true;
  }
#endif /* JERRY_ESNEXT */

  if (context_p->token.type != LEXER_LEFT_PAREN)
  {
#if JERRY_ESNEXT
    if (context_p->token.type == LEXER_LITERAL
        && context_p->token.keyword_type == LEXER_KEYW_AWAIT
        && !(context_p->token.lit_location.status_flags & LEXER_LIT_LOCATION_HAS_ESCAPE))
    {
      parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_ASYNC);
    }
#endif /* JERRY_ESNEXT */
    parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
  }

  if (context_p->next_scanner_info_p->source_p == context_p->source_p)
  {
    parser_for_in_of_statement_t for_in_of_statement;
    scanner_location_t start_location, end_location;

#if JERRY_ESNEXT
    JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN
                  || context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_OF);

    bool is_for_in = (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN);
    end_location = ((scanner_location_info_t *) context_p->next_scanner_info_p)->location;

    scanner_release_next (context_p, sizeof (scanner_location_info_t));

    scanner_get_location (&start_location, context_p);
    lexer_next_token (context_p);

    uint8_t token_type = LEXER_EOS;
    bool has_context = false;

    if (context_p->token.type == LEXER_KEYW_VAR
        || context_p->token.type == LEXER_KEYW_LET
        || context_p->token.type == LEXER_KEYW_CONST)
    {
      token_type = context_p->token.type;
      has_context = context_p->next_scanner_info_p->source_p == context_p->source_p;
      JERRY_ASSERT (!has_context || context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
      scanner_get_location (&start_location, context_p);

      /* TODO: remove this after the pre-scanner supports strict mode detection. */
      if (context_p->next_scanner_info_p->source_p == context_p->source_p
          && context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION)
      {
        scanner_release_next (context_p, sizeof (scanner_info_t));
      }
    }
    else if (context_p->token.type == LEXER_LITERAL && lexer_token_is_let (context_p))
    {
      if (context_p->next_scanner_info_p->source_p == context_p->source_p
          && context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION)
      {
        scanner_release_next (context_p, sizeof (scanner_info_t));
      }
      else
      {
        token_type = LEXER_KEYW_LET;
        has_context = (context_p->next_scanner_info_p->source_p == context_p->source_p);
        scanner_get_location (&start_location, context_p);
      }
    }

    if (has_context)
    {
      has_context = parser_push_block_context (context_p, true);
    }

    scanner_set_location (context_p, &end_location);
#else /* !JERRY_ESNEXT */
    JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN);

    bool is_for_in = true;
    scanner_get_location (&start_location, context_p);

    scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
    scanner_release_next (context_p, sizeof (scanner_location_info_t));
#endif /* JERRY_ESNEXT */

    /* The length of both 'in' and 'of' is two. */
    const uint8_t *source_end_p = context_p->source_p - 2;

    scanner_seek (context_p);

#if JERRY_ESNEXT
    if (is_for_in && is_for_await)
    {
      context_p->token.line = context_p->line;
      context_p->token.column = context_p->column - 2;
      parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_OF);
    }
#endif /* JERRY_ESNEXT */

    lexer_next_token (context_p);
    int options = is_for_in ? PARSE_EXPR : PARSE_EXPR_LEFT_HAND_SIDE;
    parser_parse_expression (context_p, options);

    if (context_p->token.type != LEXER_RIGHT_PAREN)
    {
      parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
    }

#ifndef JERRY_NDEBUG
    PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth,
                           is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION
                                     : PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */

    cbc_ext_opcode_t init_opcode = CBC_EXT_FOR_IN_INIT;

#if JERRY_ESNEXT
    if (!is_for_in)
    {
      init_opcode = is_for_await ? CBC_EXT_FOR_AWAIT_OF_INIT : CBC_EXT_FOR_OF_INIT;
    }
#endif /* JERRY_ESNEXT */

    parser_emit_cbc_ext_forward_branch (context_p, init_opcode, &for_in_of_statement.branch);

    JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
    for_in_of_statement.start_offset = context_p->byte_code_size;

#if JERRY_ESNEXT
    if (has_context)
    {
      parser_emit_cbc_ext (context_p, CBC_EXT_CLONE_CONTEXT);
    }
#endif /* JERRY_ESNEXT */

    /* The expression parser must not read the 'in' or 'of' tokens. */
    scanner_get_location (&end_location, context_p);
    scanner_set_location (context_p, &start_location);

    const uint8_t *original_source_end_p = context_p->source_end_p;
    context_p->source_end_p = source_end_p;
    scanner_seek (context_p);

#if JERRY_ESNEXT
    if (token_type == LEXER_EOS)
    {
      lexer_next_token (context_p);

      if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE)
      {
        token_type = context_p->token.type;
      }
    }
#else /* !JERRY_ESNEXT */
    lexer_next_token (context_p);

    uint8_t token_type = context_p->token.type;
#endif /* JERRY_ESNEXT */

    switch (token_type)
    {
#if JERRY_ESNEXT
      case LEXER_KEYW_LET:
      case LEXER_KEYW_CONST:
#endif /* JERRY_ESNEXT */
      case LEXER_KEYW_VAR:
      {
#if JERRY_ESNEXT
        if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE))
        {
          parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
                                                    : CBC_EXT_FOR_OF_GET_NEXT);

          parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK);

          if (context_p->next_scanner_info_p->source_p == (context_p->source_p + 1))
          {
            if (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER)
            {
              scanner_release_next (context_p, sizeof (scanner_location_info_t));
            }
            else
            {
              JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS);
              if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST)
              {
                flags |= PARSER_PATTERN_HAS_REST_ELEMENT;
              }

              scanner_release_next (context_p, sizeof (scanner_info_t));
            }
          }

          if (token_type == LEXER_KEYW_LET)
          {
            flags |= PARSER_PATTERN_LET;
          }
          else if (token_type == LEXER_KEYW_CONST)
          {
            flags |= PARSER_PATTERN_CONST;
          }

          parser_parse_initializer_by_next_char (context_p, flags);
          break;
        }
#endif /* JERRY_ESNEXT */

        lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);

#if JERRY_ESNEXT
        if (context_p->token.keyword_type == LEXER_KEYW_LET
            && token_type != LEXER_KEYW_VAR)
        {
          parser_raise_error (context_p, PARSER_ERR_LEXICAL_LET_BINDING);
        }
#endif /* JERRY_ESNEXT */

        JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
                      && context_p->token.lit_location.type == LEXER_IDENT_LITERAL);

        uint16_t literal_index = context_p->lit_object.index;
        lexer_next_token (context_p);

        if (context_p->token.type == LEXER_ASSIGN)
        {
#if JERRY_ESNEXT
          if ((context_p->status_flags & PARSER_IS_STRICT) || !is_for_in)
          {
            parser_raise_error (context_p, PARSER_ERR_FOR_IN_OF_DECLARATION);
          }
#endif /* JERRY_ESNEXT */
          parser_branch_t branch;

          /* Initialiser is never executed. */
          parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &branch);
          lexer_next_token (context_p);
          parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA);
          parser_set_branch_to_current_position (context_p, &branch);
        }

        parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
                                                  : CBC_EXT_FOR_OF_GET_NEXT);
#if JERRY_ESNEXT
#ifndef JERRY_NDEBUG
        if (literal_index < PARSER_REGISTER_START
            && has_context
            && !scanner_literal_is_created (context_p, literal_index))
        {
          context_p->global_status_flags |= ECMA_PARSE_INTERNAL_FOR_IN_OFF_CONTEXT_ERROR;
        }
#endif /* !JERRY_NDEBUG */

        uint16_t opcode = (has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT);
        parser_emit_cbc_literal (context_p, opcode, literal_index);
#else /* !JERRY_ESNEXT */
        parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
#endif /* JERRY_ESNEXT */
        break;
      }
#if JERRY_ESNEXT
      case LEXER_LEFT_BRACE:
      case LEXER_LEFT_SQUARE:
      {
        if (context_p->next_scanner_info_p->source_p == context_p->source_p
            && context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS
            && (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_DESTRUCTURING_FOR))
        {
          parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
                                                    : CBC_EXT_FOR_OF_GET_NEXT);

          uint32_t flags = PARSER_PATTERN_TARGET_ON_STACK;

          if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST)
          {
            flags |= PARSER_PATTERN_HAS_REST_ELEMENT;
          }

          scanner_release_next (context_p, sizeof (scanner_info_t));
          parser_parse_initializer (context_p, flags);
          /* Pop the value returned by GET_NEXT. */
          parser_emit_cbc (context_p, CBC_POP);
          break;
        }
        /* FALLTHRU */
      }
#endif /* JERRY_ESNEXT */
      default:
      {
        uint16_t opcode;

        parser_parse_expression (context_p, PARSE_EXPR_LEFT_HAND_SIDE);

        opcode = context_p->last_cbc_opcode;

        /* The CBC_EXT_FOR_IN_CREATE_CONTEXT flushed the opcode combiner. */
        JERRY_ASSERT (opcode != CBC_PUSH_TWO_LITERALS
                      && opcode != CBC_PUSH_THREE_LITERALS);

        opcode = parser_check_left_hand_side_expression (context_p, opcode);

        parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
                                                  : CBC_EXT_FOR_OF_GET_NEXT);
        parser_flush_cbc (context_p);

        context_p->last_cbc_opcode = opcode;
        break;
      }
    }

    if (context_p->token.type != LEXER_EOS)
    {
#if JERRY_ESNEXT
      parser_raise_error (context_p, is_for_in ? PARSER_ERR_IN_EXPECTED : PARSER_ERR_OF_EXPECTED);
#else /* !JERRY_ESNEXT */
      parser_raise_error (context_p, PARSER_ERR_IN_EXPECTED);
#endif /* JERRY_ESNEXT */
    }

    parser_flush_cbc (context_p);
    scanner_set_location (context_p, &end_location);
    context_p->source_end_p = original_source_end_p;
    lexer_next_token (context_p);

    loop.branch_list_p = NULL;

    parser_stack_push (context_p, &for_in_of_statement, sizeof (parser_for_in_of_statement_t));
    parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));

    uint8_t for_type = PARSER_STATEMENT_FOR_IN;

#if JERRY_ESNEXT
    if (!is_for_in)
    {
      for_type = is_for_await ? PARSER_STATEMENT_FOR_AWAIT_OF : PARSER_STATEMENT_FOR_OF;
    }
#endif /* JERRY_ESNEXT */

    parser_stack_push_uint8 (context_p, for_type);
    parser_stack_iterator_init (context_p, &context_p->last_statement);
    return;
  }

  lexer_next_token (context_p);

  if (context_p->token.type != LEXER_SEMICOLON)
  {
#if JERRY_ESNEXT
    const uint8_t *source_p = context_p->source_p;
#endif /* JERRY_ESNEXT */

    switch (context_p->token.type)
    {
#if JERRY_ESNEXT
      case LEXER_LITERAL:
      {
        if (!lexer_token_is_let (context_p))
        {
          parser_parse_expression_statement (context_p, PARSE_EXPR);
          break;
        }

        if (context_p->next_scanner_info_p->source_p == context_p->source_p
            && context_p->next_scanner_info_p->type != SCANNER_TYPE_BLOCK)
        {
          if (context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION)
          {
            scanner_release_next (context_p, sizeof (scanner_info_t));
          }

          parser_parse_expression_statement (context_p, PARSE_EXPR);
          break;
        }

        context_p->token.type = LEXER_KEYW_LET;
        /* FALLTHRU */
      }
      case LEXER_KEYW_LET:
      case LEXER_KEYW_CONST:
      {
        if (context_p->next_scanner_info_p->source_p == source_p)
        {
          parser_push_block_context (context_p, true);
        }
        /* FALLTHRU */
      }
#endif /* JERRY_ESNEXT */
      case LEXER_KEYW_VAR:
      {
        parser_parse_var_statement (context_p);
        break;
      }
      default:
      {
        parser_parse_expression_statement (context_p, PARSE_EXPR);
        break;
      }
    }

    if (context_p->token.type != LEXER_SEMICOLON)
    {
      parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
    }
  }

#if JERRY_ESNEXT
  if (is_for_await)
  {
    parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_OF);
  }
#endif /* JERRY_ESNEXT */

  JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p
                || context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR);

  if (context_p->next_scanner_info_p->source_p != context_p->source_p
      || ((scanner_for_info_t *) context_p->next_scanner_info_p)->end_location.source_p == NULL)
  {
    if (context_p->next_scanner_info_p->source_p == context_p->source_p)
    {
      /* Even though the scanning is failed, there might be valid statements
       * inside the for statement which depend on scanner info blocks. */
      scanner_release_next (context_p, sizeof (scanner_for_info_t));
    }

    /* The prescanner couldn't find the second semicolon or the closing paranthesis. */
    lexer_next_token (context_p);
    parser_parse_expression (context_p, PARSE_EXPR);

    if (context_p->token.type != LEXER_SEMICOLON)
    {
      parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
    }

    lexer_next_token (context_p);
    parser_parse_expression_statement (context_p, PARSE_EXPR);

    JERRY_ASSERT (context_p->token.type != LEXER_RIGHT_PAREN);
    parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
  }

  parser_for_statement_t for_statement;
  scanner_for_info_t *for_info_p = (scanner_for_info_t *) context_p->next_scanner_info_p;

  parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &for_statement.branch);

  JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);

  for_statement.start_offset = context_p->byte_code_size;
  scanner_get_location (&for_statement.condition_location, context_p);
  for_statement.expression_location = for_info_p->expression_location;

  scanner_set_location (context_p, &for_info_p->end_location);
  scanner_release_next (context_p, sizeof (scanner_for_info_t));
  scanner_seek (context_p);
  lexer_next_token (context_p);

  loop.branch_list_p = NULL;

  parser_stack_push (context_p, &for_statement, sizeof (parser_for_statement_t));
  parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
  parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR);
  parser_stack_iterator_init (context_p, &context_p->last_statement);
} /* parser_parse_for_statement_start */

Fix parsing unterminated let statement (#4808)

This patch fixes #4754

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik robert.fancsik@h-lab.eu


parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
{
  parser_loop_statement_t loop;

  JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FOR);
  lexer_next_token (context_p);

#if JERRY_ESNEXT
  bool is_for_await = false;

  if (context_p->token.type == LEXER_KEYW_AWAIT)
  {
    if (JERRY_UNLIKELY (context_p->token.lit_location.status_flags & LEXER_LIT_LOCATION_HAS_ESCAPE))
    {
      parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
    }
    lexer_next_token (context_p);
    is_for_await = true;
  }
#endif /* JERRY_ESNEXT */

  if (context_p->token.type != LEXER_LEFT_PAREN)
  {
#if JERRY_ESNEXT
    if (context_p->token.type == LEXER_LITERAL
        && context_p->token.keyword_type == LEXER_KEYW_AWAIT
        && !(context_p->token.lit_location.status_flags & LEXER_LIT_LOCATION_HAS_ESCAPE))
    {
      parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_ASYNC);
    }
#endif /* JERRY_ESNEXT */
    parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
  }

  if (context_p->next_scanner_info_p->source_p == context_p->source_p)
  {
    parser_for_in_of_statement_t for_in_of_statement;
    scanner_location_t start_location, end_location;

#if JERRY_ESNEXT
    JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN
                  || context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_OF);

    bool is_for_in = (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN);
    end_location = ((scanner_location_info_t *) context_p->next_scanner_info_p)->location;

    scanner_release_next (context_p, sizeof (scanner_location_info_t));

    scanner_get_location (&start_location, context_p);
    lexer_next_token (context_p);

    uint8_t token_type = LEXER_EOS;
    bool has_context = false;

    if (context_p->token.type == LEXER_KEYW_VAR
        || context_p->token.type == LEXER_KEYW_LET
        || context_p->token.type == LEXER_KEYW_CONST)
    {
      token_type = context_p->token.type;
      has_context = context_p->next_scanner_info_p->source_p == context_p->source_p;
      JERRY_ASSERT (!has_context || context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
      scanner_get_location (&start_location, context_p);

      /* TODO: remove this after the pre-scanner supports strict mode detection. */
      if (context_p->next_scanner_info_p->source_p == context_p->source_p
          && context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION)
      {
        scanner_release_next (context_p, sizeof (scanner_info_t));
      }
    }
    else if (context_p->token.type == LEXER_LITERAL && lexer_token_is_let (context_p))
    {
      if (context_p->next_scanner_info_p->source_p == context_p->source_p
          && context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION)
      {
        scanner_release_next (context_p, sizeof (scanner_info_t));
      }
      else
      {
        token_type = LEXER_KEYW_LET;
        has_context = (context_p->next_scanner_info_p->source_p == context_p->source_p);
        scanner_get_location (&start_location, context_p);
      }
    }

    if (has_context)
    {
      has_context = parser_push_block_context (context_p, true);
    }

    scanner_set_location (context_p, &end_location);
#else /* !JERRY_ESNEXT */
    JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN);

    bool is_for_in = true;
    scanner_get_location (&start_location, context_p);

    scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
    scanner_release_next (context_p, sizeof (scanner_location_info_t));
#endif /* JERRY_ESNEXT */

    /* The length of both 'in' and 'of' is two. */
    const uint8_t *source_end_p = context_p->source_p - 2;

    scanner_seek (context_p);

#if JERRY_ESNEXT
    if (is_for_in && is_for_await)
    {
      context_p->token.line = context_p->line;
      context_p->token.column = context_p->column - 2;
      parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_OF);
    }
#endif /* JERRY_ESNEXT */

    lexer_next_token (context_p);
    int options = is_for_in ? PARSE_EXPR : PARSE_EXPR_LEFT_HAND_SIDE;
    parser_parse_expression (context_p, options);

    if (context_p->token.type != LEXER_RIGHT_PAREN)
    {
      parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
    }

#ifndef JERRY_NDEBUG
    PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth,
                           is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION
                                     : PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */

    cbc_ext_opcode_t init_opcode = CBC_EXT_FOR_IN_INIT;

#if JERRY_ESNEXT
    if (!is_for_in)
    {
      init_opcode = is_for_await ? CBC_EXT_FOR_AWAIT_OF_INIT : CBC_EXT_FOR_OF_INIT;
    }
#endif /* JERRY_ESNEXT */

    parser_emit_cbc_ext_forward_branch (context_p, init_opcode, &for_in_of_statement.branch);

    JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
    for_in_of_statement.start_offset = context_p->byte_code_size;

#if JERRY_ESNEXT
    if (has_context)
    {
      parser_emit_cbc_ext (context_p, CBC_EXT_CLONE_CONTEXT);
    }
#endif /* JERRY_ESNEXT */

    /* The expression parser must not read the 'in' or 'of' tokens. */
    scanner_get_location (&end_location, context_p);
    scanner_set_location (context_p, &start_location);

    const uint8_t *original_source_end_p = context_p->source_end_p;
    context_p->source_end_p = source_end_p;
    scanner_seek (context_p);

#if JERRY_ESNEXT
    if (token_type == LEXER_EOS)
    {
      lexer_next_token (context_p);

      if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE)
      {
        token_type = context_p->token.type;
      }
    }
#else /* !JERRY_ESNEXT */
    lexer_next_token (context_p);

    uint8_t token_type = context_p->token.type;
#endif /* JERRY_ESNEXT */

    switch (token_type)
    {
#if JERRY_ESNEXT
      case LEXER_KEYW_LET:
      case LEXER_KEYW_CONST:
#endif /* JERRY_ESNEXT */
      case LEXER_KEYW_VAR:
      {
#if JERRY_ESNEXT
        if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE))
        {
          parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
                                                    : CBC_EXT_FOR_OF_GET_NEXT);

          parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK);

          if (context_p->next_scanner_info_p->source_p == (context_p->source_p + 1))
          {
            if (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER)
            {
              scanner_release_next (context_p, sizeof (scanner_location_info_t));
            }
            else
            {
              JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS);
              if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST)
              {
                flags |= PARSER_PATTERN_HAS_REST_ELEMENT;
              }

              scanner_release_next (context_p, sizeof (scanner_info_t));
            }
          }

          if (token_type == LEXER_KEYW_LET)
          {
            flags |= PARSER_PATTERN_LET;
          }
          else if (token_type == LEXER_KEYW_CONST)
          {
            flags |= PARSER_PATTERN_CONST;
          }

          parser_parse_initializer_by_next_char (context_p, flags);
          break;
        }
#endif /* JERRY_ESNEXT */

        lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);

#if JERRY_ESNEXT
        if (context_p->token.keyword_type == LEXER_KEYW_LET
            && token_type != LEXER_KEYW_VAR)
        {
          parser_raise_error (context_p, PARSER_ERR_LEXICAL_LET_BINDING);
        }
#endif /* JERRY_ESNEXT */

        JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
                      && context_p->token.lit_location.type == LEXER_IDENT_LITERAL);

        uint16_t literal_index = context_p->lit_object.index;
        lexer_next_token (context_p);

        if (context_p->token.type == LEXER_ASSIGN)
        {
#if JERRY_ESNEXT
          if ((context_p->status_flags & PARSER_IS_STRICT) || !is_for_in)
          {
            parser_raise_error (context_p, PARSER_ERR_FOR_IN_OF_DECLARATION);
          }
#endif /* JERRY_ESNEXT */
          parser_branch_t branch;

          /* Initialiser is never executed. */
          parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &branch);
          lexer_next_token (context_p);
          parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA);
          parser_set_branch_to_current_position (context_p, &branch);
        }

        parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
                                                  : CBC_EXT_FOR_OF_GET_NEXT);
#if JERRY_ESNEXT
#ifndef JERRY_NDEBUG
        if (literal_index < PARSER_REGISTER_START
            && has_context
            && !scanner_literal_is_created (context_p, literal_index))
        {
          context_p->global_status_flags |= ECMA_PARSE_INTERNAL_FOR_IN_OFF_CONTEXT_ERROR;
        }
#endif /* !JERRY_NDEBUG */

        uint16_t opcode = (has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT);
        parser_emit_cbc_literal (context_p, opcode, literal_index);
#else /* !JERRY_ESNEXT */
        parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
#endif /* JERRY_ESNEXT */
        break;
      }
#if JERRY_ESNEXT
      case LEXER_LEFT_BRACE:
      case LEXER_LEFT_SQUARE:
      {
        if (context_p->next_scanner_info_p->source_p == context_p->source_p
            && context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS
            && (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_DESTRUCTURING_FOR))
        {
          parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
                                                    : CBC_EXT_FOR_OF_GET_NEXT);

          uint32_t flags = PARSER_PATTERN_TARGET_ON_STACK;

          if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST)
          {
            flags |= PARSER_PATTERN_HAS_REST_ELEMENT;
          }

          scanner_release_next (context_p, sizeof (scanner_info_t));
          parser_parse_initializer (context_p, flags);
          /* Pop the value returned by GET_NEXT. */
          parser_emit_cbc (context_p, CBC_POP);
          break;
        }
        /* FALLTHRU */
      }
#endif /* JERRY_ESNEXT */
      default:
      {
        uint16_t opcode;

        parser_parse_expression (context_p, PARSE_EXPR_LEFT_HAND_SIDE);

        opcode = context_p->last_cbc_opcode;

        /* The CBC_EXT_FOR_IN_CREATE_CONTEXT flushed the opcode combiner. */
        JERRY_ASSERT (opcode != CBC_PUSH_TWO_LITERALS
                      && opcode != CBC_PUSH_THREE_LITERALS);

        opcode = parser_check_left_hand_side_expression (context_p, opcode);

        parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
                                                  : CBC_EXT_FOR_OF_GET_NEXT);
        parser_flush_cbc (context_p);

        context_p->last_cbc_opcode = opcode;
        break;
      }
    }

    if (context_p->token.type != LEXER_EOS)
    {
#if JERRY_ESNEXT
      parser_raise_error (context_p, is_for_in ? PARSER_ERR_IN_EXPECTED : PARSER_ERR_OF_EXPECTED);
#else /* !JERRY_ESNEXT */
      parser_raise_error (context_p, PARSER_ERR_IN_EXPECTED);
#endif /* JERRY_ESNEXT */
    }

    parser_flush_cbc (context_p);
    scanner_set_location (context_p, &end_location);
    context_p->source_end_p = original_source_end_p;
    lexer_next_token (context_p);

    loop.branch_list_p = NULL;

    parser_stack_push (context_p, &for_in_of_statement, sizeof (parser_for_in_of_statement_t));
    parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));

    uint8_t for_type = PARSER_STATEMENT_FOR_IN;

#if JERRY_ESNEXT
    if (!is_for_in)
    {
      for_type = is_for_await ? PARSER_STATEMENT_FOR_AWAIT_OF : PARSER_STATEMENT_FOR_OF;
    }
#endif /* JERRY_ESNEXT */

    parser_stack_push_uint8 (context_p, for_type);
    parser_stack_iterator_init (context_p, &context_p->last_statement);
    return;
  }

  lexer_next_token (context_p);

  if (context_p->token.type != LEXER_SEMICOLON)
  {
#if JERRY_ESNEXT
    const uint8_t *source_p = context_p->source_p;
#endif /* JERRY_ESNEXT */

    switch (context_p->token.type)
    {
#if JERRY_ESNEXT
      case LEXER_LITERAL:
      {
        if (!lexer_token_is_let (context_p))
        {
          parser_parse_expression_statement (context_p, PARSE_EXPR);
          break;
        }

        /* FALLTHRU */
      }
      case LEXER_KEYW_LET:
      {
        if (context_p->next_scanner_info_p->source_p == context_p->source_p
            && context_p->next_scanner_info_p->type != SCANNER_TYPE_BLOCK)
        {
          if (context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION)
          {
            scanner_release_next (context_p, sizeof (scanner_info_t));
          }

          parser_parse_expression_statement (context_p, PARSE_EXPR);
          break;
        }

        context_p->token.type = LEXER_KEYW_LET;

        /* FALLTHRU */
      }
      case LEXER_KEYW_CONST:
      {
        if (context_p->next_scanner_info_p->source_p == source_p)
        {
          parser_push_block_context (context_p, true);
        }
        /* FALLTHRU */
      }
#endif /* JERRY_ESNEXT */
      case LEXER_KEYW_VAR:
      {
        parser_parse_var_statement (context_p);
        break;
      }
      default:
      {
        parser_parse_expression_statement (context_p, PARSE_EXPR);
        break;
      }
    }

    if (context_p->token.type != LEXER_SEMICOLON)
    {
      parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
    }
  }

#if JERRY_ESNEXT
  if (is_for_await)
  {
    parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_OF);
  }
#endif /* JERRY_ESNEXT */

  JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p
                || context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR);

  if (context_p->next_scanner_info_p->source_p != context_p->source_p
      || ((scanner_for_info_t *) context_p->next_scanner_info_p)->end_location.source_p == NULL)
  {
    if (context_p->next_scanner_info_p->source_p == context_p->source_p)
    {
      /* Even though the scanning is failed, there might be valid statements
       * inside the for statement which depend on scanner info blocks. */
      scanner_release_next (context_p, sizeof (scanner_for_info_t));
    }

    /* The prescanner couldn't find the second semicolon or the closing paranthesis. */
    lexer_next_token (context_p);
    parser_parse_expression (context_p, PARSE_EXPR);

    if (context_p->token.type != LEXER_SEMICOLON)
    {
      parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
    }

    lexer_next_token (context_p);
    parser_parse_expression_statement (context_p, PARSE_EXPR);

    JERRY_ASSERT (context_p->token.type != LEXER_RIGHT_PAREN);
    parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
  }

  parser_for_statement_t for_statement;
  scanner_for_info_t *for_info_p = (scanner_for_info_t *) context_p->next_scanner_info_p;

  parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &for_statement.branch);

  JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);

  for_statement.start_offset = context_p->byte_code_size;
  scanner_get_location (&for_statement.condition_location, context_p);
  for_statement.expression_location = for_info_p->expression_location;

  scanner_set_location (context_p, &for_info_p->end_location);
  scanner_release_next (context_p, sizeof (scanner_for_info_t));
  scanner_seek (context_p);
  lexer_next_token (context_p);

  loop.branch_list_p = NULL;

  parser_stack_push (context_p, &for_statement, sizeof (parser_for_statement_t));
  parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
  parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR);
  parser_stack_iterator_init (context_p, &context_p->last_statement);
} /* parser_parse_for_statement_start */


static void ok_png_decode2(ok_png_decoder *decoder) {
    ok_png *png = decoder->png;

    uint8_t png_header[8];
    if (!ok_read(decoder, png_header, sizeof(png_header))) {
        return;
    }
    uint8_t png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
    if (memcmp(png_header, png_signature, 8) != 0) {
        ok_png_error(decoder->png, OK_PNG_ERROR_INVALID, "Invalid signature (not a PNG file)");
        return;
    }

    // When info_only is true, we only care about the IHDR chunk and whether or not
    // the tRNS chunk exists.
    bool info_only = (decoder->decode_flags & OK_PNG_INFO_ONLY) != 0;
    bool hdr_found = false;
    bool end_found = false;
    while (!end_found) {
        uint8_t chunk_header[8];
        uint8_t chunk_footer[4];
        if (!ok_read(decoder, chunk_header, sizeof(chunk_header))) {
            return;
        }
        const uint32_t chunk_length = readBE32(chunk_header);
        const uint32_t chunk_type = readBE32(chunk_header + 4);
        bool success = false;

        if (!hdr_found && chunk_type != OK_PNG_CHUNK_CGBI && chunk_type != OK_PNG_CHUNK_IHDR) {
            ok_png_error(png, OK_PNG_ERROR_INVALID, "IHDR chunk must appear first");
            return;
        }
        if (chunk_type == OK_PNG_CHUNK_IHDR) {
            hdr_found = true;
            success = ok_png_read_header(decoder, chunk_length);
            if (success && info_only) {
                // If the png has alpha, then we have all the info we need.
                // Otherwise, continue scanning to see if the tRNS chunk exists.
                if (png->has_alpha) {
                    return;
                }
            }
        } else if (chunk_type == OK_PNG_CHUNK_CGBI) {
            success = ok_seek(decoder, (long)chunk_length);
            decoder->is_ios_format = true;
        } else if (chunk_type == OK_PNG_CHUNK_PLTE && !info_only) {
            success = ok_png_read_palette(decoder, chunk_length);
        } else if (chunk_type == OK_PNG_CHUNK_TRNS) {
            if (info_only) {
                // No need to parse this chunk, we have all the info we need.
                png->has_alpha = true;
                return;
            } else {
                success = ok_png_read_transparency(decoder, chunk_length);
            }
        } else if (chunk_type == OK_PNG_CHUNK_IDAT) {
            if (info_only) {
                // Both IHDR and tRNS must come before IDAT, so we have all the info we need.
                return;
            }
            success = ok_png_read_data(decoder, chunk_length);
        } else if (chunk_type == OK_PNG_CHUNK_IEND) {
            success = ok_seek(decoder, (long)chunk_length);
            end_found = true;
        } else {
            // Ignore this chunk
            success = ok_seek(decoder, (long)chunk_length);
        }

        if (!success) {
            return;
        }

        // Read the footer (CRC) and ignore it
        if (!ok_read(decoder, chunk_footer, sizeof(chunk_footer))) {
            return;
        }
    }

    // Sanity check
    if (!decoder->decoding_completed) {
        ok_png_error(png, OK_PNG_ERROR_INVALID, "Missing imaga data");
    }
}

ok_png: Disallow multiple IHDR chunks (#15)


static void ok_png_decode2(ok_png_decoder *decoder) {
    ok_png *png = decoder->png;

    uint8_t png_header[8];
    if (!ok_read(decoder, png_header, sizeof(png_header))) {
        return;
    }
    uint8_t png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
    if (memcmp(png_header, png_signature, 8) != 0) {
        ok_png_error(decoder->png, OK_PNG_ERROR_INVALID, "Invalid signature (not a PNG file)");
        return;
    }

    // When info_only is true, we only care about the IHDR chunk and whether or not
    // the tRNS chunk exists.
    bool info_only = (decoder->decode_flags & OK_PNG_INFO_ONLY) != 0;
    bool hdr_found = false;
    bool end_found = false;
    while (!end_found) {
        uint8_t chunk_header[8];
        uint8_t chunk_footer[4];
        if (!ok_read(decoder, chunk_header, sizeof(chunk_header))) {
            return;
        }
        const uint32_t chunk_length = readBE32(chunk_header);
        const uint32_t chunk_type = readBE32(chunk_header + 4);
        bool success = false;

        if (!hdr_found && chunk_type != OK_PNG_CHUNK_CGBI && chunk_type != OK_PNG_CHUNK_IHDR) {
            ok_png_error(png, OK_PNG_ERROR_INVALID, "IHDR chunk must appear first");
            return;
        }
        if (chunk_type == OK_PNG_CHUNK_IHDR) {
            if (hdr_found) {
                ok_png_error(png, OK_PNG_ERROR_INVALID, "Multiple IHDR chunks not allowed");
                return;
            }
            hdr_found = true;
            success = ok_png_read_header(decoder, chunk_length);
            if (success && info_only) {
                // If the png has alpha, then we have all the info we need.
                // Otherwise, continue scanning to see if the tRNS chunk exists.
                if (png->has_alpha) {
                    return;
                }
            }
        } else if (chunk_type == OK_PNG_CHUNK_CGBI) {
            success = ok_seek(decoder, (long)chunk_length);
            decoder->is_ios_format = true;
        } else if (chunk_type == OK_PNG_CHUNK_PLTE && !info_only) {
            success = ok_png_read_palette(decoder, chunk_length);
        } else if (chunk_type == OK_PNG_CHUNK_TRNS) {
            if (info_only) {
                // No need to parse this chunk, we have all the info we need.
                png->has_alpha = true;
                return;
            } else {
                success = ok_png_read_transparency(decoder, chunk_length);
            }
        } else if (chunk_type == OK_PNG_CHUNK_IDAT) {
            if (info_only) {
                // Both IHDR and tRNS must come before IDAT, so we have all the info we need.
                return;
            }
            success = ok_png_read_data(decoder, chunk_length);
        } else if (chunk_type == OK_PNG_CHUNK_IEND) {
            success = ok_seek(decoder, (long)chunk_length);
            end_found = true;
        } else {
            // Ignore this chunk
            success = ok_seek(decoder, (long)chunk_length);
        }

        if (!success) {
            return;
        }

        // Read the footer (CRC) and ignore it
        if (!ok_read(decoder, chunk_footer, sizeof(chunk_footer))) {
            return;
        }
    }

    // Sanity check
    if (!decoder->decoding_completed) {
        ok_png_error(png, OK_PNG_ERROR_INVALID, "Missing imaga data");
    }
}


static int check_passwd(unsigned char *passwd, size_t length)
{
	struct digest *d = NULL;
	unsigned char *passwd1_sum;
	unsigned char *passwd2_sum;
	int ret = 0;
	int hash_len;

	if (IS_ENABLED(CONFIG_PASSWD_CRYPTO_PBKDF2)) {
		hash_len = PBKDF2_LENGTH;
	} else {
		d = digest_alloc(PASSWD_SUM);
		if (!d) {
			pr_err("No such digest: %s\n",
			       PASSWD_SUM ? PASSWD_SUM : "NULL");
			return -ENOENT;
		}

		hash_len = digest_length(d);
	}

	passwd1_sum = calloc(hash_len * 2, sizeof(unsigned char));
	if (!passwd1_sum)
		return -ENOMEM;

	passwd2_sum = passwd1_sum + hash_len;

	if (is_passwd_env_enable())
		ret = read_env_passwd(passwd2_sum, hash_len);
	else if (is_passwd_default_enable())
		ret = read_default_passwd(passwd2_sum, hash_len);
	else
		ret = -EINVAL;

	if (ret < 0)
		goto err;

	if (IS_ENABLED(CONFIG_PASSWD_CRYPTO_PBKDF2)) {
		char *key = passwd2_sum + PBKDF2_SALT_LEN;
		char *salt = passwd2_sum;
		int keylen = PBKDF2_LENGTH - PBKDF2_SALT_LEN;

		ret = pkcs5_pbkdf2_hmac_sha1(passwd, length, salt,
			PBKDF2_SALT_LEN, PBKDF2_COUNT, keylen, passwd1_sum);
		if (ret)
			goto err;

		if (strncmp(passwd1_sum, key, keylen) == 0)
			ret = 1;
	} else {
		ret = digest_digest(d, passwd, length, passwd1_sum);

		if (ret)
			goto err;

		if (strncmp(passwd1_sum, passwd2_sum, hash_len) == 0)
			ret = 1;
	}

err:
	free(passwd1_sum);
	digest_free(d);

	return ret;
}

password: Use crypto_memneq() to compare hashes

Cryptographic verifications should be time-constant so that an attacker
cannot get information about the secrets used by observing the system,
so use crypto_memneq() rather than memcmp() to compare password hashes.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>


static int check_passwd(unsigned char *passwd, size_t length)
{
	struct digest *d = NULL;
	unsigned char *passwd1_sum;
	unsigned char *passwd2_sum;
	int ret = 0;
	int hash_len;

	if (IS_ENABLED(CONFIG_PASSWD_CRYPTO_PBKDF2)) {
		hash_len = PBKDF2_LENGTH;
	} else {
		d = digest_alloc(PASSWD_SUM);
		if (!d) {
			pr_err("No such digest: %s\n",
			       PASSWD_SUM ? PASSWD_SUM : "NULL");
			return -ENOENT;
		}

		hash_len = digest_length(d);
	}

	passwd1_sum = calloc(hash_len * 2, sizeof(unsigned char));
	if (!passwd1_sum)
		return -ENOMEM;

	passwd2_sum = passwd1_sum + hash_len;

	if (is_passwd_env_enable())
		ret = read_env_passwd(passwd2_sum, hash_len);
	else if (is_passwd_default_enable())
		ret = read_default_passwd(passwd2_sum, hash_len);
	else
		ret = -EINVAL;

	if (ret < 0)
		goto err;

	if (IS_ENABLED(CONFIG_PASSWD_CRYPTO_PBKDF2)) {
		char *key = passwd2_sum + PBKDF2_SALT_LEN;
		char *salt = passwd2_sum;
		int keylen = PBKDF2_LENGTH - PBKDF2_SALT_LEN;

		ret = pkcs5_pbkdf2_hmac_sha1(passwd, length, salt,
			PBKDF2_SALT_LEN, PBKDF2_COUNT, keylen, passwd1_sum);
		if (ret)
			goto err;

		if (!crypto_memneq(passwd1_sum, key, keylen))
			ret = 1;
	} else {
		ret = digest_digest(d, passwd, length, passwd1_sum);

		if (ret)
			goto err;

		if (!crypto_memneq(passwd1_sum, passwd2_sum, hash_len))
			ret = 1;
	}

err:
	free(passwd1_sum);
	digest_free(d);

	return ret;
}


  void Compute(OpKernelContext* context) override {
    // Get the input Tensors.
    OpInputList params_nested_splits_in;
    OP_REQUIRES_OK(context, context->input_list("params_nested_splits",
                                                &params_nested_splits_in));
    const Tensor& params_dense_values_in =
        context->input(params_nested_splits_in.size());
    const Tensor& indices_in =
        context->input(params_nested_splits_in.size() + 1);

    DCHECK_GT(params_nested_splits_in.size(), 0);  // Enforced by REGISTER_OP.
    SPLITS_TYPE num_params = params_nested_splits_in[0].dim_size(0) - 1;
    OP_REQUIRES_OK(context, ValidateIndices(indices_in, num_params));

    OP_REQUIRES(context, params_dense_values_in.dims() > 0,
                errors::InvalidArgument("params.rank must be nonzero"));
    SPLITS_TYPE num_params_dense_values = params_dense_values_in.dim_size(0);

    // Calculate the `splits`, and store the value slices that we need to
    // copy in `value_slices`.
    std::vector<std::pair<SPLITS_TYPE, SPLITS_TYPE>> value_slices;
    SPLITS_TYPE num_values = 0;
    std::vector<std::vector<SPLITS_TYPE>> out_splits;
    OP_REQUIRES_OK(context, MakeSplits(indices_in, params_nested_splits_in,
                                       num_params_dense_values, &out_splits,
                                       &value_slices, &num_values));

    // Write the output tensors.
    OP_REQUIRES_OK(context, WriteSplits(out_splits, context));
    OP_REQUIRES_OK(context,
                   WriteValues(params_dense_values_in, value_slices,
                               out_splits.size(), num_values, context));
  }

Fix heap OOB in `tf.raw_ops.RaggedGather`

PiperOrigin-RevId: 388355464
Change-Id: If14d96231d1cd7aad7c4d1c22c1bab1576b75717


  void Compute(OpKernelContext* context) override {
    // Get the input Tensors.

    OpInputList params_nested_splits_in;
    OP_REQUIRES_OK(context, context->input_list("params_nested_splits",
                                                &params_nested_splits_in));
    OP_REQUIRES(
        context, params_nested_splits_in.size() > 0,
        errors::InvalidArgument("params_nested_splits must be non empty"));

    const Tensor& params_dense_values_in =
        context->input(params_nested_splits_in.size());
    const Tensor& indices_in =
        context->input(params_nested_splits_in.size() + 1);

    OP_REQUIRES(context, params_nested_splits_in[0].dims() > 0,
                errors::InvalidArgument("Split tensors must not be scalars"));
    SPLITS_TYPE num_params = params_nested_splits_in[0].dim_size(0) - 1;
    OP_REQUIRES_OK(context, ValidateIndices(indices_in, num_params));

    OP_REQUIRES(context, params_dense_values_in.dims() > 0,
                errors::InvalidArgument("params.rank must be nonzero"));
    SPLITS_TYPE num_params_dense_values = params_dense_values_in.dim_size(0);

    // Calculate the `splits`, and store the value slices that we need to
    // copy in `value_slices`.
    std::vector<std::pair<SPLITS_TYPE, SPLITS_TYPE>> value_slices;
    SPLITS_TYPE num_values = 0;
    std::vector<std::vector<SPLITS_TYPE>> out_splits;
    OP_REQUIRES_OK(context, MakeSplits(indices_in, params_nested_splits_in,
                                       num_params_dense_values, &out_splits,
                                       &value_slices, &num_values));

    // Write the output tensors.
    OP_REQUIRES_OK(context, WriteSplits(out_splits, context));
    OP_REQUIRES_OK(context,
                   WriteValues(params_dense_values_in, value_slices,
                               out_splits.size(), num_values, context));
  }


void ReshapeSparseTensor(OpKernelContext *context,
                         const Tensor &input_indices_in,
                         const Tensor &input_shape_in,
                         const Tensor &target_shape_in, int output_indices_idx,
                         int output_shape_idx) {
  OP_REQUIRES(context, TensorShapeUtils::IsMatrix(input_indices_in.shape()),
              errors::InvalidArgument(
                  "Input indices should be a matrix but received shape ",
                  input_indices_in.shape().DebugString()));
  OP_REQUIRES(context, TensorShapeUtils::IsVector(input_shape_in.shape()),
              errors::InvalidArgument(
                  "Input shape should be a vector but received shape ",
                  input_shape_in.shape().DebugString()));
  OP_REQUIRES(context, TensorShapeUtils::IsVector(target_shape_in.shape()),
              errors::InvalidArgument(
                  "Target shape should be a vector but received shape ",
                  target_shape_in.shape().DebugString()));

  const int64_t output_rank = target_shape_in.NumElements();
  const TensorShape input_shape(input_shape_in.vec<int64>());
  const int64_t dense_size = input_shape.num_elements();
  const int64_t nnz = input_indices_in.shape().dim_size(0);

  // Compute the output shape. Determine product of specified dimensions, and
  // find the index of the unspecified one.
  TensorShape output_shape;
  int64_t product = 1;
  int unknown_index = -1;
  auto target_shape = target_shape_in.vec<int64>();
  for (int d = 0; d < output_rank; ++d) {
    const int64_t size = target_shape(d);
    if (size == -1) {
      OP_REQUIRES(
          context, unknown_index == -1,
          errors::InvalidArgument("only one output dimension may be -1, "
                                  "not both ",
                                  unknown_index, " and ", d));
      unknown_index = d;
      output_shape.AddDim(1);
    } else {
      OP_REQUIRES(context, size >= 0,
                  errors::InvalidArgument("size ", d,
                                          " must be non-negative, not ", size));
      product *= size;
      output_shape.AddDim(size);
    }
  }
  if (unknown_index != -1) {
    OP_REQUIRES(
        context, product > 0,
        errors::InvalidArgument("reshape cannot infer the missing "
                                "input size for an empty tensor unless all "
                                "specified input sizes are non-zero"));
    const int64_t missing = dense_size / product;
    OP_REQUIRES(
        context, product * missing == dense_size,
        errors::InvalidArgument(
            "Input to reshape is a SparseTensor with ", dense_size,
            " dense values, but the requested shape requires a multiple of ",
            product, ". input_shape=", input_shape.DebugString(),
            " output_shape=", output_shape.DebugString()));
    output_shape.set_dim(unknown_index, missing);
  }

  OP_REQUIRES(
      context, output_shape.num_elements() == dense_size,
      errors::InvalidArgument("Input to reshape is a tensor with ", dense_size,
                              " dense values, but the requested shape has ",
                              output_shape.num_elements(),
                              ". input_shape=", input_shape.DebugString(),
                              " output_shape=", output_shape.DebugString()));

  // Optimize for reshaping to the same shape.
  if (input_shape == output_shape) {
    context->set_output(output_indices_idx, input_indices_in);
    context->set_output(output_shape_idx, input_shape_in);
    return;
  }

  Tensor *result_shape = nullptr;
  OP_REQUIRES_OK(context, context->allocate_output(output_shape_idx,
                                                   TensorShape({output_rank}),
                                                   &result_shape));
  auto output_shape_vec = result_shape->vec<int64>();
  for (int j = 0; j < output_shape.dims(); ++j) {
    output_shape_vec(j) = output_shape.dim_size(j);
  }

  Tensor *result_indices = nullptr;
  OP_REQUIRES_OK(context,
                 context->allocate_output(output_indices_idx,
                                          TensorShape({nnz, output_rank}),
                                          &result_indices));
  if (nnz > 0) {
    OP_REQUIRES_OK(context, functor::ReshapeSparseTensorFunctor<Device>()(
                                context, input_shape, output_shape,
                                input_indices_in.matrix<int64>(),
                                result_indices->matrix<int64>()));
  }
}

Don't do any work when reshaping 0 elements sparse tensor.

If reshaping to 0 elements tensor, check that input has no elements.
If reshaping no elements input, check that output has no elements.

PiperOrigin-RevId: 388296986
Change-Id: Iadc9fe7252e14313ca987e69bf0d7042fd10232a


void ReshapeSparseTensor(OpKernelContext *context,
                         const Tensor &input_indices_in,
                         const Tensor &input_shape_in,
                         const Tensor &target_shape_in, int output_indices_idx,
                         int output_shape_idx) {
  OP_REQUIRES(context, TensorShapeUtils::IsMatrix(input_indices_in.shape()),
              errors::InvalidArgument(
                  "Input indices should be a matrix but received shape ",
                  input_indices_in.shape().DebugString()));
  OP_REQUIRES(context, TensorShapeUtils::IsVector(input_shape_in.shape()),
              errors::InvalidArgument(
                  "Input shape should be a vector but received shape ",
                  input_shape_in.shape().DebugString()));
  OP_REQUIRES(context, TensorShapeUtils::IsVector(target_shape_in.shape()),
              errors::InvalidArgument(
                  "Target shape should be a vector but received shape ",
                  target_shape_in.shape().DebugString()));

  const int64_t output_rank = target_shape_in.NumElements();
  const TensorShape input_shape(input_shape_in.vec<int64>());
  const int64_t dense_size = input_shape.num_elements();
  const int64_t nnz = input_indices_in.shape().dim_size(0);

  // Compute the output shape. Determine product of specified dimensions, and
  // find the index of the unspecified one.
  TensorShape output_shape;
  int64_t product = 1;
  int unknown_index = -1;
  auto target_shape = target_shape_in.vec<int64>();
  for (int d = 0; d < output_rank; ++d) {
    const int64_t size = target_shape(d);
    if (size == -1) {
      OP_REQUIRES(
          context, unknown_index == -1,
          errors::InvalidArgument("only one output dimension may be -1, "
                                  "not both ",
                                  unknown_index, " and ", d));
      unknown_index = d;
      output_shape.AddDim(1);
    } else {
      OP_REQUIRES(context, size >= 0,
                  errors::InvalidArgument("size ", d,
                                          " must be non-negative, not ", size));
      product *= size;
      output_shape.AddDim(size);
    }
  }
  if (unknown_index != -1) {
    OP_REQUIRES(
        context, product > 0,
        errors::InvalidArgument("reshape cannot infer the missing "
                                "input size for an empty tensor unless all "
                                "specified input sizes are non-zero"));
    const int64_t missing = dense_size / product;
    OP_REQUIRES(
        context, product * missing == dense_size,
        errors::InvalidArgument(
            "Input to reshape is a SparseTensor with ", dense_size,
            " dense values, but the requested shape requires a multiple of ",
            product, ". input_shape=", input_shape.DebugString(),
            " output_shape=", output_shape.DebugString()));
    output_shape.set_dim(unknown_index, missing);
  }

  OP_REQUIRES(
      context, output_shape.num_elements() == dense_size,
      errors::InvalidArgument("Input to reshape is a tensor with ", dense_size,
                              " dense values, but the requested shape has ",
                              output_shape.num_elements(),
                              ". input_shape=", input_shape.DebugString(),
                              " output_shape=", output_shape.DebugString()));

  // Optimize for reshaping to the same shape.
  if (input_shape == output_shape) {
    context->set_output(output_indices_idx, input_indices_in);
    context->set_output(output_shape_idx, input_shape_in);
    return;
  }

  Tensor *result_shape = nullptr;
  OP_REQUIRES_OK(context, context->allocate_output(output_shape_idx,
                                                   TensorShape({output_rank}),
                                                   &result_shape));
  auto output_shape_vec = result_shape->vec<int64>();
  for (int j = 0; j < output_shape.dims(); ++j) {
    output_shape_vec(j) = output_shape.dim_size(j);
  }

  Tensor *result_indices = nullptr;
  OP_REQUIRES_OK(context,
                 context->allocate_output(output_indices_idx,
                                          TensorShape({nnz, output_rank}),
                                          &result_indices));
  if (nnz > 0) {
    OP_REQUIRES(
        context, dense_size > 0 && product > 0,
        errors::InvalidArgument(
            "Input tensor has ", nnz, " non zero elements but input shape (",
            input_shape.DebugString(), ") or output shape (",
            output_shape.DebugString(), ") is empty"));
    OP_REQUIRES_OK(context, functor::ReshapeSparseTensorFunctor<Device>()(
                                context, input_shape, output_shape,
                                input_indices_in.matrix<int64>(),
                                result_indices->matrix<int64>()));
  }
}


void cms_set_pw_data(cms_context *cms, secuPWData *pwdata)
{
	ingress();

	switch (cms->pwdata.source) {
	case PW_SOURCE_INVALID:
	case PW_PROMPT:
	case PW_DEVICE:
	case PW_SOURCE_MAX:
		break;

	case PW_FROMFD:
		if (cms->pwdata.intdata >= 0 &&
		    !(pwdata->source == PW_FROMFD &&
		      cms->pwdata.intdata == pwdata->intdata))
			close(cms->pwdata.intdata);
		break;

	case PW_FROMFILEDB:
	case PW_FROMENV:
	case PW_FROMFILE:
	case PW_PLAINTEXT:
		memset(cms->pwdata.data, 0, strlen(cms->pwdata.data));
		xfree(cms->pwdata.data);
		break;

	case PW_DATABASE:
		xfree(cms->pwdata.data);
		break;
	}
	memmove(&cms->pwdata, pwdata, sizeof(*pwdata));

	dprintf("pwdata:%p", pwdata);
	dprintf("pwdata->source:%d", pwdata->source);
	dprintf("pwdata->data:%p (\"%s\")", pwdata->data,
		pwdata->data ? pwdata->data : "(null)");
	egress();
}

Handle NULL pwdata in cms_set_pw_data()

When 12f16710ee44ef64ddb044a3523c3c4c4d90039a rewrote this function, it
didn't handle the NULL pwdata invocation from daemon.c.  This leads to a
explicit NULL dereference and crash on all attempts to daemonize pesign.

Signed-off-by: Robbie Harwood <rharwood@redhat.com>


void cms_set_pw_data(cms_context *cms, secuPWData *pwdata)
{
	ingress();

	switch (cms->pwdata.source) {
	case PW_SOURCE_INVALID:
	case PW_PROMPT:
	case PW_DEVICE:
	case PW_SOURCE_MAX:
		break;

	case PW_FROMFD:
		if (cms->pwdata.intdata >= 0 &&
		    !(pwdata && pwdata->source == PW_FROMFD &&
		      cms->pwdata.intdata == pwdata->intdata))
			close(cms->pwdata.intdata);
		break;

	case PW_FROMFILEDB:
	case PW_FROMENV:
	case PW_FROMFILE:
	case PW_PLAINTEXT:
		memset(cms->pwdata.data, 0, strlen(cms->pwdata.data));
		xfree(cms->pwdata.data);
		break;

	case PW_DATABASE:
		xfree(cms->pwdata.data);
		break;
	}

	if (!pwdata) {
		cms->pwdata.source = PW_SOURCE_INVALID;
		dprintf("pwdata:NULL");
	} else {
		memmove(&cms->pwdata, pwdata, sizeof(*pwdata));
		dprintf("pwdata:%p", pwdata);
		dprintf("pwdata->source:%d", pwdata->source);
		dprintf("pwdata->data:%p (\"%s\")", pwdata->data,
			pwdata->data ? pwdata->data : "(null)");
	}

	egress();
}


net_bind(short unsigned *port, int type, const char *log_service_name)
{
  struct addrinfo hints = { 0 };
  struct addrinfo *servinfo;
  struct addrinfo *ptr;
  const char *cfgaddr;
  char addr[INET6_ADDRSTRLEN];
  char strport[8];
  int yes = 1;
  int no = 0;
  int fd;
  int ret;

  cfgaddr = cfg_getstr(cfg_getsec(cfg, "general"), "bind_address");

  hints.ai_socktype = (type & (SOCK_STREAM | SOCK_DGRAM)); // filter since type can be SOCK_STREAM | SOCK_NONBLOCK
  hints.ai_family = (cfg_getbool(cfg_getsec(cfg, "general"), "ipv6")) ? AF_INET6 : AF_INET;
  hints.ai_flags = cfgaddr ? 0 : AI_PASSIVE;

  snprintf(strport, sizeof(strport), "%hu", *port);
  ret = getaddrinfo(cfgaddr, strport, &hints, &servinfo);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_MISC, "Failure creating '%s' service, could not resolve '%s' (port %s): %s\n", log_service_name, cfgaddr ? cfgaddr : "(ANY)", strport, gai_strerror(ret));
      return -1;
    }

  for (ptr = servinfo, fd = -1; ptr != NULL; ptr = ptr->ai_next)
    {
      if (fd >= 0)
	close(fd);

      fd = socket(ptr->ai_family, type | SOCK_CLOEXEC, ptr->ai_protocol);
      if (fd < 0)
	continue;

      // TODO libevent sets this, we do the same?
      ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
      if (ret < 0)
	continue;

      ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
      if (ret < 0)
	continue;

      if (ptr->ai_family == AF_INET6)
	{
	  // We want to be sure the service is dual stack
	  ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
	  if (ret < 0)
	    continue;
	}

      ret = bind(fd, ptr->ai_addr, ptr->ai_addrlen);
      if (ret < 0)
	continue;

      break;
    }

  freeaddrinfo(servinfo);

  if (!ptr)
    {
      DPRINTF(E_LOG, L_MISC, "Could not create service '%s' with address %s, port %hu: %s\n", log_service_name, cfgaddr ? cfgaddr : "(ANY)", *port, strerror(errno));
      goto error;
    }

  // Get the port that was assigned
  ret = getsockname(fd, ptr->ai_addr, &ptr->ai_addrlen);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_MISC, "Could not find address of service '%s': %s\n", log_service_name, strerror(errno));
      goto error;
    }

  net_port_get(port, (union net_sockaddr *)ptr->ai_addr);
  net_address_get(addr, sizeof(addr), (union net_sockaddr *)ptr->ai_addr);

  DPRINTF(E_DBG, L_MISC, "Service '%s' bound to %s, port %hu, socket %d\n", log_service_name, addr, *port, fd);

  return fd;

 error:
  close(fd);
  return -1;
}

[misc] Fix use-after-free in net_bind()

Thanks to Ba Jinsheng for reporting this bug


net_bind(short unsigned *port, int type, const char *log_service_name)
{
  struct addrinfo hints = { 0 };
  struct addrinfo *servinfo;
  struct addrinfo *ptr;
  union net_sockaddr naddr = { 0 };
  socklen_t naddr_len = sizeof(naddr);
  const char *cfgaddr;
  char addr[INET6_ADDRSTRLEN];
  char strport[8];
  int yes = 1;
  int no = 0;
  int fd;
  int ret;

  cfgaddr = cfg_getstr(cfg_getsec(cfg, "general"), "bind_address");

  hints.ai_socktype = (type & (SOCK_STREAM | SOCK_DGRAM)); // filter since type can be SOCK_STREAM | SOCK_NONBLOCK
  hints.ai_family = (cfg_getbool(cfg_getsec(cfg, "general"), "ipv6")) ? AF_INET6 : AF_INET;
  hints.ai_flags = cfgaddr ? 0 : AI_PASSIVE;

  snprintf(strport, sizeof(strport), "%hu", *port);
  ret = getaddrinfo(cfgaddr, strport, &hints, &servinfo);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_MISC, "Failure creating '%s' service, could not resolve '%s' (port %s): %s\n", log_service_name, cfgaddr ? cfgaddr : "(ANY)", strport, gai_strerror(ret));
      return -1;
    }

  for (ptr = servinfo, fd = -1; ptr != NULL; ptr = ptr->ai_next)
    {
      if (fd >= 0)
	close(fd);

      fd = socket(ptr->ai_family, type | SOCK_CLOEXEC, ptr->ai_protocol);
      if (fd < 0)
	continue;

      // TODO libevent sets this, we do the same?
      ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
      if (ret < 0)
	continue;

      ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
      if (ret < 0)
	continue;

      if (ptr->ai_family == AF_INET6)
	{
	  // We want to be sure the service is dual stack
	  ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
	  if (ret < 0)
	    continue;
	}

      ret = bind(fd, ptr->ai_addr, ptr->ai_addrlen);
      if (ret < 0)
	continue;

      break;
    }

  freeaddrinfo(servinfo);

  if (!ptr)
    {
      DPRINTF(E_LOG, L_MISC, "Could not create service '%s' with address %s, port %hu: %s\n", log_service_name, cfgaddr ? cfgaddr : "(ANY)", *port, strerror(errno));
      goto error;
    }

  // Get our address (as string) and the port that was assigned (necessary when
  // caller didn't specify a port)
  ret = getsockname(fd, &naddr.sa, &naddr_len);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_MISC, "Error finding address of service '%s': %s\n", log_service_name, strerror(errno));
      goto error;
    }
  else if (naddr_len > sizeof(naddr))
    {
      DPRINTF(E_LOG, L_MISC, "Unexpected address length of service '%s'\n", log_service_name);
      goto error;
    }

  net_port_get(port, &naddr);
  net_address_get(addr, sizeof(addr), &naddr);

  DPRINTF(E_DBG, L_MISC, "Service '%s' bound to %s, port %hu, socket %d\n", log_service_name, addr, *port, fd);

  return fd;

 error:
  close(fd);
  return -1;
}


  void Compute(OpKernelContext* ctx) override {
    const Tensor* x_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("x", &x_tensor));

    const Tensor* cs_prev_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("cs_prev", &cs_prev_tensor));

    const Tensor* h_prev_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("h_prev", &h_prev_tensor));

    const Tensor* w_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("w", &w_tensor));

    const Tensor* wci_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("wci", &wci_tensor));

    const Tensor* wcf_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("wcf", &wcf_tensor));

    const Tensor* wco_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("wco", &wco_tensor));

    const Tensor* b_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("b", &b_tensor));

    const int64_t batch_size = x_tensor->dim_size(0);
    const int64_t input_size = x_tensor->dim_size(1);
    const int64_t cell_size = cs_prev_tensor->dim_size(1);

    // Sanity checks for our input shapes.
    OP_REQUIRES(ctx, cs_prev_tensor->dim_size(0) == batch_size,
                errors::InvalidArgument("cs_prev.dims(0) != batch_size: ",
                                        cs_prev_tensor->dim_size(0), " vs. ",
                                        batch_size));
    OP_REQUIRES(ctx, cs_prev_tensor->dim_size(1) == cell_size,
                errors::InvalidArgument("cs_prev.dims(1) != cell_size: ",
                                        cs_prev_tensor->dim_size(1), " vs. ",
                                        cell_size));

    OP_REQUIRES(ctx, h_prev_tensor->dim_size(0) == batch_size,
                errors::InvalidArgument("h_prev.dims(0) != batch_size: ",
                                        h_prev_tensor->dim_size(0), " vs. ",
                                        batch_size));
    OP_REQUIRES(ctx, h_prev_tensor->dim_size(1) == cell_size,
                errors::InvalidArgument(
                    "h_prev.dims(1) != cell_size: ", h_prev_tensor->dim_size(1),
                    " vs. ", cell_size));

    OP_REQUIRES(ctx, w_tensor->dim_size(0) == input_size + cell_size,
                errors::InvalidArgument(
                    "w.dim_size(0) != input_size + cell_size: ",
                    w_tensor->dim_size(0), " vs. ", input_size + cell_size));
    OP_REQUIRES(ctx, w_tensor->dim_size(1) == cell_size * 4,
                errors::InvalidArgument(
                    "w.dim_size(1) != cell_size * 4: ", w_tensor->dim_size(1),
                    " vs. ", cell_size * 4));

    OP_REQUIRES(ctx, b_tensor->dim_size(0) == cell_size * 4,
                errors::InvalidArgument(
                    "b.dim_size(0) != cell_size * 4: ", b_tensor->dim_size(0),
                    " vs. ", cell_size * 4));

    // Allocate our output tensors.
    Tensor* i_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->forward_input_or_allocate_output(
                            {"h_prev"}, "i",
                            TensorShape({batch_size, cell_size}), &i_tensor));

    Tensor* cs_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("cs", TensorShape({batch_size, cell_size}),
                                  &cs_tensor));

    Tensor* f_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("f", TensorShape({batch_size, cell_size}),
                                  &f_tensor));

    Tensor* o_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->forward_input_or_allocate_output(
                            {"cs_prev"}, "o",
                            TensorShape({batch_size, cell_size}), &o_tensor));

    Tensor* ci_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("ci", TensorShape({batch_size, cell_size}),
                                  &ci_tensor));

    Tensor* co_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("co", TensorShape({batch_size, cell_size}),
                                  &co_tensor));

    Tensor* h_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("h", TensorShape({batch_size, cell_size}),
                                  &h_tensor));

    // Allocate our temp tensors.
    Tensor xh_tensor;
    OP_REQUIRES_OK(ctx, ctx->allocate_temp(
                            DataTypeToEnum<T>::v(),
                            TensorShape({batch_size, input_size + cell_size}),
                            &xh_tensor));

    Tensor gates_tensor;
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_temp(DataTypeToEnum<T>::v(),
                                      TensorShape({batch_size, cell_size * 4}),
                                      &gates_tensor));

    const Device& device = ctx->eigen_device<Device>();

    functor::LSTMBlockCellFprop<Device, T, USE_CUBLAS, gate_layout>(
        batch_size, input_size, cell_size)(
        ctx, device, forget_bias_, cell_clip_, use_peephole_,
        x_tensor->matrix<T>(), cs_prev_tensor->matrix<T>(),
        h_prev_tensor->matrix<T>(), w_tensor->matrix<T>(), wci_tensor->vec<T>(),
        wcf_tensor->vec<T>(), wco_tensor->vec<T>(), b_tensor->vec<T>(),
        xh_tensor.matrix<T>(), i_tensor->matrix<T>(), cs_tensor->matrix<T>(),
        f_tensor->matrix<T>(), o_tensor->matrix<T>(), ci_tensor->matrix<T>(),
        co_tensor->matrix<T>(), gates_tensor.matrix<T>(),
        h_tensor->matrix<T>());
  }

Fix security vulnerability with LSTMBlockCellOp

PiperOrigin-RevId: 446028341


  void Compute(OpKernelContext* ctx) override {
    const Tensor* x_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("x", &x_tensor));

    const Tensor* cs_prev_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("cs_prev", &cs_prev_tensor));

    const Tensor* h_prev_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("h_prev", &h_prev_tensor));

    const Tensor* w_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("w", &w_tensor));

    const Tensor* wci_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("wci", &wci_tensor));

    const Tensor* wcf_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("wcf", &wcf_tensor));

    const Tensor* wco_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("wco", &wco_tensor));

    const Tensor* b_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->input("b", &b_tensor));

    const int64_t batch_size = x_tensor->dim_size(0);
    const int64_t input_size = x_tensor->dim_size(1);
    const int64_t cell_size = cs_prev_tensor->dim_size(1);

    // Sanity checks for our input shapes.
    OP_REQUIRES(ctx, cs_prev_tensor->dim_size(0) == batch_size,
                errors::InvalidArgument("cs_prev.dims(0) != batch_size: ",
                                        cs_prev_tensor->dim_size(0), " vs. ",
                                        batch_size));
    OP_REQUIRES(ctx, cs_prev_tensor->dim_size(1) == cell_size,
                errors::InvalidArgument("cs_prev.dims(1) != cell_size: ",
                                        cs_prev_tensor->dim_size(1), " vs. ",
                                        cell_size));

    OP_REQUIRES(ctx, h_prev_tensor->dim_size(0) == batch_size,
                errors::InvalidArgument("h_prev.dims(0) != batch_size: ",
                                        h_prev_tensor->dim_size(0), " vs. ",
                                        batch_size));
    OP_REQUIRES(ctx, h_prev_tensor->dim_size(1) == cell_size,
                errors::InvalidArgument(
                    "h_prev.dims(1) != cell_size: ", h_prev_tensor->dim_size(1),
                    " vs. ", cell_size));

    OP_REQUIRES(ctx, w_tensor->dim_size(0) == input_size + cell_size,
                errors::InvalidArgument(
                    "w.dim_size(0) != input_size + cell_size: ",
                    w_tensor->dim_size(0), " vs. ", input_size + cell_size));
    OP_REQUIRES(ctx, w_tensor->dim_size(1) == cell_size * 4,
                errors::InvalidArgument(
                    "w.dim_size(1) != cell_size * 4: ", w_tensor->dim_size(1),
                    " vs. ", cell_size * 4));

    OP_REQUIRES(ctx, b_tensor->dim_size(0) == cell_size * 4,
                errors::InvalidArgument(
                    "b.dim_size(0) != cell_size * 4: ", b_tensor->dim_size(0),
                    " vs. ", cell_size * 4));

    // Allocate our output tensors.
    Tensor* i_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->forward_input_or_allocate_output(
                            {"h_prev"}, "i",
                            TensorShape({batch_size, cell_size}), &i_tensor));

    Tensor* cs_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("cs", TensorShape({batch_size, cell_size}),
                                  &cs_tensor));

    Tensor* f_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("f", TensorShape({batch_size, cell_size}),
                                  &f_tensor));

    Tensor* o_tensor = nullptr;
    OP_REQUIRES_OK(ctx, ctx->forward_input_or_allocate_output(
                            {"cs_prev"}, "o",
                            TensorShape({batch_size, cell_size}), &o_tensor));

    Tensor* ci_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("ci", TensorShape({batch_size, cell_size}),
                                  &ci_tensor));

    Tensor* co_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("co", TensorShape({batch_size, cell_size}),
                                  &co_tensor));

    Tensor* h_tensor = nullptr;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output("h", TensorShape({batch_size, cell_size}),
                                  &h_tensor));

    // Allocate our temp tensors.
    Tensor xh_tensor;
    OP_REQUIRES_OK(ctx, ctx->allocate_temp(
                            DataTypeToEnum<T>::v(),
                            TensorShape({batch_size, input_size + cell_size}),
                            &xh_tensor));

    Tensor gates_tensor;
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_temp(DataTypeToEnum<T>::v(),
                                      TensorShape({batch_size, cell_size * 4}),
                                      &gates_tensor));

    const Device& device = ctx->eigen_device<Device>();

    // Sanity check that each of the tensors have the required NDIMS.
    OP_REQUIRES(ctx, x_tensor->dims() == 2,
                errors::InvalidArgument("x_tensor must be rank 2 but is rank ",
                                        x_tensor->dims(), "."));
    OP_REQUIRES(
        ctx, cs_prev_tensor->dims() == 2,
        errors::InvalidArgument("cs_prev_tensor must be rank 2 but is rank ",
                                cs_prev_tensor->dims(), "."));
    OP_REQUIRES(
        ctx, h_prev_tensor->dims() == 2,
        errors::InvalidArgument("h_prev_tensor must be rank 2 but is rank ",
                                h_prev_tensor->dims(), "."));
    OP_REQUIRES(ctx, w_tensor->dims() == 2,
                errors::InvalidArgument("w_tensor must be rank 2 but is rank ",
                                        w_tensor->dims(), "."));
    OP_REQUIRES(
        ctx, wci_tensor->dims() == 1,
        errors::InvalidArgument("wci_tensor must be rank 1 but is rank ",
                                wci_tensor->dims(), "."));
    OP_REQUIRES(
        ctx, wcf_tensor->dims() == 1,
        errors::InvalidArgument("wcf_tensor must be rank 1 but is rank ",
                                wci_tensor->dims(), "."));
    OP_REQUIRES(
        ctx, wco_tensor->dims() == 1,
        errors::InvalidArgument("wco_tensor must be rank 1 but is rank ",
                                wco_tensor->dims(), "."));
    OP_REQUIRES(ctx, b_tensor->dims() == 1,
                errors::InvalidArgument("b_tensor must be rank 1 but is rank ",
                                        b_tensor->dims(), "."));
    OP_REQUIRES(ctx, xh_tensor.dims() == 2,
                errors::InvalidArgument("xh_tensor must be rank 2 but is rank ",
                                        xh_tensor.dims(), "."));
    OP_REQUIRES(ctx, i_tensor->dims() == 2,
                errors::InvalidArgument("i_tensor must be rank 2 but is rank ",
                                        i_tensor->dims(), "."));
    OP_REQUIRES(ctx, cs_tensor->dims() == 2,
                errors::InvalidArgument("cs_tensor must be rank 2 but is rank ",
                                        cs_tensor->dims(), "."));
    OP_REQUIRES(ctx, f_tensor->dims() == 2,
                errors::InvalidArgument("f_tensor must be rank 2 but is rank ",
                                        f_tensor->dims(), "."));
    OP_REQUIRES(ctx, o_tensor->dims() == 2,
                errors::InvalidArgument("o_tensor must be rank 2 but is rank ",
                                        o_tensor->dims(), "."));
    OP_REQUIRES(ctx, ci_tensor->dims() == 2,
                errors::InvalidArgument("ci_tensor must be rank 2 but is rank ",
                                        ci_tensor->dims(), "."));
    OP_REQUIRES(ctx, co_tensor->dims() == 2,
                errors::InvalidArgument("co_tensor must be rank 2 but is rank ",
                                        co_tensor->dims(), "."));
    OP_REQUIRES(
        ctx, gates_tensor.dims() == 2,
        errors::InvalidArgument("gates_tensor must be rank 2 but is rank ",
                                gates_tensor.dims(), "."));
    OP_REQUIRES(ctx, h_tensor->dims() == 2,
                errors::InvalidArgument("h_tensor must be rank 2 but is rank ",
                                        h_tensor->dims(), "."));

    functor::LSTMBlockCellFprop<Device, T, USE_CUBLAS, gate_layout>(
        batch_size, input_size, cell_size)(
        ctx, device, forget_bias_, cell_clip_, use_peephole_,
        x_tensor->matrix<T>(), cs_prev_tensor->matrix<T>(),
        h_prev_tensor->matrix<T>(), w_tensor->matrix<T>(), wci_tensor->vec<T>(),
        wcf_tensor->vec<T>(), wco_tensor->vec<T>(), b_tensor->vec<T>(),
        xh_tensor.matrix<T>(), i_tensor->matrix<T>(), cs_tensor->matrix<T>(),
        f_tensor->matrix<T>(), o_tensor->matrix<T>(), ci_tensor->matrix<T>(),
        co_tensor->matrix<T>(), gates_tensor.matrix<T>(),
        h_tensor->matrix<T>());
  }


static void handle_PORT(ctrl_t *ctrl, char *str)
{
	int a, b, c, d, e, f;
	char addr[INET_ADDRSTRLEN];
	struct sockaddr_in sin;

	if (ctrl->data_sd > 0) {
		uev_io_stop(&ctrl->data_watcher);
		close(ctrl->data_sd);
		ctrl->data_sd = -1;
	}

	/* Convert PORT command's argument to IP address + port */
	sscanf(str, "%d,%d,%d,%d,%d,%d", &a, &b, &c, &d, &e, &f);
	sprintf(addr, "%d.%d.%d.%d", a, b, c, d);

	/* Check IPv4 address using inet_aton(), throw away converted result */
	if (!inet_aton(addr, &(sin.sin_addr))) {
		ERR(0, "Invalid address '%s' given to PORT command", addr);
		send_msg(ctrl->sd, "500 Illegal PORT command.\r\n");
		return;
	}

	strlcpy(ctrl->data_address, addr, sizeof(ctrl->data_address));
	ctrl->data_port = e * 256 + f;

	DBG("Client PORT command accepted for %s:%d", ctrl->data_address, ctrl->data_port);
	send_msg(ctrl->sd, "200 PORT command successful.\r\n");
}

FTP: Fix buffer overflow in PORT parser, reported by Aaron Esau

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>


static void handle_PORT(ctrl_t *ctrl, char *str)
{
	int a, b, c, d, e, f;
	char addr[INET_ADDRSTRLEN];
	struct sockaddr_in sin;

	if (ctrl->data_sd > 0) {
		uev_io_stop(&ctrl->data_watcher);
		close(ctrl->data_sd);
		ctrl->data_sd = -1;
	}

	/* Convert PORT command's argument to IP address + port */
	sscanf(str, "%d,%d,%d,%d,%d,%d", &a, &b, &c, &d, &e, &f);
	snprintf(addr, sizeof(addr), "%d.%d.%d.%d", a, b, c, d);

	/* Check IPv4 address using inet_aton(), throw away converted result */
	if (!inet_aton(addr, &(sin.sin_addr))) {
		ERR(0, "Invalid address '%s' given to PORT command", addr);
		send_msg(ctrl->sd, "500 Illegal PORT command.\r\n");
		return;
	}

	strlcpy(ctrl->data_address, addr, sizeof(ctrl->data_address));
	ctrl->data_port = e * 256 + f;

	DBG("Client PORT command accepted for %s:%d", ctrl->data_address, ctrl->data_port);
	send_msg(ctrl->sd, "200 PORT command successful.\r\n");
}


ctcompare(const char *a,		/* I - First string */
          const char *b)		/* I - Second string */
{
  int	result = 0;			/* Result */

  while (*a && *b)
  {
    result |= *a ^ *b;
    a ++;
    b ++;
  }

  return (result);
}

CVE-2022-26691: An incorrect comparison in local admin authentication


ctcompare(const char *a,		/* I - First string */
          const char *b)		/* I - Second string */
{
  int	result = 0;			/* Result */

  while (*a && *b)
  {
    result |= *a ^ *b;
    a ++;
    b ++;
  }

  // either both *a and *b == '\0', or one points inside a string,
  // so factor that in.
  result |= (*a ^ *b);

  return (result);
}