Changeset 1a3b953 in mainline


Ignore:
Timestamp:
2012-08-20T00:22:19Z (12 years ago)
Author:
Sean Bartell <wingedtachikoma@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0784869
Parents:
5e514c0
Message:

Bithenge: better error injection

Location:
uspace
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • uspace/dist/src/bithenge/test.sh

    r5e514c0 r1a3b953  
    77if type valgrind >/dev/null 2>&1
    88then
    9         BITHENGE="valgrind -q --show-reachable=yes ${BITHENGE}"
     9        BITHENGE="valgrind -q --show-reachable=yes --error-exitcode=64 ${BITHENGE}"
    1010else
    1111        echo "Valgrind not found."
  • uspace/lib/bithenge/blob.c

    r5e514c0 r1a3b953  
    5858        assert(ops->size);
    5959
     60        if (bithenge_should_fail())
     61                return ENOMEM;
     62
    6063        blob->base.type = BITHENGE_NODE_BLOB;
    6164        blob->base.refs = 1;
     
    195198{
    196199        memory_blob_t *blob = blob_as_memory(base);
     200        if (bithenge_should_fail())
     201                return EIO;
    197202        *size = blob->size;
    198203        return EOK;
     
    223228        .destroy = memory_destroy,
    224229};
    225 
    226 /** Create a blob node from data. Unlike with @a
    227  * bithenge_blob_t::bithenge_new_blob_from_buffer, the data is copied into a
    228  * new buffer and the original data can be changed after this call. The blob
    229  * must be freed with @a bithenge_node_t::bithenge_node_destroy after it is
    230  * used.
    231  * @memberof bithenge_blob_t
    232  * @param[out] out Stores the created blob node.
    233  * @param[in] data The data.
    234  * @param len The length of the data.
    235  * @return EOK on success or an error code from errno.h. */
    236 int bithenge_new_blob_from_data(bithenge_node_t **out, const void *data,
    237     size_t len)
    238 {
    239         int rc;
    240         assert(data || !len);
    241 
    242         memory_blob_t *blob = malloc(sizeof(*blob));
    243         if (!blob)
    244                 return ENOMEM;
    245         rc = bithenge_init_random_access_blob(memory_as_blob(blob),
    246             &memory_ops);
    247         if (rc != EOK) {
    248                 free(blob);
    249                 return rc;
    250         }
    251         char *buffer = malloc(len);
    252         if (!buffer) {
    253                 free(blob);
    254                 return rc;
    255         }
    256         memcpy(buffer, data, len);
    257         blob->buffer = buffer;
    258         blob->size = len;
    259         blob->needs_free = true;
    260         *out = bithenge_blob_as_node(memory_as_blob(blob));
    261         return EOK;
    262 }
    263230
    264231/** Create a blob node from a buffer. The buffer must exist as long as the blob
     
    280247
    281248        memory_blob_t *blob = malloc(sizeof(*blob));
    282         if (!blob)
    283                 return ENOMEM;
     249        if (!blob) {
     250                rc = ENOMEM;
     251                goto error;
     252        }
    284253        rc = bithenge_init_random_access_blob(memory_as_blob(blob),
    285254            &memory_ops);
    286         if (rc != EOK) {
    287                 free(blob);
    288                 return rc;
    289         }
     255        if (rc != EOK)
     256                goto error;
    290257        blob->buffer = buffer;
    291258        blob->size = len;
     
    293260        *out = bithenge_blob_as_node(memory_as_blob(blob));
    294261        return EOK;
    295 }
     262       
     263error:
     264        if (needs_free)
     265                free((void *)buffer);
     266        free(blob);
     267        return rc;
     268}
     269
     270/** Create a blob node from data. Unlike with @a
     271 * bithenge_blob_t::bithenge_new_blob_from_buffer, the data is copied into a
     272 * new buffer and the original data can be changed after this call. The blob
     273 * must be freed with @a bithenge_node_t::bithenge_node_destroy after it is
     274 * used.
     275 * @memberof bithenge_blob_t
     276 * @param[out] out Stores the created blob node.
     277 * @param[in] data The data.
     278 * @param len The length of the data.
     279 * @return EOK on success or an error code from errno.h. */
     280int bithenge_new_blob_from_data(bithenge_node_t **out, const void *data,
     281    size_t len)
     282{
     283        char *buffer = malloc(len);
     284        if (!buffer)
     285                return ENOMEM;
     286        memcpy(buffer, data, len);
     287
     288        return bithenge_new_blob_from_buffer(out, buffer, len, true);
     289}
     290
     291
    296292
    297293typedef struct {
  • uspace/lib/bithenge/compound.c

    r5e514c0 r1a3b953  
    3838#include "compound.h"
    3939#include "expression.h"
     40#include "os.h"
    4041#include "transform.h"
    4142#include "tree.h"
  • uspace/lib/bithenge/expression.c

    r5e514c0 r1a3b953  
    4040#include "blob.h"
    4141#include "expression.h"
     42#include "os.h"
    4243#include "transform.h"
    4344#include "tree.h"
     
    5354        assert(ops->evaluate);
    5455        assert(ops->destroy);
     56        if (bithenge_should_fail())
     57                return ENOMEM;
    5558        self->ops = ops;
    5659        self->refs = 1;
     
    304307int bithenge_in_node_expression(bithenge_expression_t **out)
    305308{
     309        if (bithenge_should_fail())
     310                return ENOMEM;
    306311        bithenge_expression_inc_ref(&in_node_expression);
    307312        *out = &in_node_expression;
  • uspace/lib/bithenge/failure.c

    r5e514c0 r1a3b953  
    3636
    3737#include <errno.h>
     38#include <execinfo.h>
    3839#include <fcntl.h>
    3940#include <stdio.h>
     
    4546#define BITHENGE_FAILURE_DECLS_ONLY 1
    4647#include "failure.h"
     48#include "os.h"
    4749
    4850/* This file raises fake errors from system calls, to test that Bithenge
     
    5456 * correctly (exit code is 1), the main process continues without errors. If
    5557 * the child process has a problem, the main process raises the fake error
    56  * again and shows all stdout and stderr output. For speed, failures only occur
    57  * for some system calls after the first 128.
     58 * again and shows all stdout and stderr output. For speed, errors are only
     59 * raised when part of the backtrace has not been seen before.
    5860 *
    5961 * BITHENGE_FAILURE_INDEX set: the program runs normally until system call
     
    6163 * call. */
    6264
     65static int g_initialized = 0;
    6366static int g_failure_index = -1;
    64 static int g_failure_index_selected = -2;
    65 
    66 static int should_fail(void)
     67static int g_failure_index_selected = -1;
     68
     69typedef struct backtrace_item {
     70        struct backtrace_item *next;
     71        void *backtrace_item;
     72} backtrace_item_t;
     73
     74static backtrace_item_t *g_backtrace_items = NULL;
     75
     76static void atexit_handler(void)
     77{
     78        while (g_backtrace_items) {
     79                backtrace_item_t *first = g_backtrace_items;
     80                g_backtrace_items = first->next;
     81                free(first);
     82        }
     83}
     84
     85static inline void initialize(void)
     86{
     87        g_initialized = 1;
     88        int rc = atexit(atexit_handler);
     89        if (rc)
     90                exit(127);
     91
     92        char *sel_str = getenv("BITHENGE_FAILURE_INDEX");
     93        if (sel_str)
     94                g_failure_index_selected = strtol(sel_str, NULL, 10);
     95}
     96
     97/* Record a hit for a backtrace address and return whether this is the first
     98 * hit. */
     99static inline int backtrace_item_hit(void *addr)
     100{
     101        backtrace_item_t **bip;
     102        for (bip = &g_backtrace_items; *bip; bip = &(*bip)->next) {
     103                backtrace_item_t *bi = *bip;
     104                if (bi->backtrace_item == addr) {
     105                        /* Keep frequently accessed items near the front. */
     106                        *bip = bi->next;
     107                        bi->next = g_backtrace_items;
     108                        g_backtrace_items = bi;
     109                        return 0;
     110                }
     111        }
     112
     113        /* No item found; create one. */
     114        backtrace_item_t *i = malloc(sizeof(*i));
     115        if (!i)
     116                exit(127);
     117        i->next = g_backtrace_items;
     118        i->backtrace_item = addr;
     119        g_backtrace_items = i;
     120        return 1;
     121}
     122
     123int bithenge_should_fail(void)
    67124{
    68125        g_failure_index++;
    69126
    70         if (g_failure_index_selected == -2) {
    71                 char *sel_str = getenv("BITHENGE_FAILURE_INDEX");
    72                 if (sel_str) {
    73                         g_failure_index_selected = strtol(sel_str, NULL, 10);
    74                 } else {
    75                         g_failure_index_selected = -1;
    76                 }
    77         } else if (g_failure_index_selected != -1) {
     127        if (!g_initialized)
     128                initialize();
     129
     130        if (g_failure_index_selected != -1) {
    78131                if (g_failure_index == g_failure_index_selected)
    79132                        return 1; /* breakpoint here */
     
    81134        }
    82135
    83         /* Only fail half the time after 128 failures, 1/4 the time after 256
    84          * failures, 1/8 the time after 512 failures... */
    85         int index = g_failure_index;
    86         while (index >= 128) {
    87                 int test = (index & (64 | 1));
    88                 if (test == (64 | 1) || test == 0)
    89                         return 0;
    90                 index >>= 1;
    91         }
     136        /* If all backtrace items have been seen already, there's no need to
     137         * try raising an error. */
     138        void *trace[256];
     139        int size = backtrace(trace, 256);
     140        int raise_error = 0;
     141        for (int i = 0; i < size; i++) {
     142                if (backtrace_item_hit(trace[i]))
     143                        raise_error = 1;
     144        }
     145        if (!raise_error)
     146                return 0;
    92147
    93148        if (!fork()) {
    94                 /* Child */
     149                /* Child silently fails. */
    95150                int null = open("/dev/null", O_WRONLY);
    96151                if (null == -1)
     
    102157        }
    103158
    104         /* Parent */
     159        /* Parent checks whether child failed correctly. */
    105160        int status;
    106161        wait(&status);
     
    108163                return 0;
    109164
    110         /* The child had an error! We couldn't see it because stdout and stderr
    111          * were redirected, and we couldn't debug it easily because it was a
    112          * separate process. Do it again without redirecting or forking. */
     165        /* The child had an error! We couldn't easily debug it because it was
     166         * in a separate process with redirected stdout and stderr. Do it again
     167         * without redirecting or forking. */
    113168        fprintf(stderr, "** Fake error raised here (BITHENGE_FAILURE_INDEX=%d)\n",
    114169            g_failure_index);
     
    118173void *bithenge_failure_malloc(size_t size)
    119174{
    120         if (should_fail())
     175        if (bithenge_should_fail())
    121176                return NULL;
    122177        return malloc(size);
     
    125180void *bithenge_failure_realloc(void *ptr, size_t size)
    126181{
    127         if (should_fail())
     182        if (bithenge_should_fail())
    128183                return NULL;
    129184        return realloc(ptr, size);
     
    132187ssize_t bithenge_failure_read(int fd, void *buf, size_t count)
    133188{
    134         if (should_fail()) {
     189        if (bithenge_should_fail()) {
    135190                errno = EIO;
    136191                return -1;
     
    141196off_t bithenge_failure_lseek(int fd, off_t offset, int whither)
    142197{
    143         if (should_fail()) {
     198        if (bithenge_should_fail()) {
    144199                errno = EINVAL;
    145200                return (off_t) -1;
     
    148203}
    149204
     205int bithenge_failure_ferror(FILE *stream)
     206{
     207        if (bithenge_should_fail())
     208                return 1;
     209        return ferror(stream);
     210}
     211
     212char *bithenge_failure_str_ndup(const char *s, size_t max_len)
     213{
     214        if (bithenge_should_fail())
     215                return NULL;
     216        return str_ndup(s, max_len);
     217}
     218
     219int bithenge_failure_open(const char *pathname, int flags)
     220{
     221        if (bithenge_should_fail()) {
     222                errno = EACCES;
     223                return -1;
     224        }
     225        return open(pathname, flags);
     226}
     227
     228int bithenge_failure_fstat(int fd, struct stat *buf)
     229{
     230        if (bithenge_should_fail()) {
     231                errno = EIO;
     232                return -1;
     233        }
     234        return fstat(fd, buf);
     235}
     236
    150237/** @}
    151238 */
  • uspace/lib/bithenge/failure.h

    r5e514c0 r1a3b953  
    3838#define BITHENGE_FAILURE_H_
    3939
     40#include <fcntl.h>
     41#include <stdio.h>
    4042#include <stdlib.h>
     43#include <sys/stat.h>
    4144#include <sys/types.h>
    4245#include <unistd.h>
     46#include "os.h"
    4347
     48int bithenge_should_fail(void);
    4449void *bithenge_failure_malloc(size_t);
    4550void *bithenge_failure_realloc(void *, size_t);
    4651ssize_t bithenge_failure_read(int, void *, size_t);
    4752off_t bithenge_failure_lseek(int, off_t, int);
     53int bithenge_failure_ferror(FILE *);
     54char *bithenge_failure_str_ndup(const char *, size_t);
     55int bithenge_failure_open(const char *, int);
     56int bithenge_failure_fstat(int, struct stat *);
    4857
    4958#ifndef BITHENGE_FAILURE_DECLS_ONLY
     
    5261#define read bithenge_failure_read
    5362#define lseek bithenge_failure_lseek
     63#define ferror bithenge_failure_ferror
     64#define str_ndup bithenge_failure_str_ndup
     65#define open bithenge_failure_open
     66#define fstat bithenge_failure_fstat
    5467#endif
    5568
  • uspace/lib/bithenge/file.c

    r5e514c0 r1a3b953  
    7979                return ELIMIT;
    8080        if (lseek(blob->fd, offset, SEEK_SET) < 0)
    81                 return errno == EINVAL ? EIO : EINVAL;
     81                return errno == EINVAL ? EIO : errno;
    8282
    8383        ssize_t amount_read;
  • uspace/lib/bithenge/os.h

    r5e514c0 r1a3b953  
    3535#ifdef BITHENGE_FAILURE_ENABLE
    3636#include "failure.h"
     37#else
     38static inline int bithenge_should_fail(void)
     39{
     40        return 0;
     41}
    3742#endif
  • uspace/lib/bithenge/transform.c

    r5e514c0 r1a3b953  
    4040#include <stdlib.h>
    4141#include "blob.h"
     42#include "os.h"
    4243#include "print.h"
    4344#include "transform.h"
     
    6263        assert(ops->apply || ops->prefix_apply);
    6364        assert(ops->destroy);
     65        if (bithenge_should_fail())
     66                return ENOMEM;
    6467        self->ops = ops;
    6568        self->refs = 1;
     
    371374        assert(scope);
    372375        assert(i >= 0 && i < scope->num_params);
     376        if (bithenge_should_fail()) {
     377                bithenge_node_dec_ref(node);
     378                return ENOMEM;
     379        }
    373380        scope->params[i] = node;
    374381        return EOK;
     
    487494        assert(transform);
    488495        assert(bithenge_transform_num_params(transform) == 0);
     496
     497        if (bithenge_should_fail()) {
     498                bithenge_transform_dec_ref(transform);
     499                return ENOMEM;
     500        }
    489501
    490502        barrier_transform_t *self = transform_as_barrier(base);
  • uspace/lib/bithenge/tree.c

    r5e514c0 r1a3b953  
    198198int bithenge_new_empty_internal_node(bithenge_node_t **out)
    199199{
     200        if (bithenge_should_fail())
     201                return ENOMEM;
    200202        bithenge_node_inc_ref(&empty_internal_node);
    201203        *out = &empty_internal_node;
     
    301303{
    302304        assert(out);
     305        if (bithenge_should_fail())
     306                return ENOMEM;
    303307        *out = value ? &true_node : &false_node;
    304308        (*out)->refs++;
Note: See TracChangeset for help on using the changeset viewer.