//===------- string.cpp - CStdLib Runtime functions for <string.h> --------===//
// 
//                          The SAFECode Compiler
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
//
// This file provides CStdLib runtime wrapper versions of functions found in
// <string.h>.
//
//===----------------------------------------------------------------------===//

#include "safecode/Config/config.h"
#include "CStdLib.h"

#include <string.h>
#include <algorithm>

//
// Function: poolcheckstr()
//
// Description:
//  This function is a generic load check on a string.  It is intended to be
//  used for C library functions that take a string and read its contents.
//
// Inputs:
//   Pool - The pool handle for the pool in which the string should be.
//          Pool handles can be NULL.
//   str  - A pointer to the string to check.
//
// Notes:
//   We have versions of poolcheckstr() for incomplete/unknown pointers as
//   well as debug versions that pass along debugging information.
//
void
poolcheckstr (DebugPoolTy * Pool, const char * str) {
  if (str == NULL) return;
  validStringCheck (str, Pool, true, "Generic", DEFAULT_SRC_INFO);
}

void
poolcheckstr_debug (DebugPoolTy * Pool, char * str, TAG, SRC_INFO) {
  if (str == NULL) return;
  validStringCheck (str, Pool, true, "Generic", SRC_INFO_ARGS);
}

void
poolcheckstrui (DebugPoolTy * Pool, char * str) {
  if (str == NULL) return;
  validStringCheck (str, Pool, false, "Generic", DEFAULT_SRC_INFO);
}

void
poolcheckstrui_debug (DebugPoolTy * Pool, char * str, TAG, SRC_INFO) {
  if (str == NULL) return;
  validStringCheck (str, Pool, false, "Generic", SRC_INFO_ARGS);
}

