//===-------- String.cpp - Secure C standard string library calls ---------===//
//
//                          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 pass finds all calls to functions in the C standard string library and
// transforms them to a more secure form.
//
//===----------------------------------------------------------------------===//

//
// To add a new function to the CStdLib checks, the following modifications are
// necessary:
// 
// In SAFECode:
//
//   - Add the pool_* prototype of the function to
//     runtime/include/CStdLibSupport.h.
//
//   - Implement the pool_* version of the function in the relevant file in
//     runtime/DebugRuntime.
//
//   - Add debug instrumentation information to
//     lib/DebugInstrumentation/DebugInstrumentation.cpp.
//
//   - Update the StringTransform pass to transform calls of the library
//     function into its pool_* version in lib/CStdLib/String.cpp.
//
// In poolalloc:
//
//   - Add an entry for the pool_* version of the function containing the
//     number of initial pool arguments to the structure in
//     include/poolalloc/RuntimeChecks.h.
//
//   - Add an entry to lib/DSA/StdLibPass.cpp for the pool_* version of the
//     function to allow DSA to recognize it.
//


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

#include <cstdarg>
#include <string>

using std::string;

using namespace llvm;

namespace llvm {

// Identifier variable for the pass
char StringTransform::ID = 0;

// Statistics counters

#define ADD_STATISTIC_FOR(func) \
  STATISTIC(st_xform_ ## func, "Total " #func "() calls transformed")

ADD_STATISTIC_FOR(vprintf);
ADD_STATISTIC_FOR(vfprintf);
ADD_STATISTIC_FOR(vsprintf);
ADD_STATISTIC_FOR(vsnprintf);
ADD_STATISTIC_FOR(vscanf);
ADD_STATISTIC_FOR(vsscanf);
ADD_STATISTIC_FOR(vfscanf);
ADD_STATISTIC_FOR(vsyslog);
ADD_STATISTIC_FOR(memccpy);
ADD_STATISTIC_FOR(memchr);
ADD_STATISTIC_FOR(memcmp);
ADD_STATISTIC_FOR(memcpy);
ADD_STATISTIC_FOR(memmove);
ADD_STATISTIC_FOR(memset);
ADD_STATISTIC_FOR(strcat);
ADD_STATISTIC_FOR(strchr);
ADD_STATISTIC_FOR(strcmp);
ADD_STATISTIC_FOR(strcoll);
ADD_STATISTIC_FOR(strcpy);
ADD_STATISTIC_FOR(strcspn);
ADD_STATISTIC_FOR(strlen);
ADD_STATISTIC_FOR(strncat);
ADD_STATISTIC_FOR(strncmp);
ADD_STATISTIC_FOR(strncpy);
ADD_STATISTIC_FOR(strpbrk);
ADD_STATISTIC_FOR(strrchr);
ADD_STATISTIC_FOR(strspn);
ADD_STATISTIC_FOR(strstr);
ADD_STATISTIC_FOR(strxfrm);
ADD_STATISTIC_FOR(bcmp);
ADD_STATISTIC_FOR(bcopy);
ADD_STATISTIC_FOR(bzero);
ADD_STATISTIC_FOR(index);
ADD_STATISTIC_FOR(rindex);
ADD_STATISTIC_FOR(strcasecmp);
ADD_STATISTIC_FOR(strncasecmp);
ADD_STATISTIC_FOR(fgets);
ADD_STATISTIC_FOR(fputs);
ADD_STATISTIC_FOR(fwrite);
ADD_STATISTIC_FOR(fread);
ADD_STATISTIC_FOR(gets);
ADD_STATISTIC_FOR(puts);
ADD_STATISTIC_FOR(tmpnam);
ADD_STATISTIC_FOR(read);
ADD_STATISTIC_FOR(recv);
ADD_STATISTIC_FOR(recvfrom);
ADD_STATISTIC_FOR(write);
ADD_STATISTIC_FOR(send);
ADD_STATISTIC_FOR(sendto);
ADD_STATISTIC_FOR(readdir_r);
ADD_STATISTIC_FOR(readlink);
ADD_STATISTIC_FOR(realpath);
ADD_STATISTIC_FOR(getcwd);

#ifdef HAVE_MEMPCPY
ADD_STATISTIC_FOR(mempcpy);
#endif
#ifdef HAVE_STRCASESTR
ADD_STATISTIC_FOR(strcasestr);
#endif
#ifdef HAVE_STPCPY
ADD_STATISTIC_FOR(stpcpy);
#endif
#ifdef HAVE_STRNLEN
ADD_STATISTIC_FOR(strnlen);
#endif

STATISTIC(NumStringChecks, "Number of calls to poolcheckstr() added");

//
// Functions that aren't handled (yet...):
//  - stpncpy and __stpncpy_chk
//  - setbuf
//  - setvbuf
//  - strtok() family
//

static RegisterPass<StringTransform>
ST("string_transform", "Secure C standard string library calls");

//
// Function: addStringCheck()
//
// Description:
//  This function will add a run-time check for the specified argument for
//  calls to the specified function.
//
// Inputs:
//  M - The module to modify
//  name - The name of the function which uses a string input.
//  argNo - The argument of the function which is a string.
//
static bool
addStringCheck (Module & M, const std::string & name, unsigned argNo) {
  //
  // Get the function that uses a string.  If it is not used within the
  // program, do nothing.
  //
  Function * F = M.getFunction (name);
  if (!F) return false;

  //
  // Get the type expected for string arguments.
  //
  Type * Int8PtrTy = Type::getInt8PtrTy(M.getContext());

  //
  // Don't instrument calls to the function if it is defined in this program.
  //
  if (!(F->isDeclaration()))
    return false;

  //
  // Scan through the module for uses of the function to instrument.
  //
  std::vector<Instruction *> callsToInstrument;
  for (Value::use_iterator UI = F->use_begin(), UE = F->use_end();
       UI != UE;
       ++UI) {
    // Ensure the use is an instruction and that the instruction calls the
    // source function (as opposed to passing it as a parameter or other
    // possible uses).
    CallSite CS (*UI);
    if (!CS || CS.getCalledValue() != F)
      continue;
    callsToInstrument.push_back(CS.getInstruction());
  }

  //
  // Keep track of changes to the module.
  //
  bool changed = false;

  //
  // Go through all of the calls and instrument them.
  //
  Function * strCheck = cast<Function>(M.getFunction ("poolcheckstrui"));
  for (unsigned index = 0; index < callsToInstrument.size(); ++index) {
    CallSite CS = callsToInstrument[index];

    //
    // Ignore this call site when the specified argument doesn't appear to
    // exist or is of the wrong type.
    //
    if (CS.arg_size() < argNo + 1 ||
        CS.getArgument(argNo)->getType() != Int8PtrTy)
      continue;

    //
    // Setup the arguments for the run-time check.  The first is the NULL
    // pool handle.  The second is the argument from the actual function call.
    //
    std::vector<Value *> Params;
    PointerType *VoidPtrTy = IntegerType::getInt8PtrTy(M.getContext());
    Params.push_back (ConstantPointerNull::get(VoidPtrTy));
    Params.push_back (CS.getArgument (argNo));

    //
    // Create a call instruction to the string run-time check.
    //
    CallInst *CallToStringCheck
      = CallInst::Create (strCheck, Params, "", CS.getInstruction());

    //
    // If the original call site has debug metadata, associate the metadata
    // with the newly created call.
    //
    if (MDNode *DebugNode = CS.getInstruction()->getMetadata("dbg"))
      CallToStringCheck->setMetadata("dbg", DebugNode);

    //
    // mark that we modified something in the module and also update the 
    // string check statistic.
    //
    changed = true;
    ++NumStringChecks;
  }

  return changed;
}

//
// Entry point for the LLVM pass that transforms C standard string library calls
//
bool
StringTransform::runOnModule (Module & M) {
  // Flags whether we modified the module.
  bool chgd = false;

  tdata = &getAnalysis<DataLayout>();

  // Create needed pointer types (char * == i8 * == VoidPtrTy).
  Type *VoidPtrTy = IntegerType::getInt8PtrTy(M.getContext());
  // Determine the type of size_t for functions that return this result.
  Type *SizeTTy = tdata->getIntPtrType(M.getContext(), 0);
  Type *SSizeTTy = SizeTTy;
  // Create other return types (int, void).
  Type *Int32Ty = IntegerType::getInt32Ty(M.getContext());
  Type *VoidTy  = Type::getVoidTy(M.getContext());

  //
  // Add a function that will perform a basic check upon string inputs.
  //
  std::vector<Type *> ParamTypes;
  ParamTypes.push_back (VoidPtrTy);
  ParamTypes.push_back (VoidPtrTy);
  FunctionType *FT = FunctionType::get(VoidPtrTy, ParamTypes, false);
  M.getOrInsertFunction ("poolcheckstrui", FT);

  //
  // Add basic checks on strings which are read by their C library functions.
  //
  chgd |= addStringCheck (M, "access", 0);
  chgd |= addStringCheck (M, "chdir", 0);
  chgd |= addStringCheck (M, "chmod", 0);
  chgd |= addStringCheck (M, "chown", 0);
  chgd |= addStringCheck (M, "creat", 0);
  chgd |= addStringCheck (M, "dlopen", 0);
  chgd |= addStringCheck (M, "fattach", 1);
  chgd |= addStringCheck (M, "fchmodat", 1);
  chgd |= addStringCheck (M, "fdopen", 1);
  chgd |= addStringCheck (M, "fopen", 0);
  chgd |= addStringCheck (M, "\01_fopen", 0);
  chgd |= addStringCheck (M, "freopen", 0);
  chgd |= addStringCheck (M, "fstatat", 1);
  chgd |= addStringCheck (M, "ftok", 0);
  chgd |= addStringCheck (M, "ftw", 0);
  chgd |= addStringCheck (M, "getaddrinfo", 0);
  chgd |= addStringCheck (M, "getenv", 0);
  chgd |= addStringCheck (M, "gethostbyname", 0);
  chgd |= addStringCheck (M, "lchmod", 0);
  chgd |= addStringCheck (M, "lchown", 0);
  chgd |= addStringCheck (M, "link", 0);
  chgd |= addStringCheck (M, "link", 1);
  chgd |= addStringCheck (M, "linkat", 1);
  chgd |= addStringCheck (M, "linkat", 3);
  chgd |= addStringCheck (M, "lstat", 0);
  chgd |= addStringCheck (M, "mkdir", 0);
  chgd |= addStringCheck (M, "mkdirat", 1);
  chgd |= addStringCheck (M, "mkfifo", 0);
  chgd |= addStringCheck (M, "mkfifoat", 1);
  chgd |= addStringCheck (M, "mknod", 0);
  chgd |= addStringCheck (M, "mknodat", 1);
  chgd |= addStringCheck (M, "mount", 0);
  chgd |= addStringCheck (M, "mount", 1);
  chgd |= addStringCheck (M, "mount", 2);
  chgd |= addStringCheck (M, "open", 0);
  chgd |= addStringCheck (M, "openat", 1);
  chgd |= addStringCheck (M, "openlog", 0);
  chgd |= addStringCheck (M, "popen", 0);
  chgd |= addStringCheck (M, "putenv", 0);
  chgd |= addStringCheck (M, "remove", 0);
  chgd |= addStringCheck (M, "rename", 0);
  chgd |= addStringCheck (M, "rename", 1);
  chgd |= addStringCheck (M, "renameat", 1);
  chgd |= addStringCheck (M, "renameat", 3);
  chgd |= addStringCheck (M, "rmdir", 0);
  chgd |= addStringCheck (M, "setenv", 0);
  chgd |= addStringCheck (M, "shm_open", 0);
  chgd |= addStringCheck (M, "shm_unlink", 0);
  chgd |= addStringCheck (M, "stat", 0);
  chgd |= addStringCheck (M, "statvfs", 0);
  chgd |= addStringCheck (M, "symlink", 0);
  chgd |= addStringCheck (M, "symlink", 1);
  chgd |= addStringCheck (M, "system", 0);
  chgd |= addStringCheck (M, "tempnam", 0);
  chgd |= addStringCheck (M, "tempnam", 1);
  chgd |= addStringCheck (M, "truncate", 0);
  chgd |= addStringCheck (M, "unlink", 0);
  chgd |= addStringCheck (M, "unsetenv", 0);
  chgd |= addStringCheck (M, "utime", 0);
  chgd |= addStringCheck (M, "utimensat", 1);
  chgd |= addStringCheck (M, "utimes", 0);

  //
  // Handle 64-bit versions of these functions that may exist on hybrid 32/64
  // bit systems.
  //
  chgd |= addStringCheck (M, "access64", 0);
  chgd |= addStringCheck (M, "chdir64", 0);
  chgd |= addStringCheck (M, "chmod64", 0);
  chgd |= addStringCheck (M, "chown64", 0);
  chgd |= addStringCheck (M, "creat64", 0);
  chgd |= addStringCheck (M, "fopen64", 0);
  chgd |= addStringCheck (M, "lchmod64", 0);
  chgd |= addStringCheck (M, "lchown64", 0);
  chgd |= addStringCheck (M, "link64", 0);
  chgd |= addStringCheck (M, "link64", 1);
  chgd |= addStringCheck (M, "lstat64", 0);
  chgd |= addStringCheck (M, "mkdir64", 0);
  chgd |= addStringCheck (M, "mkfifo64", 0);
  chgd |= addStringCheck (M, "mknod64", 0);
  chgd |= addStringCheck (M, "open64", 0);
  chgd |= addStringCheck (M, "openat64", 1);
  chgd |= addStringCheck (M, "remove64", 0);
  chgd |= addStringCheck (M, "rename64", 0);
  chgd |= addStringCheck (M, "rename64", 1);
  chgd |= addStringCheck (M, "rmdir64", 0);
  chgd |= addStringCheck (M, "stat64", 0);
  chgd |= addStringCheck (M, "symlink64", 0);
  chgd |= addStringCheck (M, "symlink64", 1);
  chgd |= addStringCheck (M, "unlink64", 0);

  //
  // exec() family (note only partial support; we only check the first
  // argument).
  //
  chgd |= addStringCheck (M, "execl", 0);
  chgd |= addStringCheck (M, "execlp", 0);
  chgd |= addStringCheck (M, "execle", 0);
  chgd |= addStringCheck (M, "execv", 0);
  chgd |= addStringCheck (M, "execvp", 0);

  // Functions from <stdio.h>, <syslog.h>
  chgd |= transform(M, "vprintf",  2, 1, Int32Ty, st_xform_vprintf);
  chgd |= transform(M, "vfprintf", 3, 2, Int32Ty, st_xform_vfprintf);
  chgd |= transform(M, "vsprintf", 3, 2, Int32Ty, st_xform_vsprintf);
  chgd |= transform(M, "vscanf",   2, 1, Int32Ty, st_xform_vscanf);
  chgd |= transform(M, "vsscanf",  3, 2, Int32Ty, st_xform_vsscanf);
  chgd |= transform(M, "vfscanf",  3, 2, Int32Ty, st_xform_vfscanf);
  SourceFunction VSNPf   = { "vsnprintf", Int32Ty, 4 };
  SourceFunction VSyslog = { "vsyslog", VoidTy, 3 };
  DestFunction PVSNPf   = { "pool_vsnprintf", 4, 2 };
  DestFunction PVSyslog = { "pool_vsyslog", 3, 1 };
  // Note that we need to switch the order of arguments to the instrumented
  // calls of vsnprintf() and vsyslog(), because the CStdLib pass convention is
  // to place all the interesting pointer arguments at the start of the
  // parameter list, but these functions have initial arguments that are
  // non-pointers.
  chgd |= vtransform(M, VSNPf, PVSNPf, st_xform_vsnprintf, 1u, 3u, 2u, 4u);
  chgd |= vtransform(M, VSyslog, PVSyslog, st_xform_vsyslog, 2u, 1u, 3u);
  // __isoc99_vscanf family: these are found in glibc
  SourceFunction IsoC99Vscanf  = { "__isoc99_vscanf", Int32Ty, 2 };
  SourceFunction IsoC99Vsscanf = { "__isoc99_vsscanf", Int32Ty, 3 };
  SourceFunction IsoC99Vfscanf = { "__isoc99_vfscanf", Int32Ty, 3 };
  DestFunction PVscanf  = { "pool_vscanf", 2, 1 };
  DestFunction PVsscanf = { "pool_vsscanf", 3, 2 };
  DestFunction PVfscanf = { "pool_vfscanf", 3, 2 };
  chgd |= vtransform(M, IsoC99Vscanf, PVscanf, st_xform_vscanf, 1u, 2u);
  chgd |= vtransform(M, IsoC99Vsscanf, PVsscanf, st_xform_vsscanf, 1u, 2u);
  chgd |= vtransform(M, IsoC99Vfscanf, PVfscanf, st_xform_vfscanf, 1u, 2u);
  // __vsprintf_chk, __vsnprintf_chk
  SourceFunction VSPfC  = { "__vsprintf_chk", Int32Ty, 5 };
  SourceFunction VSNPfC = { "__vsnprintf_chk", Int32Ty, 6 };
  DestFunction PVSPf = { "pool_vsprintf", 3, 2 };
  chgd |= vtransform(M, VSPfC, PVSPf, st_xform_vsprintf, 1u, 4u, 5u);
  chgd |= vtransform(M, VSNPfC, PVSNPf, st_xform_vsnprintf, 1u, 5u, 2u, 6u);
  // Functions from <string.h>
  chgd |= transform(M, "memccpy", 4, 2, VoidPtrTy, st_xform_memccpy);
  chgd |= transform(M, "memchr",  3, 1, VoidPtrTy, st_xform_memchr);
  chgd |= transform(M, "memcmp",  3, 2, Int32Ty,   st_xform_memcmp);
  chgd |= transform(M, "memcpy",  3, 2, Int32Ty,   st_xform_memcpy);
  chgd |= transform(M, "memmove", 3, 2, VoidPtrTy, st_xform_memmove);
  chgd |= transform(M, "memset",  2, 1, VoidPtrTy, st_xform_memset);
  chgd |= transform(M, "strcat",  2, 2, VoidPtrTy, st_xform_strcat);
  chgd |= transform(M, "strchr",  2, 1, VoidPtrTy, st_xform_strchr);
  chgd |= transform(M, "strcmp",  2, 2, Int32Ty,   st_xform_strcmp);
  chgd |= transform(M, "strcoll", 2, 2, Int32Ty,   st_xform_strcoll);
  chgd |= transform(M, "strcpy",  2, 2, VoidPtrTy, st_xform_strcpy);
  chgd |= transform(M, "strcspn", 2, 2, SizeTTy,   st_xform_strcspn);
  // chgd |= handle_strerror_r(M);
  chgd |= transform(M, "strlen",  1, 1, SizeTTy,   st_xform_strlen);
  chgd |= transform(M, "strncat", 3, 2, VoidPtrTy, st_xform_strncat);
  chgd |= transform(M, "strncmp", 3, 2, Int32Ty,   st_xform_strncmp);
  chgd |= transform(M, "strncpy", 3, 2, VoidPtrTy, st_xform_strncpy);
  chgd |= transform(M, "strpbrk", 2, 2, VoidPtrTy, st_xform_strpbrk);
  chgd |= transform(M, "strrchr", 2, 1, VoidPtrTy, st_xform_strrchr);
  chgd |= transform(M, "strspn",  2, 2, SizeTTy,   st_xform_strspn);
  chgd |= transform(M, "strstr",  2, 2, VoidPtrTy, st_xform_strstr);
  chgd |= transform(M, "strxfrm", 3, 2, SizeTTy,   st_xform_strxfrm);
  // Extensions to <string.h>
#ifdef HAVE_MEMPCPY
  chgd |= transform(M, "mempcpy", 3, 2, VoidPtrTy, st_xform_mempcpy);
#endif
#ifdef HAVE_STRCASESTR
  chgd |= transform(M, "strcasestr", 2, 2, VoidPtrTy, st_xform_strcasestr);
#endif
#ifdef HAVE_STPCPY
  chgd |= transform(M, "stpcpy",  2, 2, VoidPtrTy, st_xform_stpcpy);
#endif
#ifdef HAVE_STRNLEN
  chgd |= transform(M, "strnlen", 2, 1, SizeTTy,   st_xform_strnlen);
#endif
  // Functions from <strings.h>
  chgd |= transform(M, "bcmp",    3, 2, Int32Ty,   st_xform_bcmp);
  chgd |= transform(M, "bcopy",   3, 2, VoidTy,    st_xform_bcopy);
  chgd |= transform(M, "bzero",   2, 1, VoidTy,    st_xform_bzero);
  chgd |= transform(M, "index",   2, 1, VoidPtrTy, st_xform_index);
  chgd |= transform(M, "rindex",  2, 1, VoidPtrTy, st_xform_rindex);
  chgd |= transform(M, "strcasecmp", 2, 2, Int32Ty, st_xform_strcasecmp);
  chgd |= transform(M, "strncasecmp", 3, 2, Int32Ty, st_xform_strncasecmp);
  // Darwin-specific secure extensions to <string.h>
  SourceFunction MemcpyChk  = { "__memcpy_chk", VoidPtrTy, 4 };
  SourceFunction MemmoveChk = { "__memmove_chk", VoidPtrTy, 4 };
  SourceFunction MemsetChk  = { "__memset_chk", VoidPtrTy, 4 };
  SourceFunction StrcpyChk  = { "__strcpy_chk", VoidPtrTy, 3 };
  SourceFunction StrcatChk  = { "__strcat_chk", VoidPtrTy, 3 };
  SourceFunction StrncatChk = { "__strncat_chk", VoidPtrTy, 4 };
  SourceFunction StrncpyChk = { "__strncpy_chk", VoidPtrTy, 4 };
  DestFunction PoolMemcpy  = { "pool_memcpy", 3, 2 };
  DestFunction PoolMemmove = { "pool_memmove", 3, 2 };
  DestFunction PoolMemset  = { "pool_memset", 3, 1 };
  DestFunction PoolStrcpy  = { "pool_strcpy", 2, 2 };
  DestFunction PoolStrcat  = { "pool_strcat", 2, 2 };
  DestFunction PoolStrncat = { "pool_strncat", 3, 2 };
  DestFunction PoolStrncpy = { "pool_strncpy", 3, 2 };
  chgd |= vtransform(M, MemcpyChk, PoolMemcpy, st_xform_memcpy, 1u, 2u, 3u);
  chgd |= vtransform(M, MemmoveChk, PoolMemmove, st_xform_memmove, 1u, 2u, 3u);
  chgd |= vtransform(M, MemsetChk, PoolMemset, st_xform_memset, 1u, 2u, 3u);
  chgd |= vtransform(M, StrcpyChk, PoolStrcpy, st_xform_strcpy, 1u, 2u);
  chgd |= vtransform(M, StrcatChk, PoolStrcat, st_xform_strcat, 1u, 2u);
  chgd |= vtransform(M, StrncatChk, PoolStrncat, st_xform_strncat, 1u, 2u, 3u);
  chgd |= vtransform(M, StrncpyChk, PoolStrncpy, st_xform_strncpy, 1, 2u, 3u);
#ifdef HAVE_STPCPY
  SourceFunction StpcpyChk = { "__stpcpy_chk", VoidPtrTy, 3 };
  DestFunction PoolStpcpy = { "pool_stpcpy", 2, 2 };
  chgd |= vtransform(M, StpcpyChk, PoolStpcpy, st_xform_stpcpy, 1u, 2u);
#endif

  // Functions from <stdio.h> 
  chgd |= transform(M, "fgets", 3, 1, VoidPtrTy, st_xform_fgets);
  chgd |= transform(M, "fputs", 2, 1, Int32Ty, st_xform_fputs);
  chgd |= transform(M, "fwrite", 4, 1, SizeTTy, st_xform_fwrite);
  chgd |= transform(M, "fread", 4, 1, SizeTTy, st_xform_fread);
  chgd |= transform(M, "gets", 1, 1, VoidPtrTy, st_xform_gets);
  chgd |= transform(M, "puts", 1, 1, Int32Ty, st_xform_puts);
  chgd |= transform(M, "tmpnam", 1, 1, VoidPtrTy, st_xform_tmpnam);

  // System calls
  SourceFunction Read  = { "read", SSizeTTy, 3 };
  SourceFunction Recv  = { "recv", SSizeTTy, 4 };
  SourceFunction RecvFrom  = { "recvfrom", SSizeTTy, 6 };
  SourceFunction Write = { "write", SSizeTTy, 3 };
  SourceFunction Send  = { "send", SSizeTTy, 4 };
  SourceFunction SendTo = { "sendto", SSizeTTy, 6 };
  DestFunction PoolRead  = { "pool_read", 3, 1 };
  DestFunction PoolRecv  = { "pool_recv", 4, 1 };
  DestFunction PoolRecvFrom = { "pool_recvfrom", 6, 1 };
  DestFunction PoolWrite = { "pool_write", 3, 1 };
  DestFunction PoolSend  = { "pool_send", 4, 1 };
  DestFunction PoolSendTo = { "pool_sendto", 6, 1 };
  chgd |= transform(M, "readlink", 3, 2, SSizeTTy,   st_xform_readlink);
  chgd |= transform(M, "realpath", 2, 2, VoidPtrTy,   st_xform_realpath);
  chgd |= vtransform(M, Read, PoolRead, st_xform_read, 2u, 1u, 3u);
  chgd |= vtransform(M, Recv, PoolRecv, st_xform_recv, 2u, 1u, 3u, 4u);
  chgd |= vtransform(M, Write, PoolWrite, st_xform_write, 2u, 1u, 3u);
  chgd |= vtransform(M, Send, PoolSend, st_xform_send, 2u, 1u, 3u, 4u);
  chgd |= vtransform(
    M, RecvFrom, PoolRecvFrom, st_xform_recvfrom, 2u, 1u, 3u, 4u, 5u, 6u
  );
  chgd |= vtransform(
    M, SendTo, PoolSendTo, st_xform_sendto, 2u, 1u, 3u, 4u, 5u, 6u
  );

  // realpath() on Darwin
  SourceFunction DarwinRealpath = 
    { "\01_realpath$DARWIN_EXTSN", VoidPtrTy, 2 };
  DestFunction PoolRealpath = { "pool_realpath", 2, 2 };
  chgd |= vtransform(
    M, DarwinRealpath, PoolRealpath, st_xform_realpath, 1u, 2u
  );

  // Functions from <dirent.h>
  SourceFunction RdDirR = { "readdir_r", Int32Ty, 3 };
  DestFunction PoolRdDirR = { "pool_readdir_r", 3, 2 };
  chgd |= vtransform(M, RdDirR, PoolRdDirR, st_xform_readdir_r, 2u, 3u, 1u);

  // Functions from <unistd.h>
  chgd |= transform(M, "getcwd", 2, 1, VoidPtrTy, st_xform_getcwd);

  return chgd;
}

//
// Simple wrapper to gtransform() for when
//   1) the transformed function is named "pool_" + original name.
//   2) the order and number of arguments is preserved from the original to the
//      transformed function.
//
// Parameters:
//   M         - the module to scan
//   argc      - the expected number of arguments to the original function
//   pool_argc - the number of initial pool parameters to add to the transformed
//               function
//   ReturnTy  - the expected return type of the original function
//   statistic - a reference to a relevant Statistic for the number of
//               transformation
//
// Returns:
//   This function returns true if the module was modified and false otherwise.
//
bool
StringTransform::transform(Module &M,
                           const StringRef FunctionName,
                           const unsigned argc,
                           const unsigned pool_argc,
                           Type *ReturnTy,
                           Statistic &statistic) {
  SourceFunction src = { FunctionName.data(), ReturnTy, argc };
  string dst_name  = "pool_" + FunctionName.str();
  DestFunction dst = { dst_name.c_str(), argc, pool_argc };
  vector<unsigned> args;
  for (unsigned i = 1; i <= argc; i++)
    args.push_back(i);
  return gtransform(M, src, dst, statistic, args);
}

//
// vtransform() - wrapper to gtransform() that takes variable arguments
// instead of a vector as the final parameter
//
bool
StringTransform::vtransform(Module &M,
                            const SourceFunction &from,
                            const DestFunction &to,
                            Statistic &stat,
                            ...) {
  vector<unsigned> args;
  va_list ap;
  va_start(ap, stat);
  // Read the positions to append as vararg parameters.
  for (unsigned i = 1; i <= to.source_argc; i++) {
    unsigned position = va_arg(ap, unsigned);
    args.push_back(position);
  }
  va_end(ap);
  return gtransform(M, from, to, stat, args);
}

//
// Secures C standard string library calls by transforming them into
// their corresponding runtime wrapper functions.
//
// The 'from' parameter describes a function to transform. It is struct of
// the form
//   struct { const char *name; Type *return_type; unsigned argc };
// where
//   - 'name' is the name of the function to transform
//   - 'return_type' is its expected return type
//   - 'argc' is its expected number of arguments.
//
// The 'to' parameter describes the function to transform into. It is a struct
// of the form
//   struct { const char *name, unsigned source_argc, unsigned pool_argc };
// where
//   - 'name' is the name of the resulting function
//   - 'source_argc' is the number of parameters the function takes from the
//     original function
//   - 'pool_argc' is the number of initial pool parameters to add.
//
// The 'append_order' vector describes how to move the parameters of the
// original function into the transformed function call.
//
// @param M              Module from runOnModule() to scan for functions to
//                       transform.
// @param from           SourceFunction structure reference described above
// @param to             DestFunction structure reference described above.
// @param stat           A reference to the relevant transform statistic.
// @param append_order   A vector describing the order to add the arguments from
//                       the source function into the destination function.
// @return               Returns true if any calls were transformed, and
//                       false if no changes were made.
//
bool
StringTransform::gtransform(Module &M,
                            const SourceFunction &from,
                            const DestFunction &to,
                            Statistic &stat,
                            const vector<unsigned> &append_order) {
  // Get the source function if it exists in the module.
  Function *src = M.getFunction(from.name);
  if (!src)
    return false;
  // Make sure the source function behaves as described, otherwise skip it.
  FunctionType *F_type = src->getFunctionType();
  if (F_type->getReturnType() != from.return_type || F_type->isVarArg() ||
      F_type->getNumParams() != from.argc)
    return false;
  // Make sure the append_order vector has the expected number of elements.
  assert(append_order.size() == to.source_argc &&
    "Unexpected number of parameter positions in vector!");
  // Check that each pool parameter has a corresponding original parameter.
  assert(to.pool_argc <= to.source_argc && "More pools than arguments?");
  // Check if the pool completeness information can be fit into a single 8 bit
  // quantity.
  assert(to.pool_argc <= 8 && "Only up to 8 pool parameters supported!");
  std::vector<Instruction *> toModify;
  std::vector<Instruction *>::iterator modifyIter, modifyEnd;
  // Scan through the module for uses of the function to transform.
  for (Value::use_iterator UI = src->use_begin(), UE = src->use_end();
       UI != UE;
       ++UI) {
    CallSite CS(*UI);
    // Ensure the use is an instruction and that the instruction calls the
    // source function (as opposed to passing it as a parameter or other
    // possible uses).
    if (!CS || CS.getCalledValue() != src)
      continue;
    toModify.push_back(CS.getInstruction());
  }
  // Return early if we've found nothing to modify.
  if (toModify.empty())
    return false;
  // The pool handle type is a void pointer (i8 *).
  PointerType *VoidPtrTy = IntegerType::getInt8PtrTy(M.getContext());
  Type *Int8Ty = IntegerType::getInt8Ty(M.getContext());
  // Build the type of the parameters to the transformed function. This function
  // has to.pool_argc initial arguments of type i8 *.
  std::vector<Type *> ParamTy(to.pool_argc, VoidPtrTy);
  // After the initial pool arguments, parameters from the original function go
  // into the type.
  for (unsigned i = 0; i < to.source_argc; i++) {
    unsigned position = append_order[i];
    assert(0 < position && position <= from.argc && "Parameter out of bounds!");
    Type *ParamType = F_type->getParamType(position - 1);
    if (i < to.pool_argc)
      assert(
        isa<PointerType>(ParamType) && "Pointer type expected for parameter!"
      );
    ParamTy.push_back(ParamType);
  }
  // The completeness bitvector goes at the end.
  ParamTy.push_back(Int8Ty);
  // Build the type of the transformed function.
  FunctionType *FT = FunctionType::get(F_type->getReturnType(), ParamTy, false);
#ifndef NDEBUG
  Function *PoolFInModule = M.getFunction(to.name);
  // Make sure that the function declarations don't conflict.
  assert((PoolFInModule == 0 ||
    PoolFInModule->getFunctionType() == FT ||
    PoolFInModule->hasLocalLinkage()) &&
    "Replacement function already declared with wrong type!");
#endif
  // Build the actual transformed function.
  Constant *PoolF = M.getOrInsertFunction(to.name, FT);
  // This is a placeholder value for the pool handles (to be "filled in" later
  // by poolalloc).
  Value *PH = ConstantPointerNull::get(VoidPtrTy);
  // Transform every valid use of the function that was found.
  for (modifyIter = toModify.begin(), modifyEnd = toModify.end();
       modifyIter != modifyEnd;
       ++modifyIter) {
    Instruction *I = *modifyIter;
    // Construct vector of parameters to transformed function call. Also insert
    // NULL pool handles.
    std::vector<Value *> Params(to.pool_argc, PH);
    // Insert the original parameters.
    for (unsigned i = 0; i < to.source_argc; i++) {
      Value *f = I->getOperand(append_order[i] - 1);
      Params.push_back(f);
    }
    // Add the DSA completeness bitvector. Set it to 0 (= incomplete).
    Params.push_back(ConstantInt::get(Int8Ty, 0));
    // Create the call instruction for the transformed function and insert it
    // before the current instruction.
    CallInst *C = CallInst::Create(PoolF, Params, "", I);
    if (InvokeInst* Invoke = dyn_cast<InvokeInst>(I)) {
      // Our versions don't throw under any circumstances.
      // Just branch to normal:
      BranchInst::Create(Invoke->getNormalDest(), I);
      // Remove any PHIs relying on the removed edge to the unwind BB
      removeInvokeUnwindPHIs(Invoke);
    }
    // Transfer debugging metadata if it exists from the old call into the new
    // one.
    if (MDNode *DebugNode = I->getMetadata("dbg"))
      C->setMetadata("dbg", DebugNode);
    // Replace all uses of the function with its transformed equivalent.
    I->replaceAllUsesWith(C);
    I->eraseFromParent();
    // Record the transformation.
    ++stat;
  }
  // Reaching here means some call has been modified;
  return true;
}

}
