mirror of
https://github.com/idris-lang/Idris2.git
synced 2024-12-25 12:42:02 +03:00
Assertions in RefC runtime
Better crash explicitly than debug memory violation. The most important part of this is in `Buffer` implementation.
This commit is contained in:
parent
0fec867583
commit
41c20ddf6a
@ -1,4 +1,5 @@
|
||||
#include "buffer.h"
|
||||
#include "refc_util.h"
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -16,14 +17,23 @@ void* newBuffer(int bytes) {
|
||||
return (void*)buf;
|
||||
}
|
||||
|
||||
void copyBuffer(void* from, int start, int len,
|
||||
void* to, int loc) {
|
||||
static void assert_valid_range(Buffer* buf, int64_t offset, int64_t len) {
|
||||
IDRIS2_REFC_VERIFY(offset >= 0, "offset (%lld) < 0", (long long) offset);
|
||||
IDRIS2_REFC_VERIFY(len >= 0, "len (%lld) < 0", (long long) offset);
|
||||
IDRIS2_REFC_VERIFY(offset + len <= buf->size,
|
||||
"offset (%lld) + len (%lld) > buf.size (%lld)",
|
||||
(long long) offset, (long long) len, (long long) buf->size);
|
||||
}
|
||||
|
||||
void copyBuffer(void* from, int from_offset, int len,
|
||||
void* to, int to_offset) {
|
||||
Buffer* bfrom = from;
|
||||
Buffer* bto = to;
|
||||
|
||||
if (loc >= 0 && loc+len <= bto->size) {
|
||||
memcpy(bto->data + loc, bfrom->data + start, len);
|
||||
}
|
||||
assert_valid_range(bfrom, from_offset, len);
|
||||
assert_valid_range(bto, to_offset, len);
|
||||
|
||||
memcpy(bto->data + to_offset, bfrom->data + from_offset, len);
|
||||
}
|
||||
|
||||
int getBufferSize(void* buffer) {
|
||||
@ -32,87 +42,74 @@ int getBufferSize(void* buffer) {
|
||||
|
||||
void setBufferByte(void* buffer, int loc, int byte) {
|
||||
Buffer* b = buffer;
|
||||
if (loc >= 0 && loc < b->size) {
|
||||
b->data[loc] = byte;
|
||||
}
|
||||
|
||||
assert_valid_range(buffer, loc, 1);
|
||||
|
||||
b->data[loc] = byte;
|
||||
}
|
||||
|
||||
void setBufferInt(void* buffer, int loc, int64_t val) {
|
||||
Buffer* b = buffer;
|
||||
if (loc >= 0 && loc+3 < b->size) {
|
||||
b->data[loc ] = val & 0xff;
|
||||
b->data[loc+1] = (val >> 8) & 0xff;
|
||||
b->data[loc+2] = (val >> 16) & 0xff;
|
||||
b->data[loc+3] = (val >> 24) & 0xff;
|
||||
b->data[loc+4] = (val >> 32) & 0xff;
|
||||
b->data[loc+5] = (val >> 40) & 0xff;
|
||||
b->data[loc+6] = (val >> 48) & 0xff;
|
||||
b->data[loc+7] = (val >> 56) & 0xff;
|
||||
}
|
||||
assert_valid_range(b, loc, 8);
|
||||
b->data[loc ] = val & 0xff;
|
||||
b->data[loc+1] = (val >> 8) & 0xff;
|
||||
b->data[loc+2] = (val >> 16) & 0xff;
|
||||
b->data[loc+3] = (val >> 24) & 0xff;
|
||||
b->data[loc+4] = (val >> 32) & 0xff;
|
||||
b->data[loc+5] = (val >> 40) & 0xff;
|
||||
b->data[loc+6] = (val >> 48) & 0xff;
|
||||
b->data[loc+7] = (val >> 56) & 0xff;
|
||||
}
|
||||
|
||||
void setBufferDouble(void* buffer, int loc, double val) {
|
||||
Buffer* b = buffer;
|
||||
// I am not proud of this
|
||||
if (loc >= 0 && loc + sizeof(double) <= b->size) {
|
||||
unsigned char* c = (unsigned char*)(& val);
|
||||
int i;
|
||||
for (i = 0; i < sizeof(double); ++i) {
|
||||
b->data[loc+i] = c[i];
|
||||
}
|
||||
assert_valid_range(b, loc, sizeof(double));
|
||||
unsigned char* c = (unsigned char*)(& val);
|
||||
int i;
|
||||
for (i = 0; i < sizeof(double); ++i) {
|
||||
b->data[loc+i] = c[i];
|
||||
}
|
||||
}
|
||||
|
||||
void setBufferString(void* buffer, int loc, char* str) {
|
||||
Buffer* b = buffer;
|
||||
int len = strlen(str);
|
||||
|
||||
if (loc >= 0 && loc+len <= b->size) {
|
||||
memcpy((b->data)+loc, str, len);
|
||||
}
|
||||
size_t len = strlen(str);
|
||||
assert_valid_range(b, loc, len);
|
||||
memcpy((b->data)+loc, str, len);
|
||||
}
|
||||
|
||||
uint8_t getBufferByte(void* buffer, int loc) {
|
||||
Buffer* b = buffer;
|
||||
if (loc >= 0 && loc < b->size) {
|
||||
return b->data[loc];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
assert_valid_range(b, loc, 1);
|
||||
return b->data[loc];
|
||||
}
|
||||
|
||||
int64_t getBufferInt(void* buffer, int loc) {
|
||||
Buffer* b = buffer;
|
||||
if (loc >= 0 && loc+7 < b->size) {
|
||||
int64_t result = 0;
|
||||
for (size_t i=0; i<8; i++) {
|
||||
result |= (uint64_t)(uint8_t)b->data[loc + i] << (8 * i);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return 0;
|
||||
assert_valid_range(b, loc, 8);
|
||||
int64_t result = 0;
|
||||
for (size_t i=0; i<8; i++) {
|
||||
result |= (uint64_t)(uint8_t)b->data[loc + i] << (8 * i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double getBufferDouble(void* buffer, int loc) {
|
||||
Buffer* b = buffer;
|
||||
assert_valid_range(b, loc, sizeof(double));
|
||||
double d;
|
||||
// I am even less proud of this
|
||||
unsigned char *c = (unsigned char*)(& d);
|
||||
if (loc >= 0 && loc + sizeof(double) <= b->size) {
|
||||
int i;
|
||||
for (i = 0; i < sizeof(double); ++i) {
|
||||
c[i] = b->data[loc+i];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
int i;
|
||||
for (i = 0; i < sizeof(double); ++i) {
|
||||
c[i] = b->data[loc+i];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
char* getBufferString(void* buffer, int loc, int len) {
|
||||
Buffer* b = buffer;
|
||||
assert_valid_range(b, loc, len);
|
||||
char * s = (char*)(b->data + loc);
|
||||
char * rs = malloc(len + 1);
|
||||
strncpy(rs, s, len);
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "conCaseHelper.h"
|
||||
#include "refc_util.h"
|
||||
|
||||
AConAlt *newConstructorField(int nr)
|
||||
{
|
||||
AConAlt *retVal = (AConAlt *)malloc(nr * sizeof(AConAlt));
|
||||
IDRIS2_REFC_VERIFY(retVal, "malloc failed");
|
||||
for (int i = 0; i < nr; i++)
|
||||
{
|
||||
retVal[i].tag = -1;
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "runtime.h"
|
||||
#include "refc_util.h"
|
||||
|
||||
Value *newValue(size_t size)
|
||||
{
|
||||
Value *retVal = (Value *)malloc(size);
|
||||
IDRIS2_REFC_VERIFY(retVal, "malloc failed");
|
||||
retVal->header.refCounter = 1;
|
||||
retVal->header.tag = NO_TAG;
|
||||
return retVal;
|
||||
@ -225,6 +227,8 @@ void removeReference(Value *elem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
IDRIS2_REFC_VERIFY(elem->header.refCounter > 0,
|
||||
"refCounter %lld", (long long) elem->header.refCounter);
|
||||
// remove reference counter
|
||||
elem->header.refCounter--;
|
||||
if (elem->header.refCounter == 0)
|
||||
|
@ -1,11 +1,14 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "prim.h"
|
||||
#include "refc_util.h"
|
||||
|
||||
// This is NOT THREAD SAFE in the current implementation
|
||||
|
||||
IORef_Storage *newIORef_Storage(int capacity)
|
||||
{
|
||||
IORef_Storage *retVal = (IORef_Storage *)malloc(sizeof(IORef_Storage));
|
||||
IDRIS2_REFC_VERIFY(retVal, "malloc failed");
|
||||
retVal->filled = 0;
|
||||
retVal->total = capacity;
|
||||
retVal->refs = (Value **)malloc(sizeof(Value *) * retVal->total);
|
||||
@ -15,6 +18,7 @@ IORef_Storage *newIORef_Storage(int capacity)
|
||||
void doubleIORef_Storage(IORef_Storage *ior)
|
||||
{
|
||||
Value **values = (Value **)malloc(sizeof(Value *) * ior->total * 2);
|
||||
IDRIS2_REFC_VERIFY(values, "malloc failed");
|
||||
ior->total *= 2;
|
||||
for (int i = 0; i < ior->filled; i++)
|
||||
{
|
||||
@ -174,11 +178,8 @@ Value *System_Concurrency_Raw_prim__makeMutex(Value *_world)
|
||||
Value_Mutex *mut = IDRIS2_NEW_VALUE(Value_Mutex);
|
||||
mut->header.tag = MUTEX_TAG;
|
||||
mut->mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
|
||||
if (pthread_mutex_init(mut->mutex, NULL))
|
||||
{
|
||||
fprintf(stderr, "Error init Mutex\n");
|
||||
exit(-1);
|
||||
}
|
||||
int r = pthread_mutex_init(mut->mutex, NULL);
|
||||
IDRIS2_REFC_VERIFY(!r, "pthread_mutex_init failed: %s", strerror(r));
|
||||
return (Value *)mut;
|
||||
}
|
||||
|
||||
@ -187,11 +188,8 @@ Value *System_Concurrency_Raw_prim__makeMutex(Value *_world)
|
||||
// using pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
Value *System_Concurrency_Raw_prim__mutexAcquire(Value *_mutex, Value *_world)
|
||||
{
|
||||
if (pthread_mutex_lock(((Value_Mutex *)_mutex)->mutex))
|
||||
{
|
||||
fprintf(stderr, "Error locking mutex\n");
|
||||
exit(-1);
|
||||
}
|
||||
int r = pthread_mutex_lock(((Value_Mutex *)_mutex)->mutex);
|
||||
IDRIS2_REFC_VERIFY(!r, "pthread_mutex_lock failed: %s", strerror(r));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -200,11 +198,8 @@ Value *System_Concurrency_Raw_prim__mutexAcquire(Value *_mutex, Value *_world)
|
||||
//using int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
Value *System_Concurrency_Raw_prim__mutexRelease(Value *_mutex, Value *_world)
|
||||
{
|
||||
if (pthread_mutex_unlock(((Value_Mutex *)_mutex)->mutex))
|
||||
{
|
||||
fprintf(stderr, "Error locking mutex\n");
|
||||
exit(-1);
|
||||
}
|
||||
int r = pthread_mutex_unlock(((Value_Mutex *)_mutex)->mutex);
|
||||
IDRIS2_REFC_VERIFY(!r, "pthread_mutex_unlock failed: %s", strerror(r));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -222,11 +217,9 @@ Value *System_Concurrency_Raw_prim__makeCondition(Value *_world)
|
||||
Value_Condition *c = IDRIS2_NEW_VALUE(Value_Condition);
|
||||
c->header.tag = CONDITION_TAG;
|
||||
c->cond = (pthread_cond_t *)malloc(sizeof(pthread_cond_t));
|
||||
if (pthread_cond_init(c->cond, NULL))
|
||||
{
|
||||
fprintf(stderr, "error init condition\n");
|
||||
exit(-1);
|
||||
}
|
||||
IDRIS2_REFC_VERIFY(c->cond, "malloc failed");
|
||||
int r = pthread_cond_init(c->cond, NULL);
|
||||
IDRIS2_REFC_VERIFY(!r, "pthread_cond_init failed: %s", strerror(r));
|
||||
return (Value *)c;
|
||||
}
|
||||
|
||||
@ -237,11 +230,8 @@ Value *System_Concurrency_Raw_prim__conditionWait(Value *_condition, Value *_mut
|
||||
{
|
||||
Value_Condition *cond = (Value_Condition *)_condition;
|
||||
Value_Mutex *mutex = (Value_Mutex *)_mutex;
|
||||
if (pthread_cond_wait(cond->cond, mutex->mutex))
|
||||
{
|
||||
fprintf(stderr, "Error Conditional Wait\n");
|
||||
exit(-1);
|
||||
}
|
||||
int r = pthread_cond_wait(cond->cond, mutex->mutex);
|
||||
IDRIS2_REFC_VERIFY(!r, "pthread_cond_wait failed: %s", strerror(r));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -256,11 +246,8 @@ Value *System_Concurrency_Raw_prim__conditionWaitTimeout(Value *_condition, Valu
|
||||
struct timespec t;
|
||||
t.tv_sec = timeout->i64 / 1000000;
|
||||
t.tv_nsec = timeout->i64 % 1000000;
|
||||
if (pthread_cond_timedwait(cond->cond, mutex->mutex, &t))
|
||||
{
|
||||
fprintf(stderr, "Error in pthread_cond_timedwait\n");
|
||||
exit(-1);
|
||||
}
|
||||
int r = pthread_cond_timedwait(cond->cond, mutex->mutex, &t);
|
||||
IDRIS2_REFC_VERIFY(!r, "pthread_cond_timedwait failed: %s", strerror(r));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -270,11 +257,8 @@ Value *System_Concurrency_Raw_prim__conditionWaitTimeout(Value *_condition, Valu
|
||||
Value *System_Concurrency_Raw_prim__conditionSignal(Value *_condition, Value *_world)
|
||||
{
|
||||
Value_Condition *cond = (Value_Condition *)_condition;
|
||||
if (pthread_cond_signal(cond->cond))
|
||||
{
|
||||
fprintf(stderr, "Error in pthread_cond_signal\n");
|
||||
exit(-1);
|
||||
}
|
||||
int r = pthread_cond_signal(cond->cond);
|
||||
IDRIS2_REFC_VERIFY(!r, "pthread_cond_signal failed: %s", strerror(r));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -284,10 +268,7 @@ Value *System_Concurrency_Raw_prim__conditionSignal(Value *_condition, Value *_w
|
||||
Value *System_Concurrency_Raw_prim__conditionBroadcast(Value *_condition, Value *_mutex)
|
||||
{
|
||||
Value_Condition *cond = (Value_Condition *)_condition;
|
||||
if (pthread_cond_broadcast(cond->cond))
|
||||
{
|
||||
fprintf(stderr, "Error in pthread_cond_broadcast\n");
|
||||
exit(-1);
|
||||
}
|
||||
int r = pthread_cond_broadcast(cond->cond);
|
||||
IDRIS2_REFC_VERIFY(!r, "pthread_cond_broadcast failed: %s", strerror(r));
|
||||
return NULL;
|
||||
}
|
||||
|
16
support/refc/refc_util.c
Normal file
16
support/refc/refc_util.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include "refc_util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
void idris2_refc_verify_failed(const char* file, int line, const char* cond, const char* fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
char message[1000];
|
||||
snprintf(message, sizeof(message), fmt, ap);
|
||||
|
||||
fprintf(stderr, "assertion failed in %s:%d: %s: %s\n", file, line, cond, message);
|
||||
abort();
|
||||
}
|
20
support/refc/refc_util.h
Normal file
20
support/refc/refc_util.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdnoreturn.h>
|
||||
|
||||
// Utilities used by RefC code.
|
||||
|
||||
// Crash is the condition is false.
|
||||
#define IDRIS2_REFC_VERIFY(cond, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
idris2_refc_verify_failed(__FILE__, __LINE__, #cond, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Used by `IDRIS2_REFC_VERIFY`, do not use directly.
|
||||
noreturn void idris2_refc_verify_failed(const char* file, int line, const char* cond, const char* fmt, ...)
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
__attribute__ ((format(printf, 4, 5)))
|
||||
#endif
|
||||
;
|
@ -1,4 +1,5 @@
|
||||
#include "runtime.h"
|
||||
#include "refc_util.h"
|
||||
|
||||
void missing_ffi()
|
||||
{
|
||||
@ -12,11 +13,7 @@ void missing_ffi()
|
||||
|
||||
void push_Arglist(Value_Arglist *arglist, Value *arg)
|
||||
{
|
||||
if (arglist->filled >= arglist->total)
|
||||
{
|
||||
fprintf(stderr, "unable to add more arguments to arglist\n");
|
||||
exit(1);
|
||||
}
|
||||
IDRIS2_REFC_VERIFY(arglist->filled < arglist->total, "unable to add more arguments to arglist");
|
||||
|
||||
arglist->args[arglist->filled] = newReference(arg);
|
||||
arglist->filled++;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "stringOps.h"
|
||||
#include "refc_util.h"
|
||||
|
||||
Value *stringLength(Value *s)
|
||||
{
|
||||
@ -23,6 +24,7 @@ Value *tail(Value *input)
|
||||
if(l != 0)
|
||||
{
|
||||
tailStr->str = malloc(l);
|
||||
IDRIS2_REFC_VERIFY(tailStr->str, "malloc failed");
|
||||
memset(tailStr->str, 0, l);
|
||||
memcpy(tailStr->str, s->str + 1, l - 1);
|
||||
return (Value *)tailStr;
|
||||
@ -30,6 +32,7 @@ Value *tail(Value *input)
|
||||
else
|
||||
{
|
||||
tailStr->str = malloc(1);
|
||||
IDRIS2_REFC_VERIFY(tailStr->str, "malloc failed");
|
||||
tailStr->str[0] = '\0';
|
||||
return (Value *)tailStr;
|
||||
}
|
||||
@ -42,6 +45,7 @@ Value *reverse(Value *str)
|
||||
Value_String *input = (Value_String *)str;
|
||||
int l = strlen(input->str);
|
||||
retVal->str = malloc(l + 1);
|
||||
IDRIS2_REFC_VERIFY(retVal->str, "malloc failed");
|
||||
memset(retVal->str, 0, l + 1);
|
||||
char *p = retVal->str;
|
||||
char *q = input->str + (l - 1);
|
||||
@ -190,6 +194,7 @@ Value *stringIteratorNew(char *str)
|
||||
int l = strlen(str);
|
||||
|
||||
String_Iterator *it = (String_Iterator *)malloc(sizeof(String_Iterator));
|
||||
IDRIS2_REFC_VERIFY(it, "malloc failed");
|
||||
it->str = (char *)malloc(l + 1);
|
||||
it->pos = 0;
|
||||
memcpy(it->str, str, l + 1); // Take a copy of str, in case it gets GCed
|
||||
|
Loading…
Reference in New Issue
Block a user