blob: b0c6d2cab6b152a6ebef10ec33311bce4d9e9d24 [file] [log] [blame]
//===------- CStdLib.h - CStdLib runtime helper functions -----------------===//
//
// 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 all external functions included by the CStdLib pass.
//
//===----------------------------------------------------------------------===//
#ifndef _CSTDLIB_H
#define _CSTDLIB_H
#include "../include/CStdLibSupport.h"
#include "../include/CWE.h"
#include "../include/strnlen.h"
#include "DebugReport.h"
#include "PoolAllocator.h"
#include <iostream>
#define TAG unsigned tag
#define SRC_INFO const char *SourceFile, unsigned lineNo
// Default versions of arguments to debug functions
#define DEFAULT_TAG 0
#define DEFAULT_SRC_INFO "<Unknown>", 0
#define DEFAULTS DEFAULT_TAG, DEFAULT_SRC_INFO
#define SRC_INFO_ARGS SourceFile, lineNo
using namespace llvm;
namespace {
//
// Various violation types
//
static inline void
OOB_VIOLATION(const void *fault_ptr,
DebugPoolTy *handle,
const void *start,
size_t len,
SRC_INFO) {
OutOfBoundsViolation v;
v.type = ViolationInfo::FAULT_OUT_OF_BOUNDS;
v.faultPC = __builtin_return_address(0);
v.faultPtr = fault_ptr;
v.CWE = CWEBufferOverflow;
v.SourceFile = SourceFile;
v.lineNo = lineNo;
v.PoolHandle = handle;
v.objStart = start;
v.objLen = len;
v.dbgMetaData = NULL;
ReportMemoryViolation(&v);
}
static inline void
WRITE_VIOLATION(const void *fault_ptr,
DebugPoolTy *handle,
size_t dst_sz,
size_t src_sz,
SRC_INFO) {
WriteOOBViolation v;
v.type = ViolationInfo::FAULT_WRITE_OUT_OF_BOUNDS;
v.faultPC = __builtin_return_address(0);
v.faultPtr = fault_ptr;
v.CWE = CWEBufferOverflow;
v.SourceFile = SourceFile;
v.lineNo = lineNo;
v.PoolHandle = handle;
v.dstSize = dst_sz;
v.srcSize = src_sz;
v.dbgMetaData = NULL;
ReportMemoryViolation(&v);
}
static inline void
LOAD_STORE_VIOLATION(const void *fault_ptr,
DebugPoolTy *handle,
SRC_INFO) {
DebugViolationInfo v;
v.faultPC = __builtin_return_address(0);
v.faultPtr = fault_ptr;
v.CWE = CWEBufferOverflow;
v.dbgMetaData = NULL;
v.PoolHandle = handle;
v.SourceFile = SourceFile;
v.lineNo = lineNo;
ReportMemoryViolation(&v);
}
static inline void
C_LIBRARY_VIOLATION(const void *fault_ptr,
DebugPoolTy *handle,
const char *function,
SRC_INFO) {
CStdLibViolation v;
v.type = ViolationInfo::FAULT_CSTDLIB;
v.faultPC = __builtin_return_address(0);
v.faultPtr = fault_ptr;
v.CWE = CWEBufferOverflow;
v.SourceFile = SourceFile;
v.lineNo = lineNo;
v.PoolHandle = handle;
v.function = function;
v.dbgMetaData = NULL;
ReportMemoryViolation(&v);
}
//
// Check for string termination.
//
// @param start This is a pointer to the start of the string.
// @param end The end of the object. String is not scanned farther than here.
// @param p Reference to size object. Filled with the length of the string if
// string is terminated, otherwised filled with the size of the object.
// @return Returns true if the string is terminated within bounds (ie.,
// if the nul terminator occurs between string and end, inclusive).
// Returns false if no nul terminator was found.
//
// Note that start and end should be valid boundaries for a valid object.
//
static inline bool
isTerminated(const char *start, void *end, size_t &p) {
size_t max = 1 + ((char *)end - (const char *)start), len;
len = _strnlen((const char *)start, max);
p = len;
if (len == max)
return false;
else
return true;
}
//
// Check for object overlap.
//
// @param ptr1Start The start of the first memory object
// @param ptr1End The end of the first memory object or the bound that writing
// operation actually touch.
// @param ptr2Start The start of the second memory object
// @param ptr2End The end of the second memory object or the bound that writing
// operation actually touch.
//
// @return Whether these 2 memory object overlaps
//
static inline bool
isOverlapped(const void* ptr1Start,
const void* ptr1End,
const void* ptr2Start,
const void* ptr2End) {
if( ((long int)ptr1Start>(long int)ptr2End && (long int)ptr1End>(long int)ptr2Start) ||
((long int)ptr1Start<(long int)ptr2End && (long int)ptr1End<(long int)ptr2Start) )
return false;
return true;
}
//
// Searches inside the given pool for the memory object associated with the
// the given address. If the memory object is found, it sets the poolBegin
// and poolEnd pointers to point to the first and last valid positions of
// the memory object, and returns true. If the memory object is not found in
// the pool, or the pool is NULL, it attemps to find the object in the external
// objects pool. When the object is not found in either pool, the function
// returns false.
//
// @param pool The pool handle which is expected to contain the object.
// @param address The address for which the bounding object is sought.
// @param poolBegin Reference to a pointer to set to the beginning of
// the memory object.
// @param poolEnd Reference to a pointer to set to the last valid address
// the memory object.
// @return Returns true if the object was found, false otherwise.
//
static inline bool
pool_find(DebugPoolTy *pool, void *address, void *&poolBegin, void *&poolEnd) {
if (address == NULL)
return false;
// Retrieve memory area's bounds from pool handle.
if ((pool && pool->Objects.find(address, poolBegin, poolEnd)) ||
ExternalObjects->find(address, poolBegin, poolEnd))
return true;
return false;
}
//
// Macros for determining the completeness of pointer arguments using the
// completeness bitwise vector.
//
#define ARG1_COMPLETE(c) ((bool) (c & 0x1))
#define ARG2_COMPLETE(c) ((bool) (c & 0x2))
// Return the number of bytes between a and b, inclusive.
static inline size_t byte_range(const void *a, const void *b) {
return 1 + (char *) b - (char *) a;
}
// Use this stream for reporting errors.
static std::ostream &err = std::cerr;
//
// This function attempts to verify that given string pointer points to
// a valid string that is terminated within its memory object's boundaries.
// For strings that are marked complete, if the string is discovered to be
// not in its pool, or unterminated within memory object boundaries,
// the function reports a violation and returns false.
// For strings not marked complete, the function attempts to do the same
// checks as for complete pointers, except that it assumes the string was
// valid if the string's memory object is not found in the pool.
//
// The function returns true if no memory violations were discovered, and
// false when there was a violation.
//
// @param string The pointer to the string to be checked.
// @param pool The pool that should be searched for the memory object
// that contains the string.
// @param complete This is a boolean value which is true if the string
// pointer was reported complete by DSA, and false if not.
// If the string is incomplete, no errors are reported
// if it does not exist in the pool and is non-NULL.
// @param function The name of the C library function for debug reporting
// purposes.
// @param SRC_INFO Source and line info debug information.
// @return Returns true if no violations were discoverd, and false
// if the pointer does not point to a valid string and a
// memory violation was reported.
// Note that if the function returns true, the pointer may
// still not point to a valid string if the pointer was
// incomplete.
//
static inline bool
validStringCheck(const char *string,
DebugPoolTy *pool,
bool complete,
const char *function,
SRC_INFO) {
void *objStart, *objEnd;
size_t len;
// Check if the string is NULL. If it is, report this as an error.
if (string == NULL) {
err << "String pointer is NULL!\n";
C_LIBRARY_VIOLATION(string, pool, function, SRC_INFO_ARGS);
return false;
}
// Retrieve the string from the pool. If no string is found and the pointer
// is not complete, return true. Otherwise report an error and return false.
if (!pool_find(pool, (void *)string, objStart, objEnd)) {
if (complete) {
err << "String not found in pool!\n";
LOAD_STORE_VIOLATION(string, pool, SRC_INFO_ARGS);
return false;
}
else
return true;
}
// Do a termination check.
if (!isTerminated(string, objEnd, len)) {
err << "String is not terminated within object bounds!\n";
C_LIBRARY_VIOLATION(string, pool, function, SRC_INFO_ARGS);
return false;
}
return true;
}
//
// Check to see if the memory region between the location pointed to by Buf
// and the end of the same memory object is of at least the given minimum size.
//
// This function will look up the buffer object in the pool to determine its
// size. If the pointer is complete and not found in the pool the function
// will report an error. If the pointer points to a region of size less than
// MinSize then this function will report an error.
//
// Inputs
// Pool - The pool handle for the buffer
// Buf - The buffer
// Complete - A boolean describing if the pointer is complete
// MinSize - The minimum expected size of the region pointed to by Buf
// SRC_INFO - Source file and line number information for debugging purposes
//
static inline void
minSizeCheck (DebugPoolTy * Pool,
void * Buf,
bool Complete,
size_t MinSize,
SRC_INFO) {
bool Found;
void * BufStart = 0, * BufEnd = 0;
//
// Retrive the buffer's bound from the pool. If we cannot find the object and
// we know everything about what the buffer should be pointing to, then
// report an error.
//
if (!(Found = pool_find (Pool, Buf, BufStart, BufEnd)) && Complete) {
LOAD_STORE_VIOLATION (Buf, Pool, SRC_INFO_ARGS);
}
if (Found) {
//
// Make sure that the region between the location pointed to by Buf and the
// end of the same memory object is of size at least MinSize.
//
size_t BufSize = byte_range (Buf, BufEnd);
if (BufSize < MinSize) {
C_LIBRARY_VIOLATION (Buf, Pool, "", SRC_INFO_ARGS);
}
}
return;
}
}
#endif // _CSTDLIB_H