blob: 8ae572037fd52bab6ccb1dc64b563221c68b8080 [file] [log] [blame]
//===------- stdio.cpp - CStdLib Runtime functions for <stdio.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
// <stdio.h>.
//
//===----------------------------------------------------------------------===//
#include <cstdio>
#include "CStdLib.h"
//
// Portions of this file are based on code found in MINIX's source distribution
// in the directory lib/libc/stdio, which has the following license:
//
// Copyright (c) 1987, 1997, 2006, Vrije Universiteit, Amsterdam,
// The Netherlands All rights reserved. Redistribution and use of the MINIX 3
// operating system in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the Vrije Universiteit nor the names of the
// software authors or contributors may be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// * Any deviations from these conditions require written permission
// from the copyright holder in advance
//
//
// Disclaimer
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
// NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Function: pool_fgets()
//
// Description:
// This is a memory safe replacement for the fgets() function.
//
// Inputs:
// Pool - The pool handle for the string to write.
// s - The memory buffer into which to read the result.
// n - The maximum number of bytes to read.
// stream - The FILE * from which to read the data.
// complete - The Completeness bit vector.
// TAG - The Tag information for debugging purposes
// SRC_INFO - Source file and line number information for debugging purposes
//
char *
pool_fgets_debug (DebugPoolTy * Pool,
char * s,
int n,
FILE * stream,
const uint8_t complete,
TAG,
SRC_INFO) {
//
// Determine the completeness of the various pointers.
//
const bool BufferComplete = ARG1_COMPLETE(complete);
//
// Retrieve the buffer's bounds from the pool. If we cannot find the object
// and we know everything about what the buffer should be pointing to (i.e.,
// the check is complete), then report an error.
//
bool found;
void * ObjStart = 0;
void * ObjEnd = 0;
if (!(found = pool_find (Pool, s, ObjStart, ObjEnd)) && BufferComplete) {
LOAD_STORE_VIOLATION (s, Pool, SRC_INFO_ARGS);
}
register int ch = 0;
register char *ptr;
ptr = s;
while (--n > 0 && (ch = getc (stream)) != EOF) {
//
// Check if the object is going to be written out of bounds.
//
if (found && ptr == &((char *) ObjEnd)[1]) {
size_t ObjSz = byte_range ((void *) s, ObjEnd);
WRITE_VIOLATION (ptr, Pool, ObjSz, ObjSz + 1, SRC_INFO_ARGS);
}
*ptr++ = ch;
if (ch == '\n')
break;
}
if (ch == EOF) {
if (feof (stream)) {
if (ptr == s) return NULL;
} else return NULL;
}
//
// Check if the nul terminator is written out of bounds.
//
if (found && ptr == &((char *) ObjEnd)[1]) {
size_t ObjSz = byte_range ((void *) s, ObjEnd);
WRITE_VIOLATION (ptr, Pool, ObjSz, ObjSz + 1, SRC_INFO_ARGS);
}
*ptr = '\0';
return s;
}
char *
pool_fgets (DebugPoolTy * Pool,
char * s,
int n,
FILE * stream,
const uint8_t complete) {
return pool_fgets_debug (Pool, s, n, stream, complete, DEFAULTS);
}
//
// Function: pool_fputs()
//
// Description:
// This is a memory safe replacement for the fputs() function.
//
// Inputs:
// Pool - The pool handle for the string to output.
// s - The memory buffer from which to read the result.
// stream - The FILE * into which to write the data.
// complete - The Completeness bit vector.
// TAG - The Tag information for debugging purposes
// SRC_INFO - Source file and line number information for debugging purposes
//
int
pool_fputs_debug (DebugPoolTy * Pool,
char * s,
FILE * stream,
const uint8_t complete,
TAG,
SRC_INFO) {
validStringCheck (s, Pool, ARG1_COMPLETE(complete), "fputs", SRC_INFO_ARGS);
return fputs (s, stream);
}
int
pool_fputs (DebugPoolTy * Pool,
char * s,
FILE * stream,
const uint8_t complete) {
return pool_fputs_debug (Pool, s, stream, complete, DEFAULTS);
}
//
// Function: pool_gets()
//
// Description:
// This is a "memory safe" replacement for the gets() function.
//
// Inputs:
// Pool - The pool handle for the string to output.
// s - The memory buffer into which to write the result.
// complete - The Completeness bit vector.
// TAG - The Tag information for debugging purposes
// SRC_INFO - Source file and line number information for debugging purposes
//
//
// NOTE:
// This code is very close to that of pool_fgets(), with the following
// changes:
// - No limit on input size is set.
// - Reading is done from stdin.
// - No final newline is ever appended.
//
char *
pool_gets_debug (DebugPoolTy * Pool,
char * s,
const uint8_t complete,
TAG,
SRC_INFO) {
//
// Determine the completeness of the various pointers.
//
const bool BufferComplete = ARG1_COMPLETE(complete);
//
// Retrieve the buffer's bounds from the pool. If we cannot find the object
// and we know everything about what the buffer should be pointing to (i.e.,
// the check is complete), then report an error.
//
bool found;
void * ObjStart = 0;
void * ObjEnd = 0;
if (!(found = pool_find (Pool, s, ObjStart, ObjEnd)) && BufferComplete) {
LOAD_STORE_VIOLATION (s, Pool, SRC_INFO_ARGS);
}
register int ch;
register char *ptr;
ptr = s;
while ((ch = getc(stdin)) != EOF) {
//
// Exit the loop immediately upon reading a newline.
//
if ( ch == '\n')
break;
//
// Check if the object is going to be written out of bounds.
//
if (found && ptr == &((char *) ObjEnd)[1]) {
size_t ObjSz = byte_range ((void *) s, ObjEnd);
WRITE_VIOLATION (ptr, Pool, ObjSz, ObjSz + 1, SRC_INFO_ARGS);
}
*ptr++ = ch;
}
if (ch == EOF) {
if (feof (stdin)) {
if (ptr == s) return NULL;
} else return NULL;
}
//
// Check if the nul terminator is written out of bounds.
//
if (found && ptr == &((char *) ObjEnd)[1]) {
size_t ObjSz = byte_range ((void *) s, ObjEnd);
WRITE_VIOLATION (ptr, Pool, ObjSz, ObjSz + 1, SRC_INFO_ARGS);
}
*ptr = '\0';
return s;
}
char *
pool_gets (DebugPoolTy * Pool,
char * s,
const uint8_t complete) {
return pool_gets_debug (Pool, s, complete, DEFAULTS);
}
//
// Function: pool_puts()
//
// Description:
// This is a memory safe replacement for the puts() function.
//
// Inputs:
// Pool - The pool handle for the string to output.
// s - The memory buffer from which to read the result.
// complete - The Completeness bit vector.
// TAG - The Tag information for debugging purposes
// SRC_INFO - Source file and line number information for debugging purposes
//
int
pool_puts_debug (DebugPoolTy * Pool,
char * s,
const uint8_t complete,
TAG,
SRC_INFO) {
validStringCheck (s, Pool, ARG1_COMPLETE(complete), "fputs", SRC_INFO_ARGS);
return puts (s);
}
int
pool_puts (DebugPoolTy * Pool,
char * s,
const uint8_t complete) {
return pool_puts_debug (Pool, s, complete, DEFAULTS);
}
//
// Function: pool_fread()
//
// Description:
// This is a memory safe replacement for the fread() function.
//
// Inputs:
// Pool - The pool handle for the buffer to write.
// ptr - The buffer into which to write what is read.
// size - The size of an object to read.
// nmemb - The number of objects to read.
// stream - The FILE * from which to read the contents.
// complete - The Completeness bit vector.
// TAG - The Tag information for debugging purposes
// SRC_INFO - Source file and line number information for debugging purposes
//
size_t
pool_fread_debug (DebugPoolTy *Pool,
void *ptr,
size_t size,
size_t nmemb,
FILE *stream,
const uint8_t complete,
TAG,
SRC_INFO) {
//
// Determine the completeness of the various pointers.
//
const bool BufferComplete = ARG1_COMPLETE(complete);
//
// Retrieve the buffer's bounds from the pool. If we cannot find the object
// and we know everything about what the buffer should be pointing to (i.e.,
// the check is complete), then report an error.
//
bool found;
void * ObjStart = 0;
void * ObjEnd = 0;
if (!(found = pool_find (Pool, ptr, ObjStart, ObjEnd)) && BufferComplete) {
LOAD_STORE_VIOLATION (ptr, Pool, SRC_INFO_ARGS);
}
register char *cp = (char *) ptr;
register int c;
size_t ndone = 0;
register size_t s;
if (size)
while ( ndone < nmemb ) {
s = size;
do {
if ((c = getc (stream)) != EOF) {
//
// Check if the object is going to be written out of bounds.
//
if (found && (void*) cp == &((char *) ObjEnd)[1]) {
size_t ObjSz = byte_range (ptr, ObjEnd);
WRITE_VIOLATION (ptr, Pool, ObjSz, ObjSz + 1, SRC_INFO_ARGS);
}
*cp++ = c;
}
else
return ndone;
} while (--s);
ndone++;
}
return ndone;
}
size_t
pool_fread (DebugPoolTy *Pool,
void *ptr,
size_t size,
size_t nmemb,
FILE *stream,
const uint8_t complete) {
return pool_fread_debug (Pool, ptr, size, nmemb, stream, complete, DEFAULTS);
}
//
// Function: pool_fwrite()
//
// Description:
// This is a memory safe replacement for the fwrite() function.
//
// Inputs:
// Pool - The pool handle for the buffer to write.
// ptr - The buffer from which to read the data.
// size - The size of an object to read.
// nmemb - The number of objects to read.
// stream - The FILE * into which to write the contents.
// complete - The Completeness bit vector.
// TAG - The Tag information for debugging purposes
// SRC_INFO - Source file and line number information for debugging purposes
//
size_t
pool_fwrite_debug (DebugPoolTy *Pool,
void *ptr,
size_t size,
size_t nmemb,
register FILE *stream,
const uint8_t complete,
TAG,
SRC_INFO) {
//
// Determine the completeness of the various pointers.
//
const bool BufferComplete = ARG1_COMPLETE(complete);
//
// Retrieve the buffer's bounds from the pool. If we cannot find the object
// and we know everything about what the buffer should be pointing to (i.e.,
// the check is complete), then report an error.
//
bool found;
void * ObjStart = 0;
void * ObjEnd = 0;
if (!(found = pool_find (Pool, ptr, ObjStart, ObjEnd)) && BufferComplete) {
LOAD_STORE_VIOLATION (ptr, Pool, SRC_INFO_ARGS);
}
//
// Check if the function reads a quantity more than the size of the buffer.
//
if (found && size * nmemb > byte_range(ptr, ObjEnd))
OOB_VIOLATION(ptr, Pool, ptr, size * nmemb, SRC_INFO_ARGS);
//
// Perform the write operation.
//
return fwrite(ptr, size, nmemb, stream);
}
size_t
pool_fwrite (DebugPoolTy *Pool,
void *ptr,
size_t size,
size_t nmemb,
register FILE *stream,
const uint8_t complete) {
return pool_fwrite_debug(Pool, ptr, size, nmemb, stream, complete, DEFAULTS);
}
//
// Function: pool_tmpnam()
//
// Description:
// This is a memory safe replacement for the tmpnam() function.
//
// Inputs:
// Pool - The pool handle for the buffer to write.
// str - A pointer to a buffer or NULL
// complete - The Completeness bit vector.
// TAG - The Tag information for debugging purposes
// SRC_INFO - Source file and line number information for debugging purposes
//
// Returns:
// Returns a pointer to a temporary filename
//
char *
pool_tmpnam_debug (DebugPoolTy *Pool,
char *str,
const uint8_t complete,
TAG,
SRC_INFO) {
// str is allowed to be NULL; only perform checks if the string is not null.
if (str != 0) {
// The passed pointer should point to an object at least L_tmpnam in size.
minSizeCheck(Pool, str, ARG1_COMPLETE(complete), L_tmpnam, SRC_INFO_ARGS);
}
return tmpnam(str);
}
char *
pool_tmpnam (DebugPoolTy *Pool,
char *str,
const uint8_t complete) {
return pool_tmpnam_debug(Pool, str, complete, DEFAULTS);
}