<commit_before>//===- lib/Runtimes/Tracer/WrapCstdio_h.cpp -------------------------------===//
//
//                                    SeeC
//
// This file is distributed under The MIT License (MIT). See LICENSE.TXT for
// details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
//===----------------------------------------------------------------------===//

#include "SimpleWrapper.hpp"
#include "Tracer.hpp"

#include "seec/RuntimeErrors/FormatSelects.hpp"
#include "seec/RuntimeErrors/RuntimeErrors.hpp"
#include "seec/Runtimes/MangleFunction.h"
#include "seec/Trace/DetectCalls.hpp"
#include "seec/Trace/ScanFormatSpecifiers.hpp"
#include "seec/Trace/TraceThreadListener.hpp"
#include "seec/Trace/TraceThreadMemCheck.hpp"
#include "seec/Util/Fallthrough.hpp"
#include "seec/Util/ScopeExit.hpp"

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CallSite.h"

#include <cctype>
#include <cinttypes>
#include <cstdio>
#include <cstdarg>


//===----------------------------------------------------------------------===//
// scanf, fscanf, sscanf common methods
//===----------------------------------------------------------------------===//

/// \brief Attempt to match a sequence of literal characters.
///
bool matchNonConversionCharacters(int &CharactersRead,
                                  FILE *Stream,
                                  char const *Start,
                                  char const *End = nullptr)
{
  while(*Start && (End == nullptr || Start < End)) {
    if (std::isspace(*Start)) {
      // Match all whitespace characters.
      int ReadChar;
      
      while ((ReadChar = std::fgetc(Stream)) != EOF) {
        if (!std::isspace(ReadChar)) {
          std::ungetc(ReadChar, Stream);
          break;
        }
        
        ++CharactersRead;
      }
    }
    else {
      // Match a single character.
      int ReadChar = std::fgetc(Stream);
      if (ReadChar == EOF)
        return false;
      
      if (ReadChar != *Start) {
        std::ungetc(ReadChar, Stream);
        return false;
      }
      
      ++CharactersRead;
    }
    
    ++Start;
  }
  
  return true;
}

