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:
Stiopa Koltsov 2021-07-17 03:59:32 +01:00
parent 0fec867583
commit 41c20ddf6a
8 changed files with 119 additions and 97 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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
View 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
View 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
;

View File

@ -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++;

View File

@ -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