//
// pool_memccpy()
//
// See pool_memccpy_debug().
//
void *
pool_memccpy(DebugPoolTy *dPool,
             DebugPoolTy *sPool, 
             void *d,
             void *s,
             char c,
             size_t n,
             const uint8_t complete) {
  return pool_memccpy_debug(dPool, sPool, d, s, c, n, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace memccpy()
//
// Inputs:
//   dstPool  Pool handle for destination memory area
//   srcPool  Pool handle for source memory area
//   dst      Destination memory area
//   src      Source memory area
//   c        Stop copying when we see this byte
//   n        Maximum number of bytes to copy
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
//
// Returns:
//   A pointer to the first byte after c in dst or, if c was not found in the
//   first n bytes of s2, it returns a null pointer.
//
void *
pool_memccpy_debug(DebugPoolTy *dstPool, 
                   DebugPoolTy *srcPool, 
                   void *dst, 
                   void *src, 
                   int c,
                   size_t n,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  size_t dstSize = 0, srcSize = 0;
  void *dstBegin = dst, *dstEnd = NULL, *srcBegin = src, *srcEnd = NULL, *stop;
  const bool dstComplete = ARG1_COMPLETE(complete);
  const bool srcComplete = ARG2_COMPLETE(complete);
  bool dstFound, srcFound;
  // Retrieve both the destination and source buffer's bounds from the handles.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(dst, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(src, srcPool, SRC_INFO_ARGS);
  }
  if (srcFound) {
    // Calculate the maximum number of bytes to copy.
    srcSize = byte_range(src, srcEnd);
    // Get the position of the byte which terminates copying.
    stop = memchr(src, c, srcSize);
    // Get the number of bytes that will be copied over.
    size_t bytesToCopy = stop != NULL ? byte_range(src, stop) : n;
    if (bytesToCopy > srcSize) {
      err << "Cannot copy more bytes than the size of the source!\n";
      OOB_VIOLATION(src, srcPool, src, bytesToCopy, SRC_INFO_ARGS);
    }
    if (dstFound) {
      dstSize = byte_range(dst, dstEnd);
      if (bytesToCopy > dstSize) {
        err << "Cannot copy more bytes than the size of the destination!\n";
        WRITE_VIOLATION(dstBegin, dstPool, dstSize, bytesToCopy, SRC_INFO_ARGS);
      }
      const char *dstLimit = (char *) dst + bytesToCopy - 1;
      const char *srcLimit = (char *) src + bytesToCopy - 1;
      if (isOverlapped(dst, dstLimit, src, srcLimit)) { 
        err << "Input memory objects overlap each other!\n";
        C_LIBRARY_VIOLATION(dst, dstPool, "memccpy", SRC_INFO_ARGS);
      }
    }
  }
  return memccpy(dst, src, c, n);
}

//
// pool_memchr()
//
// See pool_memchr_debug().
//
void *
pool_memchr(DebugPoolTy *stringPool, 
            void *string, 
            int c, 
            size_t n,
            const uint8_t complete) {
  return pool_memchr_debug(stringPool, string, c, n,complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace memchr()
//
// Inputs:
//   stringPool  Pool handle for the string
//   string      Memory object
//   c           A byte value to be found
//   n           Number of bytes to search in
//   complete    Completeness bit vector
//   TAG         Tag information for debugging purposes
//   SRC_INFO    Source file and line number information for debugging purposes
//
// Returns:
//   This returns a pointer to the first location of c in the string, or NULL
//   if not found.
//
void *
pool_memchr_debug(DebugPoolTy *strPool, 
                  void *str,
                  int c, 
                  size_t n,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  size_t strSize = 0;
  void *strBegin = str, *strEnd = NULL, *stop= NULL;
  const bool strComplete = ARG1_COMPLETE(complete);
  bool strFound;
  // Retrieve the memory buffer's boundaries from the pool.
  if (!(strFound = pool_find(strPool, str, strBegin, strEnd)) && strComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(str, strPool, SRC_INFO_ARGS);
  }
  // If the boundaries are found, determine if memchr() would read beyond them.
  if (strFound) {
    strSize = std::min(byte_range(str, strEnd), n);
    stop    = memchr(str, c, strSize);
    if (stop != NULL)
      return stop;
    else if (n > strSize) {
      err << "memchr() reads past the end of the memory object!\n";
      OOB_VIOLATION(str, strPool, str, n, SRC_INFO_ARGS);
    }
  }
  return memchr(str, c, n);
}

//
// pool_memcmp()
//
// See pool_memcmp_debug().
//
int
pool_memcmp(DebugPoolTy *s1p,
            DebugPoolTy *s2p, 
            void *s1, 
            void *s2,
            size_t num,
            const uint8_t complete) {
    return pool_memcmp_debug(s1p, s2p, s1, s2, num, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace memcmp()
//
// Inputs:
//   str1Pool Pool handle for memory object1
//   str2Pool Pool handle for memory object1
//   num      Maximum number of bytes to compare
//   str1     Memory object 1 to be compared
//   str2     Memory object 2 to be compared
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
//
// Returns:
//   This function returns 0 if the memory areas are identical or else the
//   difference between the first two bytes that are not identical.
//
int
pool_memcmp_debug(DebugPoolTy *s1Pool,
                  DebugPoolTy *s2Pool, 
                  void *s1, 
                  void *s2,
                  size_t num,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  size_t s1Size = 0, s2Size = 0;
  void *s1Begin = s1, *s1End = NULL, *s2Begin = s2, *s2End = NULL;
  const bool s1Complete = ARG1_COMPLETE(complete);
  const bool s2Complete = ARG2_COMPLETE(complete);
  bool s1Found, s2Found;
  if (!(s1Found = pool_find(s1Pool, s1, s1Begin, s1End)) && s1Complete) {
    err << "Bytestring 1 not found in pool!\n";
    LOAD_STORE_VIOLATION(s1Begin, s1Pool, SRC_INFO_ARGS);
  }
  if (!(s2Found = pool_find(s2Pool, s2, s2Begin, s2End)) && s2Complete) {
    err << "Bytestring 2 not found in pool!\n";
    LOAD_STORE_VIOLATION(s2Begin, s2Pool, SRC_INFO_ARGS);
  }
  // These sizes are how far a read can continue safely.
  s1Size = s1Found ? byte_range(s1, s1End) : num;
  s2Size = s2Found ? byte_range(s2, s2End) : num;
  size_t p;
  const unsigned char *cs1 = (unsigned char *) s1;
  const unsigned char *cs2 = (unsigned char *) s2;
  // If we know the size of the memory objects, we can stop before we read out
  // of bounds.
  size_t stop = std::min(num, std::min(s1Size, s2Size));
  for (p = 0; p < stop; p++)
    if (cs1[p] != cs2[p])
      return cs1[p] - cs2[p];
  if (p == num)
    return 0;
  if (s1Found && p == s1Size) {
    err << "memcmp() reads beyond the end of bytestring 1!\n";
    OOB_VIOLATION(s1, s1Pool, s1, s1Size + 1, SRC_INFO_ARGS);
  }
  if (s2Found && p == s2Size) {
    err << "memcmp() reads beyond the end of bytestring 2!\n";
    OOB_VIOLATION(s2, s2Pool, s2, s2Size + 1, SRC_INFO_ARGS);
  }
  return memcmp(s1, s2, num);
}

//
// pool_memcpy()
//
// See pool_memcpy_debug().
//
void *
pool_memcpy(DebugPoolTy *dstPool, 
            DebugPoolTy *srcPool, 
            void *dst, 
            void *src, 
            size_t n,
            const uint8_t complete) {
  return pool_memcpy_debug(dstPool, srcPool, dst, src, n, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace memcpy()
//
// Inputs:
//   dstPool  Pool handle for destination memory area
//   srcPool  Pool handle for source memory area
//   dst      Destination memory area
//   src      Source memory area
//   n        Maximum number of bytes to copy
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
//
// Returns:
//  This function returns the value of dst.
//
void *
pool_memcpy_debug(DebugPoolTy *dstPool, 
                  DebugPoolTy *srcPool, 
                  void *dst, 
                  void *src, 
                  size_t n,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  size_t dstSize = 0, srcSize = 0;
  void *dstBegin = dst, *dstEnd = NULL, *srcBegin = src, *srcEnd = NULL;
  const bool dstComplete = ARG1_COMPLETE(complete);
  const bool srcComplete = ARG2_COMPLETE(complete);
  bool dstFound = false, srcFound = false;
  // Retrieve both the destination and source buffers' bounds from the handles.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Destination object not found in pool!\n";
    LOAD_STORE_VIOLATION(dst, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Source object not found in pool!\n";
    LOAD_STORE_VIOLATION(src, srcPool, SRC_INFO_ARGS);
  }
  // Calculate the maximum number of bytes to copy.
  dstSize = byte_range(dst, dstEnd);
  srcSize = byte_range(src, srcEnd);
  if (srcFound && n > srcSize) {
    err << "memcpy() reads beyond the source object's boundaries!\n";
    OOB_VIOLATION(src, srcPool, src, n, SRC_INFO_ARGS);
  }
  if (dstFound && n > dstSize) {
    err << "memcpy() writes beyond the destination object's boundaries!\n";
    WRITE_VIOLATION(dst, dstPool, dstSize, n, SRC_INFO_ARGS);
  }
  if (dstFound && srcFound) {
    const char *srcLimit = (char *) src + n - 1;
    const char *dstLimit = (char *) dst + n - 1;
    if (isOverlapped(dst, dstLimit, src, srcLimit)) { 
      err << "Input memory objects overlap each other!\n";
      C_LIBRARY_VIOLATION(dst, dstPool, "memcpy", SRC_INFO_ARGS);
    }
  }
  return memcpy(dst, src, n);
}

//
// pool_memmove()
//
// See pool_memmove_debug().
//
void *
pool_memmove(DebugPoolTy *dstPool, 
             DebugPoolTy *srcPool, 
             void *dst, 
             void *src, 
             size_t n,
             const uint8_t complete) {
  return pool_memmove_debug(dstPool, srcPool, dst, src, n, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace memmove()
//
// Inputs:
//   dstPool  Pool handle for destination memory area
//   srcPool  Pool handle for source memory area
//   dst      Destination memory area
//   src      Source memory area
//   n        Maximum number of bytes to copy
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the value of dst.
//
void *
pool_memmove_debug(DebugPoolTy *dstPool, 
                   DebugPoolTy *srcPool, 
                   void *dst, 
                   void *src, 
                   size_t n,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  size_t dstSize = 0, srcSize = 0;
  void *dstBegin = dst, *dstEnd = NULL, *srcBegin = src, *srcEnd = NULL;
  const bool dstComplete = ARG1_COMPLETE(complete);
  const bool srcComplete = ARG2_COMPLETE(complete);
  bool dstFound, srcFound;
  // Retrieve both the destination and source buffers' bounds from the pools.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Destination object not found in pool!\n";
    LOAD_STORE_VIOLATION(dst, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Source object not found in pool!\n";
    LOAD_STORE_VIOLATION(src,srcPool, SRC_INFO_ARGS);
  }
  // Calculate the maximum number of bytes to copy safely.
  dstSize = byte_range(dst, dstEnd);
  srcSize = byte_range(src, srcEnd);
  if (srcFound && n > srcSize) {
    err << "memmove() reads beyond the end of the source bytestring!\n";
    OOB_VIOLATION(src, srcPool, src, n, SRC_INFO_ARGS);
  }
  if (dstFound && n > dstSize) {
    err << "memmove() write beyond the end of the destination bytestring!\n";
    OOB_VIOLATION(dst, dstPool, dst, n, SRC_INFO_ARGS);
  }
  // We don't need to check for overlap - memmove() already handles this.
  return memmove(dst, src, n);
}

//
// pool_memset()
//
// See pool_memset_debug().
//
void *pool_memset(DebugPoolTy *stringPool, 
                  void *string, 
                  int c, 
                  size_t n,
                  const uint8_t complete) {
  return pool_memset_debug(stringPool, string, c, n,complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace memset()
//
// Inputs:
//   sPool    Pool handle for the bytestring
//   s        Bytestring pointer
//   c        The byte to write
//   n        Number of bytes to be set
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the value of s.
//
void *
pool_memset_debug(DebugPoolTy *sPool, 
                  void *s, 
                  int c, 
                  size_t n,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  size_t size = 0;
  void *sBegin = s, *sEnd = NULL;
  const bool sComplete = ARG1_COMPLETE(complete);
  bool sFound;
  // Retrive the object bounds.
  if (!(sFound = pool_find(sPool, s, sBegin, sEnd)) && sComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(s, sPool, SRC_INFO_ARGS);
  }
  size = byte_range(s, sEnd);
  // Check for writing out of bounds error.
  if (sFound && n > size) {
    err << "memset() writes beyond the end of the destination object!\n";
    WRITE_VIOLATION(s, sPool, size, n, SRC_INFO_ARGS);
  }
  return memset(s, c, n);
}

//
// pool_strcat()
//
// See pool_strcat_debug().
//
char *
pool_strcat(DebugPoolTy *dp,
            DebugPoolTy *sp,
            char *d,
            char *s,
            const unsigned char c) {
  return pool_strcat_debug(dp, sp, d, s, c, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strcat()
//
// Appends the source string to the end of the destination string.
// Attempts to verify the following:
//  - source and destination pointers point to valid strings
//  - there is no overlap between source and destination strings
//  - the destination string's object has enough space to hold the
//    concatenation in memory.
//
// Inputs:
//   dp    Pool handle for destination string
//   sp    Pool handle for source string
//   d     Pointer to the destination string
//   s     Pointer to the source string
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns a pointer to the destination string.
//
char *
pool_strcat_debug(DebugPoolTy *dstPool,
                  DebugPoolTy *srcPool,
                  char *dst,
                  char *src,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  size_t srcLen = 0, dstLen = 0, maxLen, catLen;
  void *dstBegin = NULL, *dstEnd = NULL;
  void *srcBegin = NULL, *srcEnd = NULL;
  char *dstNulPosition;
  bool srcFound, dstFound, srcTerminated = false, dstTerminated = false;
  const bool srcComplete = ARG1_COMPLETE(complete);
  const bool dstComplete = ARG2_COMPLETE(complete);
  // Find the strings' memory objects in the pools.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Destination string not found in pool\n";
    LOAD_STORE_VIOLATION(dstBegin, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Source string not found in pool!\n";
    LOAD_STORE_VIOLATION(srcBegin, srcPool, SRC_INFO_ARGS);
  }
  // Check if both src and dst are terminated, if they were found in their pool.
  if (dstFound && !(dstTerminated = isTerminated(dst, dstEnd, dstLen))) {
    err << "Destination not terminated within bounds\n";
    C_LIBRARY_VIOLATION(dst, dstPool, "strcat", SRC_INFO_ARGS);
  }
  if (srcFound && !(srcTerminated = isTerminated(src, srcEnd, srcLen))) {
    err << "Source not terminated within bounds\n";
    C_LIBRARY_VIOLATION(src, srcPool, "strcat", SRC_INFO_ARGS);
  }
  // We assume an object that is not complete and not found is valid.
  // So get its length.
  if (!srcFound && !srcComplete) {
    srcTerminated = true;
    srcLen = strlen(src);
  }
  if (!dstFound && !dstComplete) {
    dstTerminated = true;
    dstLen = strlen(dst);
  }
  // The remainder of the checks require the string length to be known.
  if (dstTerminated && srcTerminated) {
    maxLen = byte_range(dst, dstEnd) - 1;
    catLen = srcLen + dstLen;
    // Do the check for if concatenation writes out of bounds.
    if (catLen > maxLen) {
      err << "Concatenation violated destination bounds!\n";
      WRITE_VIOLATION(dstBegin, dstPool, maxLen + 1, catLen + 1, SRC_INFO_ARGS);
    }
    // Overlap occurs exactly when they share the same nul terminator in memory.
    if (&dst[dstLen] == &src[srcLen]) {
      err << "Concatenating overlapping strings is undefined\n";
      C_LIBRARY_VIOLATION(dst, dstPool, "strcat", SRC_INFO_ARGS);
    }
    // Append at the end of dst so concatenation doesn't have to scan dst again.
    dstNulPosition = &dst[dstLen];
    strncat(dstNulPosition, src, srcLen);
    return dst;
  }
  else
    return strcat(dst, src);
}

//
// pool_strchr()
//
// This is the non-debug version of pool_strchr_debug().
//
//
char *
pool_strchr(DebugPoolTy *sp, char *s, int c, const uint8_t complete) {
  return pool_strchr_debug(sp, s, c, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strchr()
//
// Returns pointer to the first instance of the given character in the string,
// or NULL if not found.
//
// Ensures the following:
//  - string argument points to a valid string
//
// Inputs:
//   sPool     Pool handle for string
//   s         String pointer
//   c         Character to find
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns a pointer to the first instance of the given
//   character in the string, or NULL if not found.
//
char *
pool_strchr_debug(DebugPoolTy *sPool,
                  char *s,
                  int c,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  validStringCheck(s, sPool, ARG1_COMPLETE(complete), "strchr", SRC_INFO_ARGS);
  return strchr(s, c);
}

//
// pool_strcmp()
//
// See pool_strcmp_debug().
//
int
pool_strcmp(DebugPoolTy *s1p,
            DebugPoolTy *s2p, 
            char *s1, 
            char *s2,
            const uint8_t complete){
  return pool_strcmp_debug(s1p, s2p, s1, s2, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strcmp()
//
// Inputs:
//   s1Pool   Pool handle for str1
//   s2Pool   Pool handle for str2
//   s1       C string to be compared
//   s2       C string to be compared
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//  This function returns a negative, zero, or positive integer depending on
//  whether s1 < s2, s1 = s2, or s1 > s2.
//
int
pool_strcmp_debug(DebugPoolTy *s1Pool,
                  DebugPoolTy *s2Pool, 
                  char *s1, 
                  char *s2,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  const bool s1Complete = ARG1_COMPLETE(complete);
  const bool s2Complete = ARG2_COMPLETE(complete);
  validStringCheck(s1, s1Pool, s1Complete, "strcmp", SRC_INFO_ARGS);
  validStringCheck(s2, s2Pool, s2Complete, "strcmp", SRC_INFO_ARGS);
  return strcmp(s1, s2);
}

//
// pool_strcoll()
//
// See pool_strcoll_debug().
//
int
pool_strcoll(DebugPoolTy *s1p,
             DebugPoolTy *s2p, 
             char *s1, 
             char *s2,
             const uint8_t complete){
  return pool_strcoll_debug(s1p, s2p, s1, s2, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strcoll()
//
// Inputs:
//   s1Pool   Pool handle for str1
//   s2Pool   Pool handle for str2
//   s1       C string to be compared
//   s2       C string to be compared
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//  This function returns a negative, zero, or positive integer depending on
//  whether s1 < s2, s1 = s2, or s1 > s2, in the ordering described by the
//  value of the LC_COLLATE category of the current locale.
//
int
pool_strcoll_debug(DebugPoolTy *s1Pool,
                   DebugPoolTy *s2Pool, 
                   char *s1, 
                   char *s2,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  const bool s1Complete = ARG1_COMPLETE(complete);
  const bool s2Complete = ARG2_COMPLETE(complete);
  validStringCheck(s1, s1Pool, s1Complete, "strcoll", SRC_INFO_ARGS);
  validStringCheck(s2, s2Pool, s2Complete, "strcoll", SRC_INFO_ARGS);
  return strcoll(s1, s2);
}

//
// pool_strcpy()
//
// See pool_strcpy_debug().
//
char *
pool_strcpy(DebugPoolTy *dstPool, 
            DebugPoolTy *srcPool, 
            char *dst, 
            char *src, 
            const uint8_t complete) {
  return pool_strcpy_debug(dstPool, srcPool, dst, src, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strcpy()
//
// Inputs:
//   dstPool  Pool handle for destination buffer
//   srcPool  Pool handle for source string
//   dst      Destination string pointer
//   src      Source string pointer
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the destination string pointer.
//
char *
pool_strcpy_debug(DebugPoolTy *dstPool, 
                  DebugPoolTy *srcPool, 
                  char *dst, 
                  char *src, 
                  const uint8_t complete, 
                  TAG,
                  SRC_INFO) {
  size_t dstMax = 0, srcLen = 0;
  void *dstBegin = dst, *dstEnd = NULL, *srcBegin = src, *srcEnd = NULL;
  const bool dstComplete = ARG1_COMPLETE(complete);
  const bool srcComplete = ARG2_COMPLETE(complete);
  bool dstFound, srcFound, srcTerminated;
  // Retrieve both the destination and source buffer's bounds from the pools.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(dst, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(src,srcPool, SRC_INFO_ARGS);
  }
  // Check for source termination.
  if (srcFound && !(srcTerminated = isTerminated(src, srcEnd, srcLen))) {
    err << "Source string is not terminated within object bounds!\n";
    C_LIBRARY_VIOLATION(src, srcPool, "strcpy", SRC_INFO_ARGS);
  }
  if (dstFound) {
    // Assume an incomplete and not found object is valid.
    if (!srcFound && !srcComplete) {
      srcTerminated = true;
      srcLen = strlen(src);
    }
    // The remainder of the checks require us to know the length of src.
    if (srcTerminated) {
      dstMax = byte_range(dst, dstEnd) - 1;
      // Check for writing out of bounds errors.
      if (srcLen > dstMax) {
        err << "strcpy() writes beyond the end of the destination object!\n";
        WRITE_VIOLATION(dst, dstPool, dstMax + 1, srcLen + 1, SRC_INFO_ARGS);
      }
      // Check for overlap.
      void *dstEdge = srcLen + (char *) dst;
      void *srcEdge = srcLen + (char *) src;
      if (isOverlapped(dst, dstEdge, src, srcEdge)) {
        err << "Memory objects in call to strcpy() overlap each other!\n";
        C_LIBRARY_VIOLATION(dst, dstPool, "strcpy", SRC_INFO_ARGS);
      }
    }
  }
  return strcpy(dst, src);
}

//
// pool_strcspn()
//
// See pool_strcspn_debug().
//
size_t pool_strcspn(DebugPoolTy *s1p,
                    DebugPoolTy *s2p, 
                    char *s1, 
                    char *s2,
                    const uint8_t complete) {
  return pool_strcspn_debug(s1p, s2p, s1, s2, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strcspn()
//
// Inputs:
//   str1Pool Pool handle for str1
//   str2Pool Pool handle for str2
//   str1     C string to be compared
//   str2     C string to be compared
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the length of the initial portion of str1 that does
//   not contain any character from str2.
//
size_t
pool_strcspn_debug(DebugPoolTy *str1Pool,
                   DebugPoolTy *str2Pool, 
                   char *str1, 
                   char *str2,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  const bool str1Complete = ARG1_COMPLETE(complete);
  const bool str2Complete = ARG2_COMPLETE(complete);
  validStringCheck(str1, str1Pool, str1Complete, "strcspn", SRC_INFO_ARGS);
  validStringCheck(str2, str2Pool, str2Complete, "strcspn", SRC_INFO_ARGS);
  return strcspn(str1, str2);
}

//
// pool_strlen()
//
// See pool_strlen_debug().
//
size_t
pool_strlen(DebugPoolTy *stringPool,
            char *string,
            const uint8_t complete) {
  return pool_strlen_debug(stringPool, string, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strlen()
//
// Inputs:
//   strPool  Pool handle for the string
//   str      String pointer
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the length of the input string.
//
size_t
pool_strlen_debug(DebugPoolTy *strPool, 
                  char *str, 
                  const uint8_t complete, 
                  TAG, 
                  SRC_INFO) {
  const bool strComplete = ARG1_COMPLETE(complete);
  bool strFound;
  size_t len = 0;
  void *strBegin = 0, *strEnd = 0;
  if (!(strFound = pool_find(strPool, str, strBegin, strEnd)) && strComplete) {
    err << "Object for string not found in pool!\n";
    LOAD_STORE_VIOLATION(str, strPool, SRC_INFO_ARGS);
  }
  if (strFound) {
    if (!isTerminated(str, strEnd, len)) {
      err << "Input string not terminated within object boundaries!\n";
      C_LIBRARY_VIOLATION(str, strPool, "strlen", SRC_INFO_ARGS);
    }
    else
      return len;
  }
  return strlen(str);
}

//
// pool_strncat()
//
// See pool_strncat_debug().
//
char *
pool_strncat(DebugPoolTy *dstPool,
             DebugPoolTy *srcPool,
             char *dst,
             char *src,
             size_t n,
             const uint8_t complete) {
  return pool_strncat_debug(dstPool, srcPool, dst, src, n, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strncat()
//
// Appends at most n characters of src onto the end of the string dst
// and then adds a nul terminator.
//
// Checks for the following:
//  - src and dst are non-null
//  - dst is terminated
//  - dst has enough space to hold the whole concatention
//  - src and dst do not overlap
//  - if src is unterminated, the first n characters of src fall within
//    the boundaries of src.
//
// Inputs:
//   dstPool  Pool handle for destination string
//   srcPool  Pool handle for source string
//   dst      Destination string pointer
//   src      Source string pointer
//   n        Number of characters to copy over
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns a pointer to the destination buffer.
//
char *
pool_strncat_debug(DebugPoolTy *dstPool,
                   DebugPoolTy *srcPool,
                   char *dst,
                   char *src,
                   size_t n,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  void *dstBegin = NULL, *dstEnd = NULL;
  void *srcBegin = NULL, *srcEnd = NULL;
  size_t dstLen = 0, srcLen = 0, maxLen, catLen, srcAmt;
  char *dstNulPosition;
  bool srcFound, dstFound, srcTerminated = false, dstTerminated;
  const bool srcComplete = ARG1_COMPLETE(complete);
  const bool dstComplete = ARG2_COMPLETE(complete);
  // Retrieve destination and source string memory objects from pool.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Destination string not found in pool!\n";  
    LOAD_STORE_VIOLATION(dstBegin, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Source string not found in pool!\n";  
    LOAD_STORE_VIOLATION(srcBegin, srcPool, SRC_INFO_ARGS);
  }
  // Check if dst is nul terminated.
  if (dstFound && !(dstTerminated = isTerminated(dst, dstEnd, dstLen))) {
    err << "String not terminated within bounds\n";
    C_LIBRARY_VIOLATION(dst, dstPool, "strncat", SRC_INFO_ARGS);
  }
  // According to POSIX, src doesn't have to be nul-terminated.
  // If it isn't, ensure strncat that doesn't read beyond the bounds of src.
  if (srcFound) {
    srcTerminated = isTerminated(src, srcEnd, srcLen);
  } else if (!srcFound && !srcComplete) {
    srcLen = _strnlen(src, n);
    srcTerminated = srcLen < n;
  }
  // Check if the number of bytes in source is < the number of bytes we have to
  // copy.
  // This will result in reading out of bounds.
  if (srcFound && !srcTerminated && byte_range(src, srcEnd) < n) {
    err << "strncat() reads beyond the boundaries of the source object!\n";
    OOB_VIOLATION(src, srcPool, src, srcLen, SRC_INFO_ARGS);
  }
  // The remaining checks require us to know the lengths of the destination and
  // the object boundaries of the source string.
  if (srcFound && dstTerminated) {
    // Determine the amount of characters to be copied over from src.
    // If the string is terminated, this is the smaller of n or the length of
    // src.
    // Otherwise this is n.
    srcAmt = srcTerminated ? std::min(srcLen, n) : n;
    // Check for undefined behavior due to overlapping objects.
    // Overlap occurs when the characters to be copied from src
    // end inside the dst string. &src[srcAmt] represents one past the end of
    // what will be copied over.
    if (dst < &src[srcAmt] && &src[srcAmt] <= &dst[dstLen]) {
      err << "Concatenating overlapping objects is undefined\n";
      C_LIBRARY_VIOLATION(dst, dstPool, "strncat", SRC_INFO_ARGS);
    }
    // maxLen is the maximum length string dst can hold without overflowing.
    maxLen = byte_range(dst, dstEnd) - 1;
    // catLen is the length of the string resulting from the concatenation.
    catLen = srcAmt + dstLen;
    // Check if the copy operation would go beyong the bounds of dst.
    if (catLen > maxLen) {
      err << "Concatenation violated destination bounds!\n";
      WRITE_VIOLATION(dst, dstPool, 1+maxLen, 1+catLen, SRC_INFO_ARGS);
    }
    // Start concatenation the end of dst so strncat() doesn't have to scan dst
    // all over again.
    dstNulPosition = &dst[dstLen];
    strncat(dstNulPosition, src, srcAmt);
    // strncat() returns the original destination string.
    return dst;
  }
  else
    return strncat(dst, src, n);
}

//
// pool_strncmp()
//
// See pool_strncmp_debug().
//
int
pool_strncmp(DebugPoolTy *s1p,
             DebugPoolTy *s2p, 
             char *s1, 
             char *s2,
             size_t num,
             const uint8_t complete){
  return pool_strncmp_debug(s1p,s2p,s1,s2,num,complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strncmp()
//
// Inputs:
//   s1Pool Pool handle for string1
//   s2Pool Pool handle for string2
//   n      Maximum number of chars to compare
//   s1     string1 to be compared
//   s2     string2 to be compared
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns a negative, zero, or positive integer depending on if
//   s1 < s2, s1 = s2, or s1 > s2 in the first n characters.
//
int
pool_strncmp_debug(DebugPoolTy *s1Pool,
                   DebugPoolTy *s2Pool, 
                   char *s1, 
                   char *s2,
                   size_t n,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {  
  size_t s1Size = 0, s2Size = 0;
  void *s1Begin = s1, *s1End = NULL, *s2Begin = s2, *s2End = NULL;
  const bool s1Complete = ARG1_COMPLETE(complete);
  const bool s2Complete = ARG2_COMPLETE(complete);
  bool s1Found, s2Found;
  // Find the objects in their pools.
  if (!(s1Found = pool_find(s1Pool, s1, s1Begin, s1End)) && s1Complete) {
    err << "String 1 not found in pool!\n";
    LOAD_STORE_VIOLATION(s1Begin, s1Pool, SRC_INFO_ARGS);
  }
  if (!(s2Found = pool_find(s2Pool, s2, s2Begin, s2End)) && s2Complete) {
    err << "String 2 not found in pool!\n";
    LOAD_STORE_VIOLATION(s1Begin, s1Pool, SRC_INFO_ARGS);
  }
  // These sizes represent the 'safe' range to read.
  s1Size = s1Found ? byte_range(s1, s1End) : n;
  s2Size = s2Found ? byte_range(s2, s2End) : n;
  size_t stop = std::min(n, std::min(s1Size, s2Size));
  size_t p;
  // Comparison is done using unsigned characters.
    const unsigned char *cs1 = (const unsigned char *) s1;
  const unsigned char *cs2 = (const unsigned char *) s2;
  for (p = 0; p < stop; p++) {
    if (cs1[p] != cs2[p])
      return cs1[p] - cs2[p];
    // We're comparing strings, so a nul terminator indicates we're done. 
    else if (cs1[p] == 0)
      return 0;
  }
  if (p == n)
    return 0;
  if (s1Found && p == s1Size) {
    err << "strncmp() reads beyond the end of string 1!\n";
    OOB_VIOLATION(s1, s1Pool, s1, s1Size + 1, SRC_INFO_ARGS);
  }
  if (s2Found && p == s2Size) {
    err << "strncmp() reads beyond the end of string 2!\n";
    OOB_VIOLATION(s2, s2Pool, s2, s2Size + 1, SRC_INFO_ARGS);
  }
  return strncmp(s1, s2, n);
}

//
// pool_strncpy()
//
// See pool_strncpy_debug().
//
char *
pool_strncpy(DebugPoolTy *dstPool,
             DebugPoolTy *srcPool,
             char *dst,
             char *src,
             size_t n,
             const uint8_t complete) {
  return pool_strncpy_debug(dstPool, srcPool, dst, src, n, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strncpy()
//
// Copies exactly n bytes to dst, which are read from src until a nul
// terminator is encountered. If len(src) < n then pads the rest of the write
// with zeroes. If len(src) >= n then the copying will be truncated and
// consequently no nul terminator will be appended.
//
// Inputs:
//   dstPool  Pool handle for destination buffer
//   srcPool  Pool handle for source string
//   dst      Destination string pointer
//   src      Source string pointer
//   n        Maximum number of bytes to copy
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the value of the destination string pointer.
//
char *
pool_strncpy_debug(DebugPoolTy *dstPool,
                   DebugPoolTy *srcPool,
                   char *dst, 
                   char *src,
                   size_t n, 
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  size_t dstSize = 0, srcSize = 0, srcLen = 0;
  void *dstBegin = dst, *dstEnd = NULL, *srcBegin = src, *srcEnd = NULL;
  const bool dstComplete = ARG1_COMPLETE(complete);
  const bool srcComplete = ARG2_COMPLETE(complete);
  bool dstFound, srcFound;
  // Retrieve both the destination and source object bounds from the pools.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(dst, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(src, srcPool, SRC_INFO_ARGS);
  }
  if (srcFound) {
    srcSize = byte_range(src, srcEnd);
    // Check if src is read out of bounds. This happens when n > the object
    // size of src, and src is not terminated before the end of the object.
    srcLen = _strnlen(src, srcSize);
    if (n > srcSize && srcLen == srcSize) {
        err << "strncpy() reads source string out of bounds!\n";
        OOB_VIOLATION(src, srcPool, src, srcSize + 1, SRC_INFO_ARGS);
      } else {
        // Check for overlap. This check doesn't work when the previous
        // condition is true, which is why it is in the else clause.
        // This is the amount of characters actually read from src.
        size_t srcRead = std::min(n, 1 + srcLen);
        void *dstEdge = (char *) dst + srcRead - 1;
        void *srcEdge = (char *) src + srcRead - 1;
        if (isOverlapped(dst, dstEdge, src, srcEdge)) {
          err << "The objects passed to strncpy() overlap!\n";
          C_LIBRARY_VIOLATION(dst, dstPool, "strncpy()", SRC_INFO_ARGS);
        }
      }
  }
  if (dstFound) {
    dstSize = byte_range(dst, dstEnd);
    if (dstSize < n) {
      err << "strncpy() writes beyond end of destination object!\n";
      WRITE_VIOLATION(dst, dstPool, dstSize, n, SRC_INFO_ARGS);
    }
  }
  return strncpy(dst, src, n);
}

//
// pool_strpbrk()
//
// See pool_strpbrk_debug().
//
char *
pool_strpbrk(DebugPoolTy *sp,
             DebugPoolTy *ap,
             char *s,
             char *a,
             const uint8_t complete) {
  return pool_strpbrk_debug(sp, ap, s, a, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strpbrk()
//
// Searches for the first instance in s of any character in a, and returns a
// pointer to that instance, or returns NULL if no instance was found.
//
// Attempts to verify that both s and a are valid strings terminated within
// their memory objects' boundaries.
//
// Inputs:
//   sPool    Pool handle for source string
//   aPool    Pool handle for accept string
//   s        String pointer
//   a        Pointer to string of characters to find
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns a pointer to the first instance in s of some
//   character in a, or NULL if none was found.
//
char *
pool_strpbrk_debug(DebugPoolTy *sPool,
                   DebugPoolTy *aPool,
                   char *s,
                   char *a,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  const bool sComplete = ARG1_COMPLETE(complete);
  const bool aComplete = ARG2_COMPLETE(complete);
  validStringCheck(s, sPool, sComplete, "strpbrk", SRC_INFO_ARGS);
  validStringCheck(a, aPool, aComplete, "strpbrk", SRC_INFO_ARGS);
  return strpbrk(s, a);
}

//
// pool_strrchr()
//
// See pool_strrchr_debug().
//
char *
pool_strrchr(DebugPoolTy *sPool,
             char *s,
             int c,
             const uint8_t complete) {
  return pool_strrchr_debug(sPool, s, c, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strrchr()
//
// Inputs:
//   sPool    Pool handle for string
//   s        String pointer
//   c        Character to find
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns a pointer to the last instance of c in the string s,
//   or NULL if none was found.
//
char *
pool_strrchr_debug(DebugPoolTy *sPool,
                   char *s,
                   int c,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  const bool sComplete = ARG1_COMPLETE(complete);
  validStringCheck(s, sPool, sComplete, "strrchr", SRC_INFO_ARGS);
  return strrchr(s, c);
}

//
// pool_strspn()
//
// See pool_strspn_debug().
//
size_t
pool_strspn(DebugPoolTy *s1p,
            DebugPoolTy *s2p, 
            char *s1, 
            char *s2,
            const uint8_t complete) {
  return pool_strspn_debug(s1p, s2p, s1, s2, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strspn()
//
// Inputs:
//   str1Pool Pool handle for str1
//   str2Pool Pool handle for str2
//   str1     A string to scan
//   str2     A string of allowed characters
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the length of the initial portion of str1 which
//   contains characters only from str2.
//
size_t
pool_strspn_debug(DebugPoolTy *str1Pool,
                  DebugPoolTy *str2Pool, 
                  char *str1, 
                  char *str2,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  const bool str1Complete = ARG1_COMPLETE(complete);
  const bool str2Complete = ARG2_COMPLETE(complete);
  validStringCheck(str1, str1Pool, str1Complete, "strspn", SRC_INFO_ARGS);
  validStringCheck(str2, str2Pool, str2Complete, "strspn", SRC_INFO_ARGS);
  return strspn(str1, str2);
}

//
// pool_strstr()
//
// See pool_strstr_debug().
//
//
char *
pool_strstr(DebugPoolTy *s1Pool,
            DebugPoolTy *s2Pool,
            char *s1,
            char *s2,
            const uint8_t complete) {
  return pool_strstr_debug(s1Pool, s2Pool, s1, s2, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strstr()
//
// Searches for the first occurence of the substring s2 in s1.
// Returns a pointer to the discovered substring, or NULL if not found.
//
// Attempts to verify that s1 and s2 are valid strings terminated within
// their memory objects' boundaries.
//
// Inputs:
//   s1Pool   Pool handle for s1
//   s2Pool   Pool handle for s2
//   s1       Pointer to string to be searched
//   s2       Pointer to substring to search for
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns a pointer to the first instance of s2 in s1, or NULL
//   if none exists.
//
char *
pool_strstr_debug(DebugPoolTy *s1Pool,
                  DebugPoolTy *s2Pool,
                  char *s1,
                  char *s2,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  const bool s1Complete = ARG1_COMPLETE(complete);
  const bool s2Complete = ARG2_COMPLETE(complete);
  validStringCheck(s1, s1Pool, s1Complete, "strstr", SRC_INFO_ARGS);
  validStringCheck(s2, s2Pool, s2Complete, "strstr", SRC_INFO_ARGS);
  return strstr(s1, s2);
}

//
// pool_strxfrm()
//
// See pool_strxfrm_debug().
//
size_t
pool_strxfrm(DebugPoolTy *dPool,
             DebugPoolTy *sPool,
             char *d,
             char *s,
             size_t n,
             const uint8_t complete) {
  return pool_strxfrm_debug(dPool, sPool, d, s, n, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strxfrm()
//
// Uses the current locale information to convert the first n characters of the
// source string into a format suitable for usage with strcmp().
//
// Inputs:
//   dPool    Pool handle for destionation
//   sPool    Pool handle for source string
//   d        Pointer to destination buffer
//   s        Pointer to source string
//   n        Number of characters to convert
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the length of the transformed string.
//
size_t
pool_strxfrm_debug(DebugPoolTy *dPool,
                   DebugPoolTy *sPool,
                   char *d,
                   char *s,
                   size_t n,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  const bool dComplete = ARG1_COMPLETE(complete);
  const bool sComplete = ARG2_COMPLETE(complete);
  bool dFound;
  void *dStart, *dEnd = NULL;
  // Retrive the memory object boundaries from the pools.
  if (!(dFound = pool_find(dPool, d, dStart, dEnd)) && dComplete) {
    err << "Destination object not found in pool!\n";
    LOAD_STORE_VIOLATION(d, dPool, SRC_INFO_ARGS);
  }
  //
  // Check only for string termination of s, because we don't know how much of
  // s will be read.
  //
  validStringCheck(s, sPool, sComplete, "strxfrm", SRC_INFO_ARGS);
  //
  // Check if we write out if bounds.
  //
  if (dFound && n > 0) {
    // Call strxfrm(NULL, s, 0) to discover the length of the transformed
    // string.
    size_t xfrmLen = std::min(strxfrm(NULL, s, 0), n - 1);
    size_t dSize   = byte_range(d, dEnd);
    if (xfrmLen + 1 > dSize) {
      err << "strxfrm() writes past the end of the destination object!\n";
      WRITE_VIOLATION(d, dPool, dSize, xfrmLen + 1, SRC_INFO_ARGS);
    }
  }
  return strxfrm(d, s, n);
}

#ifdef HAVE_MEMPCPY
//
// pool_mempcpy()
//
// See pool_mempcpy_debug().
//
void *
pool_mempcpy(DebugPoolTy *dstPool, 
             DebugPoolTy *srcPool, 
             void *dst, 
             void *src, 
             size_t n,
             const uint8_t complete) {
  return pool_mempcpy_debug(dstPool, srcPool, dst, src, n, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace mempcpy()
//
// This function is identical to memcpy(), except it returns a pointer to the
// byte right after the first n bytes of the destination.
//
// Inputs:
//   dstPool  Pool handle for destination memory area
//   srcPool  Pool handle for source memory area
//   dst      Destination memory area
//   src      Source memory area
//   n        Maximum number of bytes to copy
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns the value of &((char *) dst)[n].
//
void *
pool_mempcpy_debug(DebugPoolTy *dstPool, 
                   DebugPoolTy *srcPool, 
                   void *dst, 
                   void *src, 
                   size_t n,
                   const uint8_t complete,
                   TAG,
                   SRC_INFO) {
  size_t dstSize = 0, srcSize = 0;
  void *dstBegin = dst, *dstEnd = NULL, *srcBegin = src, *srcEnd = NULL;
  const bool dstComplete = ARG1_COMPLETE(complete);
  const bool srcComplete = ARG2_COMPLETE(complete);
  bool dstFound, srcFound;
  // Retrieve both the destination and source buffer bounds from the handles.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(dst, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Memory object not found in pool!\n";
    LOAD_STORE_VIOLATION(src,srcPool, SRC_INFO_ARGS);
  }
  // Check 1) if we write or read past the end of the memory objects, and 2) if
  // the memory areas overlap.
  dstSize = byte_range(dst, dstEnd);
  srcSize = byte_range(src, srcEnd);
  if (dstFound && n > dstSize) {
    err << "mempcpy() writes past the end of the destination object!\n";
    WRITE_VIOLATION(dst, dstPool, dstSize, n, SRC_INFO_ARGS);
  }
  if (srcFound && n > srcSize) {
    err << "mempcpy() reads past the end of the source object!\n";
    OOB_VIOLATION(src, srcPool, src, n, SRC_INFO_ARGS);
  }
#if 0
  if (dstFound && srcFound) {
    void *dstEdge = (char *) dst + n - 1;
    void *srcEdge = (char *) dst + n - 1;
    if (isOverlapped(dst, dstEdge, src, srcEdge)) {
      err << "Inputs to mempcpy() overlap!\n";
      C_LIBRARY_VIOLATION(dst, dstPool, "mempcpy", SRC_INFO_ARGS);
    }
  }
#endif
  return mempcpy(dst, src, n);
}
#endif

#ifdef HAVE_STRCASESTR
//
// pool_strcasestr()
//
// See pool_strcasestr_debug().
//
char *
pool_strcasestr(DebugPoolTy *s1Pool,
                DebugPoolTy *s2Pool,
                char *s1,
                char *s2,
                const uint8_t complete) {
  return pool_strcasestr_debug(s1Pool, s2Pool, s1, s2, complete, DEFAULTS);
}


//
// Secure runtime wrapper function to replace strcasestr()
//
// Searches for the first occurence of the substring s2 in s1, case
// insensitively.
// Returns a pointer to the discovered substring, or NULL if not found.
//
// Attempts to verify that s1 and s2 are valid strings terminated within
// their memory objects' boundaries.
//
// Inputs:
//   s1Pool   Pool handle for s1
//   s2Pool   Pool handle for s2
//   s1       Pointer to string to be searched
//   s2       Pointer to substring to search for
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   Returns a pointer to the start of the first case-insensitive occurence of
//   s2 in s1, or NULL if not found.
//
char *
pool_strcasestr_debug(DebugPoolTy *s1Pool,
                      DebugPoolTy *s2Pool,
                      char *s1,
                      char *s2,
                      const uint8_t complete,
                      TAG,
                      SRC_INFO) {
  const bool s1Complete = ARG1_COMPLETE(complete);
  const bool s2Complete = ARG2_COMPLETE(complete);
  validStringCheck(s1, s1Pool, s1Complete, "strcasestr", SRC_INFO_ARGS);
  validStringCheck(s2, s2Pool, s2Complete, "strcasestr", SRC_INFO_ARGS);
  return strcasestr(s1, s2);
}
#endif

#ifdef HAVE_STRNLEN
//
// pool_strnlen()
//
// See pool_strnlen_debug().
//
size_t
pool_strnlen(DebugPoolTy *stringPool, 
             char *string, 
             size_t maxlen,
             const uint8_t complete) {
  return pool_strnlen_debug(stringPool, string, maxlen, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace strnlen()
//
// Like strlen(), but searches for the nul terminator only within the first
// maxlen bytes of the string. If the terminator is not found, then it returns
// the value of maxlen.
//
// Inputs:
//   strPool  Pool handle for the string
//   str      Pointer to string to analyze
//   maxlen   Maximum length to search
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This function returns strlen(str) if strlen(str) < maxlen, otherwise it
//   returns maxlen.
//
size_t
pool_strnlen_debug(DebugPoolTy *strPool, 
                   char *str, 
                   size_t maxlen, 
                   const uint8_t complete, 
                   TAG, 
                   SRC_INFO) {
  size_t safelen, len;
  void *strBegin = str, *strEnd = NULL;
  const bool strComplete = ARG1_COMPLETE(complete);
  bool strFound;
  if (!(strFound = pool_find(strPool, str, strBegin, strEnd)) && strComplete) {
    err << "String not found in pool!\n";
    LOAD_STORE_VIOLATION(str, strPool, SRC_INFO_ARGS);
  }
  if (strFound) {
    // This is the maximum number of characters that can be read from str
    // without causing a memory safety error.
    safelen = byte_range(str, strEnd);
    // Thus the maximum length that _strnlen() can return is safelen - 1.
    len     = _strnlen(str, std::min(maxlen, safelen));
    // If _strnlen() returns safelen, then that means that the string is not
    // terminated within the first safelen characters, meaning that if maxlen
    // > safelen, we will be reading at least safelen + 1 characters to find
    // a nul terminator, which causes a memory safety error.
    if (len == safelen && maxlen > safelen) {
      err << "strnlen() reads beyond the end of the input string's object!\n";
      OOB_VIOLATION(str, strPool, str, safelen + 1, SRC_INFO_ARGS);
    } else // If no memory safety error occurred, len is guaranteed to be the
           // value of strnlen(str, maxlen), so just return it right away.
      return len;
  }
  return strnlen(str, maxlen);
}
#endif

#ifdef HAVE_STPCPY
//
// pool_stpcpy()
//
// See pool_stpcpy_debug().
//
char *
pool_stpcpy(DebugPoolTy *dstPool,
            DebugPoolTy *srcPool,
            char *dst,
            char *src,
            const uint8_t complete) {
  return pool_stpcpy_debug(dstPool, srcPool, dst, src, complete, DEFAULTS);
}

//
// Secure runtime wrapper function to replace stpcpy()
//
// Copies the string src to dst and returns a pointer to the nul terminator of
// dst.
//
// Attempts to verify the following:
//  - src is nul terminated within memory object bounds
//  - src and dst do not overlap
//  - dst is long enough to hold src.
//
// Inputs:
//   dstPool  Pool handle for destination string's pool
//   srcPool  Pool handle for source string's pool
//   dst      Pointer to destination of copy operation
//   src      Pointer to string to copy
//   complete Completeness bit vector
//   TAG      Tag information for debugging purposes
//   SRC_INFO Source file and line number information for debugging purposes
// Returns:
//   This functions returns the value of &dst[strlen(dst)] after the copy
//   operation is completed.
//
char *
pool_stpcpy_debug(DebugPoolTy *dstPool,
                  DebugPoolTy *srcPool,
                  char *dst,
                  char *src,
                  const uint8_t complete,
                  TAG,
                  SRC_INFO) {
  void *dstBegin = NULL, *dstEnd = NULL, *srcBegin = NULL, *srcEnd = NULL;
  size_t srcLen = 0;
  const bool dstComplete = ARG1_COMPLETE(complete);
  const bool srcComplete = ARG2_COMPLETE(complete);
  bool dstFound, srcFound;
  // Find the destination and source strings in their pools.
  if (!(dstFound = pool_find(dstPool, dst, dstBegin, dstEnd)) && dstComplete) {
    err << "Could not find destination object in pool!\n";
    LOAD_STORE_VIOLATION(dst, dstPool, SRC_INFO_ARGS);
  }
  if (!(srcFound = pool_find(srcPool, src, srcBegin, srcEnd)) && srcComplete) {
    err << "Could not find source object in pool\n";
    LOAD_STORE_VIOLATION(src, srcPool, SRC_INFO_ARGS);
  }
  // Check if source is terminated.
  if (srcFound && !isTerminated(src, srcEnd, srcLen)) {
    err << "Source string not terminated within bounds!\n";
    C_LIBRARY_VIOLATION(src, srcPool, "stpcpy", SRC_INFO_ARGS);
  }
  // The remainder of the checks require both objects to be found.
  if (dstFound && srcFound) {
    // Check for overlap of objects.
    if (isOverlapped(dst, &dst[srcLen], src, &src[srcLen])) {
      err << "Copying overlapping strings has undefined behavior!\n";
      C_LIBRARY_VIOLATION(dst, dstPool, "stpcpy", SRC_INFO_ARGS);
    }
    // dstLen is the maximum length string that dst can hold.
    size_t dstLen = byte_range(dst, dstEnd) - 1;
    // Check for overflow of dst.
    if (srcLen > dstLen) {
      err << "Destination object too short to hold string!\n";
      WRITE_VIOLATION(dst, dstPool, dstLen, srcLen, SRC_INFO_ARGS);
    }
  }
  return stpcpy(dst, src);
}
#endif