/// \brief Attempt to match an integer from a stream.
///
bool parseInt(int &CharactersRead,
              FILE *Stream,
              seec::trace::ScanConversionSpecifier const &Conversion,
              std::uintmax_t &Output)
{
  using namespace seec::trace;
  
  char Buffer[64];
  auto const BufferSize = sizeof(Buffer);
  
  auto Width = Conversion.Width;
  if (Width == 0 || Width > BufferSize - 1)
    Width = BufferSize - 1;
  
  bool Unsigned     = false;
  bool HexPrefixOK  = false;
  
  int Base = 0;
  
  switch (Conversion.Conversion) {
    case ScanConversionSpecifier::Specifier::d:
      Base = 10;
      break;
    case ScanConversionSpecifier::Specifier::i:
      break;
    case ScanConversionSpecifier::Specifier::o:
      Base = 8;
      Unsigned = true;
      break;
    case ScanConversionSpecifier::Specifier::u:
      Base = 10;
      Unsigned = true;
      break;
    case ScanConversionSpecifier::Specifier::x:
      Base = 16;
      Unsigned = true;
      break;
    default:
      llvm_unreachable("invalid conversion specifier for parseInt()");
      return false;
  }
  
  char *BufferPtr = Buffer;
  
  for (; Width != 0; --Width) {
    int ReadChar = std::fgetc(Stream);
    if (ReadChar == EOF) {
      if (std::ferror(Stream))
        return false;
      break;
    }
    
    bool ReadOK = true;
    
    switch (ReadChar) {
      // OK always. For %i, this sets the base to octal, unless it is followed
      // by 'x' or 'X', which will set the base to hexadecimal (we take care
      // of that when encountering 'x' or 'X').
      case '0':
        if (Base == 0) {
          Base = 8;
          HexPrefixOK = true;
        }
        break;
      
      // OK always.
      case '1': SEEC_FALLTHROUGH;
      case '2': SEEC_FALLTHROUGH;
      case '3': SEEC_FALLTHROUGH;
      case '4': SEEC_FALLTHROUGH;
      case '5': SEEC_FALLTHROUGH;
      case '6': SEEC_FALLTHROUGH;
      case '7':
        if (Base == 0)
          Base = 10;
        break;
      
      // OK iff decimal or hexadecimal.
      case '8': SEEC_FALLTHROUGH;
      case '9':
        if (Base == 0)
          Base = 10;
        else if (Base < 10)
          ReadOK = false;
        break;
      
      // OK iff hexadecimal.
      case 'A': SEEC_FALLTHROUGH;
      case 'a': SEEC_FALLTHROUGH;
      case 'B': SEEC_FALLTHROUGH;
      case 'b': SEEC_FALLTHROUGH;
      case 'C': SEEC_FALLTHROUGH;
      case 'c': SEEC_FALLTHROUGH;
      case 'D': SEEC_FALLTHROUGH;
      case 'd': SEEC_FALLTHROUGH;
      case 'E': SEEC_FALLTHROUGH;
      case 'e': SEEC_FALLTHROUGH;
      case 'F': SEEC_FALLTHROUGH;
      case 'f':
        if (Base < 16)
          ReadOK = false;
        break;
      
      // OK as first character.
      case '+': SEEC_FALLTHROUGH;
      case '-':
        if (BufferPtr != Buffer)
          ReadOK = false;
        break;
      
      // OK if part of the prefix "0x" or "0X".
      case 'X': SEEC_FALLTHROUGH;
      case 'x':
        if (HexPrefixOK) {
          Base = 16;
          HexPrefixOK = false;
        }
        else {
          ReadOK = false;
        }
        break;
      
      // Any other character is always invalid.
      default:
        ReadOK = false;
    }
    
    if (ReadOK) {
      *BufferPtr++ = static_cast<char>(ReadChar);
      ++CharactersRead;
    }
    else {
      // Push the character back into the stream.
      std::ungetc(ReadChar, Stream);
      break;
    }
  }
  
  // Short-circuit failure.
  if (BufferPtr == Buffer)
    return false;
  
  *BufferPtr = '\0';
  
  // Read the integer.
  char *ParseEnd = nullptr;
  
  if (Unsigned)
    Output = std::strtoumax(Buffer, &ParseEnd, Base);
  else
    Output = std::strtoimax(Buffer, &ParseEnd, Base);
  
  // Push unused characters back into the stream.
  if (ParseEnd != BufferPtr) {
    // Teach Clang's static analyzer that the value of ParseEnd following the
    // call to strtoumax or strtoimax will always be within the buffer range.
    assert(ParseEnd >= Buffer && ParseEnd < BufferPtr
           && "ParseEnd is not in buffer!");
    
    for (--BufferPtr; BufferPtr > ParseEnd; --BufferPtr) {
      std::ungetc(*BufferPtr, Stream);
    }
  }
  
  return (ParseEnd != Buffer);
}

