File size: 4,757 Bytes
4f0bd4e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | /*
* block_device.c — Simple block device with seek/read/write
*
* A small self-contained example for GRACE evaluation (Phase 4).
*
* Intentional bug:
* blk_seek() computes the new position as:
* dev->position = dev->position + offset
* When `dev->position` is close to SIZE_MAX and `offset` is large,
* this addition can overflow a size_t, wrapping around to a small value
* and bypassing the bounds check.
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/* ------------------------------------------------------------------ */
/* Data structures */
/* ------------------------------------------------------------------ */
#define BLK_BLOCK_SIZE 512
typedef struct {
uint8_t *data; /* backing storage */
size_t capacity; /* total device size in bytes */
size_t position; /* current seek position */
int is_open; /* 1 if open, 0 if closed */
uint32_t error_flags;/* accumulated error flags */
} blk_dev_t;
/* Error codes */
#define BLK_OK 0
#define BLK_ERR_CLOSED -1
#define BLK_ERR_BOUNDS -2
#define BLK_ERR_NULL -3
/* ------------------------------------------------------------------ */
/* Lifecycle */
/* ------------------------------------------------------------------ */
/*
* blk_init — initialise a block device with a backing buffer.
*
* Precondition: dev != NULL, data != NULL, size > 0
* Postcondition: dev->is_open == 1, dev->position == 0
*/
int blk_init(blk_dev_t *dev, uint8_t *data, size_t size)
{
if (dev == NULL || data == NULL)
return BLK_ERR_NULL;
dev->data = data;
dev->capacity = size;
dev->position = 0;
dev->is_open = 1;
dev->error_flags = 0;
return BLK_OK;
}
/*
* blk_close — close the block device.
*
* Precondition: dev != NULL, dev->is_open == 1
* Postcondition: dev->is_open == 0
*/
int blk_close(blk_dev_t *dev)
{
if (dev == NULL)
return BLK_ERR_NULL;
if (!dev->is_open)
return BLK_ERR_CLOSED;
dev->is_open = 0;
return BLK_OK;
}
/* ------------------------------------------------------------------ */
/* I/O operations */
/* ------------------------------------------------------------------ */
/*
* blk_read — read `len` bytes from the device at the current position.
*
* Precondition: dev != NULL, buf != NULL, dev->is_open == 1,
* dev->position + len <= dev->capacity
* Postcondition: buf[0..len-1] filled with device data,
* dev->position advanced by len
*/
int blk_read(blk_dev_t *dev, uint8_t *buf, size_t len)
{
if (dev == NULL || buf == NULL)
return BLK_ERR_NULL;
if (!dev->is_open)
return BLK_ERR_CLOSED;
if (dev->position + len > dev->capacity)
return BLK_ERR_BOUNDS;
memcpy(buf, dev->data + dev->position, len);
dev->position += len;
return BLK_OK;
}
/*
* blk_write — write `len` bytes to the device at the current position.
*
* Precondition: dev != NULL, data != NULL, dev->is_open == 1,
* dev->position + len <= dev->capacity
* Postcondition: device data updated, dev->position advanced by len
*/
int blk_write(blk_dev_t *dev, const uint8_t *data, size_t len)
{
if (dev == NULL || data == NULL)
return BLK_ERR_NULL;
if (!dev->is_open)
return BLK_ERR_CLOSED;
if (dev->position + len > dev->capacity)
return BLK_ERR_BOUNDS;
memcpy(dev->data + dev->position, data, len);
dev->position += len;
return BLK_OK;
}
/*
* blk_seek — seek to a position relative to the current position.
*
* Precondition: dev != NULL, dev->is_open == 1,
* 0 <= dev->position + offset <= dev->capacity
* Postcondition: dev->position == old(dev->position) + offset
*
* BUG: the addition `dev->position + offset` can overflow size_t when
* both values are large. The overflow wraps around to a small value,
* bypassing the `new_pos > dev->capacity` check and resulting in
* an out-of-bounds position that corrupts subsequent reads/writes.
*/
int blk_seek(blk_dev_t *dev, size_t offset)
{
if (dev == NULL)
return BLK_ERR_NULL;
if (!dev->is_open)
return BLK_ERR_CLOSED;
/* BUG: integer overflow when dev->position + offset wraps around */
size_t new_pos = dev->position + offset; /* <-- intentional overflow bug */
if (new_pos > dev->capacity)
return BLK_ERR_BOUNDS;
dev->position = new_pos;
return BLK_OK;
}
|