mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
4.4 KiB
182 lines
4.4 KiB
/*
|
|
* Example torture memory allocator with memory wiping and check for
|
|
* out-of-bounds writes.
|
|
*
|
|
* Allocation structure:
|
|
*
|
|
* [ alloc_hdr | red zone before | user area | red zone after ]
|
|
*
|
|
* ^ ^
|
|
* | `--- pointer returned to Duktape
|
|
* `--- underlying malloc ptr
|
|
*/
|
|
|
|
#include "duktape.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#define RED_ZONE_SIZE 16
|
|
#define RED_ZONE_BYTE 0x5a
|
|
#define INIT_BYTE 0xa5
|
|
#define WIPE_BYTE 0x27
|
|
|
|
typedef struct {
|
|
/* The double value in the union is there to ensure alignment is
|
|
* good for IEEE doubles too. In many 32-bit environments 4 bytes
|
|
* would be sufficiently aligned and the double value is unnecessary.
|
|
*/
|
|
union {
|
|
size_t sz;
|
|
double d;
|
|
} u;
|
|
} alloc_hdr;
|
|
|
|
static void check_red_zone(alloc_hdr *hdr) {
|
|
size_t size;
|
|
int i;
|
|
int err;
|
|
unsigned char *p;
|
|
unsigned char *userptr;
|
|
|
|
size = hdr->u.sz;
|
|
userptr = (unsigned char *) hdr + sizeof(alloc_hdr) + RED_ZONE_SIZE;
|
|
|
|
err = 0;
|
|
p = (unsigned char *) hdr + sizeof(alloc_hdr);
|
|
for (i = 0; i < RED_ZONE_SIZE; i++) {
|
|
if (p[i] != RED_ZONE_BYTE) {
|
|
err = 1;
|
|
}
|
|
}
|
|
if (err) {
|
|
fprintf(stderr, "RED ZONE CORRUPTED BEFORE ALLOC: hdr=%p ptr=%p size=%ld\n",
|
|
(void *) hdr, (void *) userptr, (long) size);
|
|
fflush(stderr);
|
|
}
|
|
|
|
err = 0;
|
|
p = (unsigned char *) hdr + sizeof(alloc_hdr) + RED_ZONE_SIZE + size;
|
|
for (i = 0; i < RED_ZONE_SIZE; i++) {
|
|
if (p[i] != RED_ZONE_BYTE) {
|
|
err = 1;
|
|
}
|
|
}
|
|
if (err) {
|
|
fprintf(stderr, "RED ZONE CORRUPTED AFTER ALLOC: hdr=%p ptr=%p size=%ld\n",
|
|
(void *) hdr, (void *) userptr, (long) size);
|
|
fflush(stderr);
|
|
}
|
|
}
|
|
|
|
void *duk_alloc_torture(void *udata, duk_size_t size) {
|
|
unsigned char *p;
|
|
|
|
(void) udata; /* Suppress warning. */
|
|
|
|
if (size == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE);
|
|
if (!p) {
|
|
return NULL;
|
|
}
|
|
|
|
((alloc_hdr *) p)->u.sz = size;
|
|
p += sizeof(alloc_hdr);
|
|
memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE);
|
|
p += RED_ZONE_SIZE;
|
|
memset((void *) p, INIT_BYTE, size);
|
|
p += size;
|
|
memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE);
|
|
p -= size;
|
|
return (void *) p;
|
|
}
|
|
|
|
void *duk_realloc_torture(void *udata, void *ptr, duk_size_t size) {
|
|
unsigned char *p, *old_p;
|
|
size_t old_size;
|
|
|
|
(void) udata; /* Suppress warning. */
|
|
|
|
/* Handle the ptr-NULL vs. size-zero cases explicitly to minimize
|
|
* platform assumptions. You can get away with much less in specific
|
|
* well-behaving environments.
|
|
*/
|
|
|
|
if (ptr) {
|
|
old_p = (unsigned char *) ptr - sizeof(alloc_hdr) - RED_ZONE_SIZE;
|
|
old_size = ((alloc_hdr *) old_p)->u.sz;
|
|
check_red_zone((alloc_hdr *) old_p);
|
|
|
|
if (size == 0) {
|
|
memset((void *) old_p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE);
|
|
free((void *) old_p);
|
|
return NULL;
|
|
} else {
|
|
/* Force address change on every realloc. */
|
|
p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE);
|
|
if (!p) {
|
|
return NULL;
|
|
}
|
|
|
|
((alloc_hdr *) p)->u.sz = size;
|
|
p += sizeof(alloc_hdr);
|
|
memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE);
|
|
p += RED_ZONE_SIZE;
|
|
if (size > old_size) {
|
|
memcpy((void *) p, (void *) (old_p + sizeof(alloc_hdr) + RED_ZONE_SIZE), old_size);
|
|
memset((void *) (p + old_size), INIT_BYTE, size - old_size);
|
|
} else {
|
|
memcpy((void *) p, (void *) (old_p + sizeof(alloc_hdr) + RED_ZONE_SIZE), size);
|
|
}
|
|
p += size;
|
|
memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE);
|
|
p -= size;
|
|
|
|
memset((void *) old_p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE);
|
|
free((void *) old_p);
|
|
|
|
return (void *) p;
|
|
}
|
|
} else {
|
|
if (size == 0) {
|
|
return NULL;
|
|
} else {
|
|
p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE);
|
|
if (!p) {
|
|
return NULL;
|
|
}
|
|
|
|
((alloc_hdr *) p)->u.sz = size;
|
|
p += sizeof(alloc_hdr);
|
|
memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE);
|
|
p += RED_ZONE_SIZE;
|
|
memset((void *) p, INIT_BYTE, size);
|
|
p += size;
|
|
memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE);
|
|
p -= size;
|
|
return (void *) p;
|
|
}
|
|
}
|
|
}
|
|
|
|
void duk_free_torture(void *udata, void *ptr) {
|
|
unsigned char *p;
|
|
size_t old_size;
|
|
|
|
(void) udata; /* Suppress warning. */
|
|
|
|
if (!ptr) {
|
|
return;
|
|
}
|
|
|
|
p = (unsigned char *) ptr - sizeof(alloc_hdr) - RED_ZONE_SIZE;
|
|
old_size = ((alloc_hdr *) p)->u.sz;
|
|
|
|
check_red_zone((alloc_hdr *) p);
|
|
memset((void *) p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE);
|
|
free((void *) p);
|
|
}
|
|
|