blob: 991edf921c64784299385cd09334e1a5c6aaaac4 [file] [log] [blame]
//===- FormatStrings.h - Header for the format string function runtime ----===//
//
// 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 contains definitions of structures and functions used by the
// format string functions in the runtime.
//
//===----------------------------------------------------------------------===//
#ifndef _FORMAT_STRING_RUNTIME_H
#define _FORMAT_STRING_RUNTIME_H
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
#include <iostream>
#include "PoolAllocator.h"
//
// Enable support for floating point numbers.
//
#define FLOATING_POINT
//
// The pointer_info structure and associated flags
// This holds a pointer argument to a format string function.
// This structure is initialized by a call to sc.fsparameter.
//
#define ISCOMPLETE 0x01 // Whether the pointer is complete according to DSA
#define ISRETRIEVED 0x02 // Whether there has been an attempt made to retrive
// the target object's boundaries
#define HAVEBOUNDS 0x04 // Whether the boundaries were retrieved successfully
#define NULL_PTR 0x08 // Whether the pointer in the structure is NULL
typedef struct
{
void *ptr; // The pointer which is wrapped by this structure
void *pool; // The pool to which the pointer belongs
void *bounds[2]; // Space for retrieving object boundaries
uint8_t flags; // See above
} pointer_info;
//
// The call_info structure, which is initialized by sc.fscallinfo before a call
// to a format string function.
//
typedef struct
{
uint32_t vargc; // The number of varargs to this function call
uint32_t tag; // tag, line_no, source_file hold debug information
uint32_t line_no;
const char *source_info;
void *whitelist[1]; // This is a list of pointer arguments that the
// format string function should treat as varargs
// arguments which are pointers. These arguments are
// all pointer_info structures. The list is terminated
// by a NULL element.
} call_info;
//
// This structure describes where to print the output for the internal printf()
// wrapper.
//
typedef struct
{
enum
{
OUTPUT_TO_ALLOCATED_STRING,
OUTPUT_TO_STRING,
OUTPUT_TO_FILE
} output_kind;
union
{
FILE *file;
struct
{
pointer_info *info;
char *string;
size_t pos;
size_t maxsz; // Maximum size of the array that can be written into the
// object safely. (SAFECode-imposed)
size_t n; // The maximum number of bytes to write. (user-imposed)
} string;
struct
{
char *string;
size_t bufsz;
size_t pos;
} alloced_string;
} output;
} output_parameter;
#define USE_M_DIRECTIVE 0x0001 // Enable parsing of the %m directive for
// syslog()
typedef unsigned options_t;
//
// This structure describes where to get input characters for the internal
// scanf() wrapper.
//
typedef struct
{
enum
{
INPUT_FROM_STREAM,
INPUT_FROM_STRING
} input_kind;
union
{
struct
{
FILE *stream;
char lastch;
} stream;
struct
{
const char *string;
size_t pos;
} string;
} input;
} input_parameter;
//
// Error reporting functions
//
extern void out_of_bounds_error(call_info *c,
pointer_info *p,
size_t obj_len);
extern void write_out_of_bounds_error(call_info *c,
pointer_info *p,
size_t dst_sz,
size_t src_sz);
extern void c_library_error(call_info *c, const char *function);
extern void load_store_error(call_info *c, pointer_info *p);
//
// Printing/scanning functions
//
extern int gprintf(const options_t &Options,
output_parameter &P,
call_info &C,
pointer_info &FormatString,
va_list Args);
extern int gscanf(input_parameter &P,
call_info &C,
pointer_info &FormatString,
va_list Args);
extern int internal_printf(const options_t &options,
output_parameter &P,
call_info &C,
const char *fmt,
va_list args);
extern int internal_scanf(input_parameter &p,
call_info &c,
const char *fmt,
va_list args);
namespace
{
using std::cerr;
using std::endl;
using namespace NAMESPACE_SC;
//
// find_object()
//
// Get the object boundaries of the pointer associated with the pointer_info
// structure.
//
// Inputs:
// c - a pointer to the relevant call_info structure
// p - a pointer to a valid pointer_info structure which contains the pointer
// whose object boundaries should be discovered
//
//
static inline void
find_object(call_info *c, pointer_info *p)
{
if (p->flags & ISRETRIEVED)
return;
DebugPoolTy *pool = (DebugPoolTy *) p->pool;
if (p->ptr == 0)
p->flags |= NULL_PTR;
else if ((pool && pool->Objects.find(p->ptr, p->bounds[0], p->bounds[1])) ||
ExternalObjects.find(p->ptr, p->bounds[0], p->bounds[1]))
{
p->flags |= HAVEBOUNDS;
}
else if (p->flags & ISCOMPLETE)
{
cerr << "Object not found in pool!" << endl;
load_store_error(c, p);
}
p->flags |= ISRETRIEVED;
}
//
// is_in_whitelist()
//
// Check if a (non-NULL) pointer_info structure exists in the whitelist of the
// given call_info structure.
//
static inline bool
is_in_whitelist(call_info *c, pointer_info *p)
{
void **whitelist = c->whitelist;
do
{
if ((void *) p == *whitelist)
break;
whitelist++;
} while (*whitelist);
return (*whitelist != 0);
}
//
// object_len()
//
// Get the number of bytes in the object that the pointer associated with the
// pointer_info structure points to, from address the pointer points to, until
// the end of the object.
//
// Note: Call find_object() before calling this.
//
static inline size_t
object_len(pointer_info *p)
{
return 1 + (size_t) ((char *) p->bounds[1] - (char *) p->ptr);
}
//
// write_check()
//
// Check if a write into the object associated with the given pointer_info
// structure of n bytes would be safe.
//
// Inputs:
// c - the relevant call_info structure
// p - the pointer_info structure
// n - the size of the write
//
// This function outputs any relevant SAFECode messages. It returns true if
// the write is to be considered safe, and false otherwise.
//
static inline bool
write_check(call_info *c, pointer_info *p, size_t n)
{
size_t max;
//
// First check if the object is a valid pointer_info structure.
//
if (p == 0 || !is_in_whitelist(c, p))
{
cerr << "The destination of the write isn't a valid pointer!" << endl;
c_library_error(c, "va_arg");
return false;
}
//
// Look up the object boundaries.
//
find_object(c, p);
//
// Check for NULL pointer writes.
//
if (p->flags & NULL_PTR)
{
cerr << "Writing into a NULL pointer!" << endl;
c_library_error(c, "va_arg");
return false;
}
else if (p->flags & HAVEBOUNDS)
{
max = object_len(p);
if (n > max)
{
cerr << "Writing out of bounds!" << endl;
write_out_of_bounds_error(c, p, max, n);
return false;
}
else
return true;
}
//
// Assume an object without discovered boundaries has enough space.
//
return true;
}
//
// varg_check()
//
// Check if too many arguments are accessed, if so, report an error.
//
// Inputs:
// c - the call_info structure describing the function call
// pos - the number of the variable argument that the function is trying to
// access
//
// This function returns true if an argument is trying to be accessed beyond
// the arguments that exist to the function call, and false otherwise.
//
static inline bool
varg_check(call_info *c, unsigned pos)
{
if (pos > c->vargc)
{
if (c->vargc == 1)
{
cerr << "Attempting to access argument " << pos << \
" but there is only 1 argument!" << endl;
}
else
{
cerr << "Attempting to access argument " << pos << \
" but there are only " << c->vargc << " arguments!" << endl;
}
c_library_error(c, "va_arg");
return true;
}
return false;
}
//
// unwrap_pointer()
//
// Get the actual pointer argument from the given parameter. If the parameter
// is whitelisted and so a wrapper, this retrieves the pointer from the
// wrapper. Otherwise it just returns the parameter because it isn't
// recognized as a wrapper.
//
// Inputs:
// c - a pointer to the relevant call_info structure
// p - a pointer to the pointer_info structure to query
//
// Returns:
// This function returns p->ptr if p is a valid pointer_info structure found
// in the whitelist, and p otherwise.
//
static inline void *
unwrap_pointer(call_info *c, void *p)
{
if (is_in_whitelist(c, (pointer_info *) p))
return ((pointer_info *) p)->ptr;
else
return p;
}
//
// This function is identical to strnlen(), which is not found on Mac OS X.
//
static inline size_t
_strnlen(const char *s, size_t n)
{
size_t i;
for (i = 0; i < n; i++)
if (s[i] == '\0')
break;
return i;
}
}
#endif