Skip to content

Commit

Permalink
Get old test scripts to work, and assorted cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-byers committed Aug 18, 2024
1 parent ac649f0 commit d0a922b
Show file tree
Hide file tree
Showing 68 changed files with 1,469 additions and 1,923 deletions.
3 changes: 0 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,8 @@ target_sources(paw
${PAW_SOURCE_DIR}/os.h
${PAW_SOURCE_DIR}/parse.h
${PAW_SOURCE_DIR}/prefix.h
${PAW_SOURCE_DIR}/resolve.h
${PAW_SOURCE_DIR}/rt.h
${PAW_SOURCE_DIR}/str.h
${PAW_SOURCE_DIR}/type.h
${PAW_SOURCE_DIR}/unify.h
${PAW_SOURCE_DIR}/util.h
${PAW_SOURCE_DIR}/value.h
Expand Down Expand Up @@ -85,7 +83,6 @@ target_sources(paw
${PAW_SOURCE_DIR}/resolve.c
${PAW_SOURCE_DIR}/rt.c
${PAW_SOURCE_DIR}/str.c
${PAW_SOURCE_DIR}/type.c
${PAW_SOURCE_DIR}/unify.c
${PAW_SOURCE_DIR}/util.c
${PAW_SOURCE_DIR}/value.c
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Modules that are intended to run as scripts under the bundled Paw interpreter `p
When `main` is finished, its return value is passed back to the process that invoked `paw`.

### Types
Paw is statically-typed, meaning all types must be known (and are fixed at) at compile-time.
Paw is statically-typed, meaning all types must be known at compile-time.
Also note that Paw is strongly typed, meaning implicit conversions are not allowed.

The following example demonstrates creation of the basic value types.
Expand Down Expand Up @@ -215,7 +215,7 @@ fn map<A, B>(f: fn(A) -> B, vec: [A]) -> [B] {
}
// infer A = float, B = int
let vec = map(|a| a as int, [0.5, 1.5, 2.5])
let vec = map(|f: float| f as int, [0.5, 1.5, 2.5])
assert(vec == [0, 1, 2])
// struct template
Expand Down
3 changes: 0 additions & 3 deletions fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ option(PAW_FuzzerUseMain "Compile with standalone main to reproduce runs" Off)
add_executable(paw_fuzz fuzz.c)
target_link_libraries(paw_fuzz PRIVATE paw)

add_executable(paw_fuzz_expr fuzz_expr.c)
target_link_libraries(paw_fuzz_expr PRIVATE paw)

if(PAW_FuzzerUseMain)
target_sources(paw_fuzz PRIVATE standalone.c)
endif()
101 changes: 5 additions & 96 deletions fuzz/fuzz.c
Original file line number Diff line number Diff line change
@@ -1,106 +1,15 @@
// Copyright (c) 2024, The paw Authors. All rights reserved.
// This source code is licensed under the MIT License, which can be found in
// LICENSE.md. See AUTHORS.md for a list of contributor names.
#include "paw.h"

#include "fuzz.h"
#include "lib.h"
#include "util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FUZZ_UNUSED(x) ((void)x)
#define FUZZ_CHECK(cond, ...) do { \
if (!(cond)) { \
FUZZ_ERROR(__VA_ARGS__); \
} \
} while (0)
#define FUZZ_ERROR(...) do { \
fprintf(stderr, __VA_ARGS__); \
abort(); \
} while (0)

struct FuzzAlloc {
size_t nbytes;
};

#define MEM_LIMIT (1024 * 1024 * 4)

static void *fuzz_alloc(void *ud, void *ptr, size_t size0, size_t size)
{
struct FuzzAlloc *a = ud;
FUZZ_CHECK(size0 <= a->nbytes,
"invalid 'size0' %zu for 'realloc' "
"(%zu bytes allocated total)",
size0, a->nbytes);
if (size > MEM_LIMIT || // '-' would wrap
a->nbytes - size0 > MEM_LIMIT - size) {
return NULL; // used too much memory
}
a->nbytes += size - size0;
return realloc(ptr, size);
}

struct FuzzReader {
const uint8_t *data;
size_t size;
};

static const char *fuzz_reader(paw_Env *P, void *ud, size_t *size)
{
FUZZ_UNUSED(P);
struct FuzzReader *fr = ud;
// read some amount of source text, dependent on the value of the first byte
const size_t value = fr->size > 0 ? fr->data[0] : 0;
const size_t nread = value > fr->size ? fr->size : value;
fr->size -= nread;
*size = nread;
return (char *)fr->data;
}

// Prevent fuzzer inputs from gaining access to outside resources. At
// present, the only way this would be possible is by importing a library,
// like 'io', so just reject all inputs containing the string "import".
static paw_Bool is_unsafe(const uint8_t *data, size_t size)
{
const char *haystack = (const char *)data;
const char needle[] = "import";
const size_t n = sizeof(needle) - 1;
while (size >= n) {
if (0 == memcmp(haystack, needle, n)) {
return PAW_TRUE;
}
++haystack;
--size;
}
return PAW_FALSE;
}

extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
// reject inputs that might be unsafe to run
if (is_unsafe(data, size)) return -1;
struct FuzzAlloc fa = {0};
struct FuzzReader fr = {
.data = data,
.size = size,
};
// open a new environment and load the input
paw_Env *P = paw_open(fuzz_alloc, &fa);
int status = pawL_load_nchunk(P, "fuzz", (const char *)data, size);
if (status != PAW_OK) {
paw_close(P);
return 0;
}
// search for a public function named 'f'
paw_push_string(P, "f");
const int pid = paw_find_public(P);
if (pid < 0) return 0;
paw_push_public(P, pid);

// call 'f()'
paw_call(P, 0);
paw_close(P);

FUZZ_CHECK(fa.nbytes == 0, "leaked memory");
struct FuzzState fs = fuzz_open(PAW_HEAP_MIN);
pawL_load_nchunk(fs.P, "fuzz", (const char *)data, size);
fuzz_close(fs);
return 0;
}
50 changes: 34 additions & 16 deletions fuzz/fuzz.dict
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
"// line comment"
"/* block comment */"
"fn f() {}"
"fn f() {}"
"fn f() {}"
"fn f() {}"
"fn f() {return 123}"
"let f = fn() {}"
"struct Unit"
"struct Singleton {value: int}"
"struct Pair {first: float, second: str}"
"struct Unit<T>"
"struct Singleton<T> {value: int}"
"struct Pair<First, Second> {first: First, second: Second}"
"let a = [123, 1.0, true, null, 'str', fn() {}]"
"let m = {'a': 123, 1: true, 2.0: 'str', true: null}"
"pub"
"fn"
"type"
"enum"
"struct"
"let"
"if"
"else"
"for"
"do"
"while"
"break"
"continue"
"return"
"in"
"as"
"true"
"false"

"struct S {"
"enum E {"
"fn f() {"
"let v = 1"
"while b {"
"do {"
"for i = 0, 8, 2 {"
"for x in y {"
"if b {"
"} else if b {"
"} else {"
"} while b"
"}"
"}}"
"}}}"
67 changes: 67 additions & 0 deletions fuzz/fuzz.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) 2024, The paw Authors. All rights reserved.
// This source code is licensed under the MIT License, which can be found in
// LICENSE.md. See AUTHORS.md for a list of contributor names.

#ifndef PAW_FUZZ_H
#define PAW_FUZZ_H

#include "paw.h"
#include <stdio.h>
#include <stdlib.h>

#define FUZZ_UNUSED(x) ((void)x)
#define FUZZ_CHECK(cond, ...) do { \
if (!(cond)) { \
FUZZ_ERROR(__VA_ARGS__); \
} \
} while (0)
#define FUZZ_ERROR(...) do { \
fprintf(stderr, __VA_ARGS__); \
abort(); \
} while (0)

struct FuzzState {
size_t heap_size;
void *heap;
paw_Env *P;
};

static inline struct FuzzState fuzz_open(size_t heap_size)
{
struct paw_Options o = {.heap_size = heap_size};
o.heap = malloc(o.heap_size);
FUZZ_CHECK(o.heap != NULL, "malloc() failed");

paw_Env *P = paw_open(&o);
FUZZ_CHECK(P != NULL, "paw_open() failed\n");
return (struct FuzzState){
.heap_size = heap_size,
.heap = o.heap,
.P = P,
};
}

static inline void fuzz_close(struct FuzzState fs)
{
paw_close(fs.P);
free(fs.heap);
}

struct FuzzReader {
const char *data;
size_t size;
};

static const char *fuzz_reader(paw_Env *P, void *ud, size_t *size)
{
FUZZ_UNUSED(P);
struct FuzzReader *fr = ud;
// read some amount of source text, dependent on the value of the first byte
const size_t value = fr->size > 0 ? fr->data[0] : 0;
const size_t nread = value > fr->size ? fr->size : value;
fr->size -= nread;
*size = nread;
return (char *)fr->data;
}

#endif // PAW_FUZZ_H
101 changes: 0 additions & 101 deletions fuzz/fuzz_expr.c

This file was deleted.

Loading

0 comments on commit d0a922b

Please sign in to comment.