<commit_before>/*
 *  Tiny C Memory and bounds checker
 * 
 *  Copyright (c) 2002 <NAME>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <malloc.h>

//#define BOUND_DEBUG

/* define so that bound array is static (faster, but use memory if
   bound checking not used) */
//#define BOUND_STATIC

/* use malloc hooks. Currently the code cannot be reliable if no hooks */
#define CONFIG_TCC_MALLOC_HOOKS

#define BOUND_T1_BITS 13
#define BOUND_T2_BITS 11
#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)

#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
#define BOUND_E_BITS  4

#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)


/* this pointer is generated when bound check is incorrect */
#define INVALID_POINTER ((void *)(-2))
/* size of an empty region */
#define EMPTY_SIZE        0xffffffff
/* size of an invalid region */
#define INVALID_SIZE      0

typedef struct BoundEntry {
    unsigned long start;
    unsigned long size;
    struct BoundEntry *next;
    unsigned long is_invalid; /* true if pointers outside region are invalid */
} BoundEntry;

/* external interface */
void __bound_init(void);
void __bound_new_region(void *p, unsigned long size);
int __bound_delete_region(void *p);

/* currently, tcc cannot compile that because we use unsupported GNU C
   extensions */
#if !defined(__TINYC__)
void *__bound_ptr_add(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir1(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir2(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir4(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir8(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir12(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir16(void *p, int offset) __attribute__((regparm(2)));
void __bound_local_new(void *p) __attribute__((regparm(1)));
void __bound_local_delete(void *p) __attribute__((regparm(1)));
#endif
static void *get_caller_pc(int n);

void *__bound_malloc(size_t size, const void *caller);
void *__bound_memalign(size_t size, size_t align, const void *caller);
void __bound_free(void *ptr, const void *caller);
void *__bound_realloc(void *ptr, size_t size, const void *caller);
static void *libc_malloc(size_t size);
static void libc_free(void *ptr);
static void install_malloc_hooks(void);
static void restore_malloc_hooks(void);

#ifdef CONFIG_TCC_MALLOC_HOOKS
static void *saved_malloc_hook;
static void *saved_free_hook;
static void *saved_realloc_hook;
static void *saved_memalign_hook;
#endif

extern char _end;

/* TCC defines: */
extern char __bounds_start; /* start of static bounds table */
/* runtime error output */
extern void rt_error(unsigned long pc, const char *fmt, ...);

#ifdef BOUND_STATIC
static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
#else
static BoundEntry **__bound_t1; /* page table */
#endif
static BoundEntry *__bound_empty_t2;   /* empty page, for unused pages */
static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */

static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
{
    unsigned long addr, tmp;
    BoundEntry *e;

    e = e1;
    while (e != NULL) {
        addr = (unsigned long)p;
        addr -= e->start;
        if (addr <= e->size) {
            /* put region at the head */
            tmp = e1->start;
            e1->start = e->start;
            e->start = tmp;
            tmp = e1->size;
            e1->size = e->size;
            e->size = tmp;
            return e1;
        }
        e = e->next;
    }
    /* no entry found: return empty entry or invalid entry */
    if (e1->is_invalid)
        return __bound_invalid_t2;
    else
        return __bound_empty_t2;
}

/* print a bound error message */
static void bound_error(const void *caller, const char *fmt, ...)
{
    rt_error((unsigned long)caller, "%s", fmt);
}

static void bound_alloc_error(void)
{
    bound_error(NULL, "not enough memory for bound checking code");
}

/* currently, tcc cannot compile that because we use GNUC extensions */
#if !defined(__TINYC__)

/* return '(p + offset)' for pointer arithmetic (a pointer can reach
   the end of a region in this case */
void *__bound_ptr_add(void *p, int offset)
{
    unsigned long addr = (unsigned long)p;
    BoundEntry *e;
#if defined(BOUND_DEBUG)
    printf("add: 0x%x %d\n", (int)p, offset);
#endif<commit_msg>added support for standalone operation<commit_after>/*
 *  Tiny C Memory and bounds checker
 * 
 *  Copyright (c) 2002 <NAME>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <malloc.h>

//#define BOUND_DEBUG

/* define so that bound array is static (faster, but use memory if
   bound checking not used) */
//#define BOUND_STATIC

/* use malloc hooks. Currently the code cannot be reliable if no hooks */
#define CONFIG_TCC_MALLOC_HOOKS

#define BOUND_T1_BITS 13
#define BOUND_T2_BITS 11
#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)

#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
#define BOUND_E_BITS  4

#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)


/* this pointer is generated when bound check is incorrect */
#define INVALID_POINTER ((void *)(-2))
/* size of an empty region */
#define EMPTY_SIZE        0xffffffff
/* size of an invalid region */
#define INVALID_SIZE      0

typedef struct BoundEntry {
    unsigned long start;
    unsigned long size;
    struct BoundEntry *next;
    unsigned long is_invalid; /* true if pointers outside region are invalid */
} BoundEntry;

/* external interface */
void __bound_init(void);
void __bound_new_region(void *p, unsigned long size);
int __bound_delete_region(void *p);

/* currently, tcc cannot compile that because we use unsupported GNU C
   extensions */
#if !defined(__TINYC__)
void *__bound_ptr_add(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir1(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir2(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir4(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir8(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir12(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir16(void *p, int offset) __attribute__((regparm(2)));
void __bound_local_new(void *p) __attribute__((regparm(1)));
void __bound_local_delete(void *p) __attribute__((regparm(1)));
#endif
static void *get_caller_pc(int n);

void *__bound_malloc(size_t size, const void *caller);
void *__bound_memalign(size_t size, size_t align, const void *caller);
void __bound_free(void *ptr, const void *caller);
void *__bound_realloc(void *ptr, size_t size, const void *caller);
static void *libc_malloc(size_t size);
static void libc_free(void *ptr);
static void install_malloc_hooks(void);
static void restore_malloc_hooks(void);

#ifdef CONFIG_TCC_MALLOC_HOOKS
static void *saved_malloc_hook;
static void *saved_free_hook;
static void *saved_realloc_hook;
static void *saved_memalign_hook;
#endif

/* linker definitions */
extern char _end;

/* TCC definitions */
extern char __bounds_start; /* start of static bounds table */
/* error function. if NULL, simply do abort() */
void (*__bound_error_func)(unsigned long caller, const char *msg);

/* runtime error output */
extern void rt_error(unsigned long pc, const char *fmt, ...);

#ifdef BOUND_STATIC
static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
#else
static BoundEntry **__bound_t1; /* page table */
#endif
static BoundEntry *__bound_empty_t2;   /* empty page, for unused pages */
static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */

static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
{
    unsigned long addr, tmp;
    BoundEntry *e;

    e = e1;
    while (e != NULL) {
        addr = (unsigned long)p;
        addr -= e->start;
        if (addr <= e->size) {
            /* put region at the head */
            tmp = e1->start;
            e1->start = e->start;
            e->start = tmp;
            tmp = e1->size;
            e1->size = e->size;
            e->size = tmp;
            return e1;
        }
        e = e->next;
    }
    /* no entry found: return empty entry or invalid entry */
    if (e1->is_invalid)
        return __bound_invalid_t2;
    else
        return __bound_empty_t2;
}

/* print a bound error message */
static void bound_error(const void *caller, const char *fmt, ...)
{
    if (!__bound_error_func)
        abort();
    __bound_error_func((unsigned long)caller, fmt);
}

static void bound_alloc_error(void)
{
    bound_error(NULL, "not enough memory for bound checking code");
}

/* currently, tcc cannot compile that because we use GNUC extensions */
#if !defined(__TINYC__)

/* return '(p + offset)' for pointer arithmetic (a pointer can reach
   the end of a region in this case */
void *__bound_ptr_add(void *p, int offset)
{
    unsigned long addr = (unsigned long)p;
    BoundEntry *e;
#if defined(BOUND_DEBUG)
    printf("add: 0x%x %d\n", (int)p, offset);
#endif
{'fraction_non_alphanumeric': 0.10596821877309683, 'fraction_numerical': 0.014597191426459719, 'mean_word_length': 4.00925497454882, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7158309', 'n_tokens_mistral': 3623, 'n_tokens_neox': 3511, 'n_words': 1197}