/// \brief Implement checked scanf and fscanf.
///
static int
checkStreamScan(seec::runtime_errors::format_selects::CStdFunction FSFunction,
                unsigned VarArgsStartIndex,
                FILE *Stream,
                char const *Format)
{
  using namespace seec::trace;
  using namespace seec::runtime_errors;
  
  auto &ThreadEnv = getThreadEnvironment();
  auto &Listener = ThreadEnv.getThreadListener();
  auto Instruction = ThreadEnv.getInstruction();
  auto InstructionIndex = ThreadEnv.getInstructionIndex();
  auto Call = llvm::CallSite(Instruction);
  assert(Call && "expected call or invoke instruction.");
    
  // Interace with the thread listener's notification system.
  Listener.enterNotification();
  auto DoExit = seec::scopeExit([&](){ Listener.exitPostNotification(); });
  
  // Use a VarArgList to access our arguments.
  detect_calls::VarArgList<TraceThreadListener>
    VarArgs{Listener, Call, VarArgsStartIndex};

  // Lock IO streams and global memory.
  Listener.acquireGlobalMemoryWriteLock();
  auto StreamsAccessor = Listener.getProcessListener().getStreamsAccessor();
  
  // Use a CIOChecker to help check memory.
  CIOChecker Checker{Listener,
                     InstructionIndex,
                     FSFunction,
                     StreamsAccessor.getObject()};
  
  // Check that the stream is valid.
  if (Stream == stdin || Stream == stdout || Stream == stderr) {
    Checker.checkStandardStreamIsValid(Stream);
  }
  else {
    Checker.checkStreamIsValid(0, Stream);
  }
  
  // Check and perform the (f)scanf.
  auto FormatSize = Checker.checkCStringRead(VarArgsStartIndex - 1, Format);
  if (!FormatSize) {
    Listener.notifyValue(InstructionIndex, Instruction, unsigned(0));
    return 0;
  }
  
  int NumConversions = 0;
  int NumAssignments = 0;
  int NumCharsRead = 0;
  unsigned NextArg = 0;
  char const *NextChar = Format;
  bool InputFailure = false;
  bool CriticalError = false;
  llvm::SmallVector<std::pair<char const *, std::size_t>, 8> StateChanges;
  
  while (!CriticalError) {
    auto Conversion = ScanConversionSpecifier::readNextFrom(NextChar);
    if (!Conversion.Start) {
      // Attempt to match and consume remaining characters.
      matchNonConversionCharacters(NumCharsRead, Stream, NextChar);
      break;
    }
    
    // Attempt to match and consume [NextChar, Conversion.Start).
    if (!matchNonConversionCharacters(NumCharsRead, Stream, NextChar,
                                      Conversion.Start))
      break;
    
    auto const StartIndex = Conversion.Start - Format;
    
    // Ensure that the conversion specifier was parsed correctly.
    if (!Conversion.End) {
      Listener.handleRunError(
        *createRunError<RunErrorType::FormatSpecifierParse>
                       (FSFunction, VarArgsStartIndex - 1, StartIndex),
        RunErrorSeverity::Fatal,
        InstructionIndex);
      
      CriticalError = true;
      break; // Leave the main processing loop.
    }
    
    auto const EndIndex = Conversion.End - Format;
    
    // If assignment was suppressed, ensure that suppressing assignment is OK.
    if (Conversion.SuppressAssignment) {
      if (!Conversion.allowedSuppressAssignment()) {
        Listener.handleRunError(
          *createRunError<RunErrorType::FormatSpecifierSuppressionDenied>
                         (FSFunction,
                          VarArgsStartIndex - 1,
                          StartIndex,
                          EndIndex),
          RunErrorSeverity::Fatal,
          InstructionIndex);
        
        CriticalError = true;
        break; // Leave the main processing loop.
      }
    }
    else {
      // Check that the argument type matches the expected type. Don't check
      // that the argument exists here, because some conversion specifiers don't
      // require an argument (i.e. %%), so we check if it exists when needed, in
      // the isArgumentTypeOK() implementation.
      if (!Conversion.isArgumentTypeOK(VarArgs, NextArg)) {
        Listener.handleRunError(
          *createRunError<RunErrorType::FormatSpecifierArgType>
                         (FSFunction,
                          VarArgsStartIndex - 1,
                          StartIndex,
                          EndIndex,
                          asCFormatLengthModifier(Conversion.Length),
                          VarArgs.offset() + NextArg),
          RunErrorSeverity::Fatal,
          InstructionIndex);
        
        CriticalError = true;
        break; // Leave the main processing loop.
      }

      // If the argument type is a pointer, check that the destination is
      // writable. The conversion for strings (and sets) is a special case.
      if (Conversion.Conversion == ScanConversionSpecifier::Specifier::s
          || Conversion.Conversion == ScanConversionSpecifier::Specifier::set) {
        if (NextArg < VarArgs.size() && Conversion.WidthSpecified) {
          // Check that the destination is writable and has sufficient space
          // for the field width specified by the programmer.
          auto MaybeArea = Conversion.getArgumentPointee(VarArgs, NextArg);
          auto const Size = (Conversion.Length == LengthModifier::l)
                          ? (Conversion.Width + 1) * sizeof(wchar_t)
                          : (Conversion.Width + 1) * sizeof(char);
          
          if (!Checker.checkMemoryExistsAndAccessibleForParameter(
                  VarArgs.offset() + NextArg,
                  reinterpret_cast<uintptr_t>(MaybeArea.get<0>().first),
                  Size,
                  seec::runtime_errors::format_selects::MemoryAccess::Write))
            
            CriticalError = true;
            break; // Leave the main processing loop.
        }
      }
      else {
        auto MaybePointeeArea = Conversion.getArgumentPointee(VarArgs, NextArg);
        if (MaybePointeeArea.assigned()) {
          auto const &Area = MaybePointeeArea.get<0>();
          Checker.checkMemoryExistsAndAccessibleForParameter(
            VarArgs.offset() + NextArg,
            reinterpret_cast<uintptr_t>(Area.first),
            Area.second,
            seec::runtime_errors::format_selects::MemoryAccess::Write);
        }
      }
    }
    <commit_msg>Remove dead stores.<commit_after>//===- lib/Runtimes/Tracer/WrapCstdio_h.cpp -------------------------------===//
//
//                                    SeeC
//
// This file is distributed under The MIT License (MIT). See LICENSE.TXT for
// details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
//===----------------------------------------------------------------------===//

#include "SimpleWrapper.hpp"
#include "Tracer.hpp"

#include "seec/RuntimeErrors/FormatSelects.hpp"
#include "seec/RuntimeErrors/RuntimeErrors.hpp"
#include "seec/Runtimes/MangleFunction.h"
#include "seec/Trace/DetectCalls.hpp"
#include "seec/Trace/ScanFormatSpecifiers.hpp"
#include "seec/Trace/TraceThreadListener.hpp"
#include "seec/Trace/TraceThreadMemCheck.hpp"
#include "seec/Util/Fallthrough.hpp"
#include "seec/Util/ScopeExit.hpp"

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CallSite.h"

#include <cctype>
#include <cinttypes>
#include <cstdio>
#include <cstdarg>


//===----------------------------------------------------------------------===//
// scanf, fscanf, sscanf common methods
//===----------------------------------------------------------------------===//

/// \brief Attempt to match a sequence of literal characters.
///
bool matchNonConversionCharacters(int &CharactersRead,
                                  FILE *Stream,
                                  char const *Start,
                                  char const *End = nullptr)
{
  while(*Start && (End == nullptr || Start < End)) {
    if (std::isspace(*Start)) {
      // Match all whitespace characters.
      int ReadChar;
      
      while ((ReadChar = std::fgetc(Stream)) != EOF) {
        if (!std::isspace(ReadChar)) {
          std::ungetc(ReadChar, Stream);
          break;
        }
        
        ++CharactersRead;
      }
    }
    else {
      // Match a single character.
      int ReadChar = std::fgetc(Stream);
      if (ReadChar == EOF)
        return false;
      
      if (ReadChar != *Start) {
        std::ungetc(ReadChar, Stream);
        return false;
      }
      
      ++CharactersRead;
    }
    
    ++Start;
  }
  
  return true;
}

/// \brief Attempt to match an integer from a stream.
///
bool parseInt(int &CharactersRead,
              FILE *Stream,
              seec::trace::ScanConversionSpecifier const &Conversion,
              std::uintmax_t &Output)
{
  using namespace seec::trace;
  
  char Buffer[64];
  auto const BufferSize = sizeof(Buffer);
  
  auto Width = Conversion.Width;
  if (Width == 0 || Width > BufferSize - 1)
    Width = BufferSize - 1;
  
  bool Unsigned     = false;
  bool HexPrefixOK  = false;
  
  int Base = 0;
  
  switch (Conversion.Conversion) {
    case ScanConversionSpecifier::Specifier::d:
      Base = 10;
      break;
    case ScanConversionSpecifier::Specifier::i:
      break;
    case ScanConversionSpecifier::Specifier::o:
      Base = 8;
      Unsigned = true;
      break;
    case ScanConversionSpecifier::Specifier::u:
      Base = 10;
      Unsigned = true;
      break;
    case ScanConversionSpecifier::Specifier::x:
      Base = 16;
      Unsigned = true;
      break;
    default:
      llvm_unreachable("invalid conversion specifier for parseInt()");
      return false;
  }
  
  char *BufferPtr = Buffer;
  
  for (; Width != 0; --Width) {
    int ReadChar = std::fgetc(Stream);
    if (ReadChar == EOF) {
      if (std::ferror(Stream))
        return false;
      break;
    }
    
    bool ReadOK = true;
    
    switch (ReadChar) {
      // OK always. For %i, this sets the base to octal, unless it is followed
      // by 'x' or 'X', which will set the base to hexadecimal (we take care
      // of that when encountering 'x' or 'X').
      case '0':
        if (Base == 0) {
          Base = 8;
          HexPrefixOK = true;
        }
        break;
      
      // OK always.
      case '1': SEEC_FALLTHROUGH;
      case '2': SEEC_FALLTHROUGH;
      case '3': SEEC_FALLTHROUGH;
      case '4': SEEC_FALLTHROUGH;
      case '5': SEEC_FALLTHROUGH;
      case '6': SEEC_FALLTHROUGH;
      case '7':
        if (Base == 0)
          Base = 10;
        break;
      
      // OK iff decimal or hexadecimal.
      case '8': SEEC_FALLTHROUGH;
      case '9':
        if (Base == 0)
          Base = 10;
        else if (Base < 10)
          ReadOK = false;
        break;
      
      // OK iff hexadecimal.
      case 'A': SEEC_FALLTHROUGH;
      case 'a': SEEC_FALLTHROUGH;
      case 'B': SEEC_FALLTHROUGH;
      case 'b': SEEC_FALLTHROUGH;
      case 'C': SEEC_FALLTHROUGH;
      case 'c': SEEC_FALLTHROUGH;
      case 'D': SEEC_FALLTHROUGH;
      case 'd': SEEC_FALLTHROUGH;
      case 'E': SEEC_FALLTHROUGH;
      case 'e': SEEC_FALLTHROUGH;
      case 'F': SEEC_FALLTHROUGH;
      case 'f':
        if (Base < 16)
          ReadOK = false;
        break;
      
      // OK as first character.
      case '+': SEEC_FALLTHROUGH;
      case '-':
        if (BufferPtr != Buffer)
          ReadOK = false;
        break;
      
      // OK if part of the prefix "0x" or "0X".
      case 'X': SEEC_FALLTHROUGH;
      case 'x':
        if (HexPrefixOK) {
          Base = 16;
          HexPrefixOK = false;
        }
        else {
          ReadOK = false;
        }
        break;
      
      // Any other character is always invalid.
      default:
        ReadOK = false;
    }
    
    if (ReadOK) {
      *BufferPtr++ = static_cast<char>(ReadChar);
      ++CharactersRead;
    }
    else {
      // Push the character back into the stream.
      std::ungetc(ReadChar, Stream);
      break;
    }
  }
  
  // Short-circuit failure.
  if (BufferPtr == Buffer)
    return false;
  
  *BufferPtr = '\0';
  
  // Read the integer.
  char *ParseEnd = nullptr;
  
  if (Unsigned)
    Output = std::strtoumax(Buffer, &ParseEnd, Base);
  else
    Output = std::strtoimax(Buffer, &ParseEnd, Base);
  
  // Push unused characters back into the stream.
  if (ParseEnd != BufferPtr) {
    // Teach Clang's static analyzer that the value of ParseEnd following the
    // call to strtoumax or strtoimax will always be within the buffer range.
    assert(ParseEnd >= Buffer && ParseEnd < BufferPtr
           && "ParseEnd is not in buffer!");
    
    for (--BufferPtr; BufferPtr > ParseEnd; --BufferPtr) {
      std::ungetc(*BufferPtr, Stream);
    }
  }
  
  return (ParseEnd != Buffer);
}

/// \brief Implement checked scanf and fscanf.
///
static int
checkStreamScan(seec::runtime_errors::format_selects::CStdFunction FSFunction,
                unsigned VarArgsStartIndex,
                FILE *Stream,
                char const *Format)
{
  using namespace seec::trace;
  using namespace seec::runtime_errors;
  
  auto &ThreadEnv = getThreadEnvironment();
  auto &Listener = ThreadEnv.getThreadListener();
  auto Instruction = ThreadEnv.getInstruction();
  auto InstructionIndex = ThreadEnv.getInstructionIndex();
  auto Call = llvm::CallSite(Instruction);
  assert(Call && "expected call or invoke instruction.");
    
  // Interace with the thread listener's notification system.
  Listener.enterNotification();
  auto DoExit = seec::scopeExit([&](){ Listener.exitPostNotification(); });
  
  // Use a VarArgList to access our arguments.
  detect_calls::VarArgList<TraceThreadListener>
    VarArgs{Listener, Call, VarArgsStartIndex};

  // Lock IO streams and global memory.
  Listener.acquireGlobalMemoryWriteLock();
  auto StreamsAccessor = Listener.getProcessListener().getStreamsAccessor();
  
  // Use a CIOChecker to help check memory.
  CIOChecker Checker{Listener,
                     InstructionIndex,
                     FSFunction,
                     StreamsAccessor.getObject()};
  
  // Check that the stream is valid.
  if (Stream == stdin || Stream == stdout || Stream == stderr) {
    Checker.checkStandardStreamIsValid(Stream);
  }
  else {
    Checker.checkStreamIsValid(0, Stream);
  }
  
  // Check and perform the (f)scanf.
  auto FormatSize = Checker.checkCStringRead(VarArgsStartIndex - 1, Format);
  if (!FormatSize) {
    Listener.notifyValue(InstructionIndex, Instruction, unsigned(0));
    return 0;
  }
  
  int NumConversions = 0;
  int NumAssignments = 0;
  int NumCharsRead = 0;
  unsigned NextArg = 0;
  char const *NextChar = Format;
  bool InputFailure = false;
  bool CriticalError = false;
  llvm::SmallVector<std::pair<char const *, std::size_t>, 8> StateChanges;
  
  while (!CriticalError) {
    auto Conversion = ScanConversionSpecifier::readNextFrom(NextChar);
    if (!Conversion.Start) {
      // Attempt to match and consume remaining characters.
      matchNonConversionCharacters(NumCharsRead, Stream, NextChar);
      break;
    }
    
    // Attempt to match and consume [NextChar, Conversion.Start).
    if (!matchNonConversionCharacters(NumCharsRead, Stream, NextChar,
                                      Conversion.Start))
      break;
    
    auto const StartIndex = Conversion.Start - Format;
    
    // Ensure that the conversion specifier was parsed correctly.
    if (!Conversion.End) {
      Listener.handleRunError(
        *createRunError<RunErrorType::FormatSpecifierParse>
                       (FSFunction, VarArgsStartIndex - 1, StartIndex),
        RunErrorSeverity::Fatal,
        InstructionIndex);
      
      break; // Leave the main processing loop.
    }
    
    auto const EndIndex = Conversion.End - Format;
    
    // If assignment was suppressed, ensure that suppressing assignment is OK.
    if (Conversion.SuppressAssignment) {
      if (!Conversion.allowedSuppressAssignment()) {
        Listener.handleRunError(
          *createRunError<RunErrorType::FormatSpecifierSuppressionDenied>
                         (FSFunction,
                          VarArgsStartIndex - 1,
                          StartIndex,
                          EndIndex),
          RunErrorSeverity::Fatal,
          InstructionIndex);
        
        break; // Leave the main processing loop.
      }
    }
    else {
      // Check that the argument type matches the expected type. Don't check
      // that the argument exists here, because some conversion specifiers don't
      // require an argument (i.e. %%), so we check if it exists when needed, in
      // the isArgumentTypeOK() implementation.
      if (!Conversion.isArgumentTypeOK(VarArgs, NextArg)) {
        Listener.handleRunError(
          *createRunError<RunErrorType::FormatSpecifierArgType>
                         (FSFunction,
                          VarArgsStartIndex - 1,
                          StartIndex,
                          EndIndex,
                          asCFormatLengthModifier(Conversion.Length),
                          VarArgs.offset() + NextArg),
          RunErrorSeverity::Fatal,
          InstructionIndex);
        
        break; // Leave the main processing loop.
      }

      // If the argument type is a pointer, check that the destination is
      // writable. The conversion for strings (and sets) is a special case.
      if (Conversion.Conversion == ScanConversionSpecifier::Specifier::s
          || Conversion.Conversion == ScanConversionSpecifier::Specifier::set) {
        if (NextArg < VarArgs.size() && Conversion.WidthSpecified) {
          // Check that the destination is writable and has sufficient space
          // for the field width specified by the programmer.
          auto MaybeArea = Conversion.getArgumentPointee(VarArgs, NextArg);
          auto const Size = (Conversion.Length == LengthModifier::l)
                          ? (Conversion.Width + 1) * sizeof(wchar_t)
                          : (Conversion.Width + 1) * sizeof(char);
          
          if (!Checker.checkMemoryExistsAndAccessibleForParameter(
                  VarArgs.offset() + NextArg,
                  reinterpret_cast<uintptr_t>(MaybeArea.get<0>().first),
                  Size,
                  seec::runtime_errors::format_selects::MemoryAccess::Write))
            
            break; // Leave the main processing loop.
        }
      }
      else {
        auto MaybePointeeArea = Conversion.getArgumentPointee(VarArgs, NextArg);
        if (MaybePointeeArea.assigned()) {
          auto const &Area = MaybePointeeArea.get<0>();
          Checker.checkMemoryExistsAndAccessibleForParameter(
            VarArgs.offset() + NextArg,
            reinterpret_cast<uintptr_t>(Area.first),
            Area.second,
            seec::runtime_errors::format_selects::MemoryAccess::Write);
        }
      }
    }
    
{'fraction_non_alphanumeric': 0.13009454198776516, 'fraction_numerical': 0.004528481766902359, 'mean_word_length': 1.9575892857142858, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5611915', 'n_tokens_mistral': 7461, 'n_tokens_neox': 7216, 'n_words': 1834}