Add short writes to pwritev in faulty_libc.

This commit is contained in:
FHaggs
2025-10-03 18:35:03 +02:00
parent 095e72eac9
commit dd6e092a5c

View File

@@ -7,6 +7,8 @@
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdint.h>
static double probabilities[] = {
[ENOSPC] = 0.01,
@@ -64,6 +66,72 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
if (libc_pwritev == NULL) {
libc_pwritev = dlsym(RTLD_NEXT, "pwritev");
}
/* If no vectors or invalid count, forward directly. */
if (iov == NULL || iovcnt <= 0) {
return libc_pwritev(fd, iov, iovcnt, offset);
}
if (iovcnt > 0 && chance(short_write_probability)) {
struct iovec iov_copy[iovcnt];
memcpy(iov_copy, iov, sizeof(struct iovec) * iovcnt);
/* Compute total bytes requested (guarding against overflow). */
size_t total = 0;
for (int i = 0; i < iovcnt; ++i) {
size_t len = iov_copy[i].iov_len;
if (len > 0 && total > SIZE_MAX - len) {
total = SIZE_MAX;
break;
}
total += len;
}
/* Only meaningful to short-write if total > 1. */
if (total > 1) {
/* Choose cutoff in [1, total-1] */
size_t cutoff = 1 + (size_t)(lrand48() % (total - 1));
size_t remaining = cutoff;
/* Walk iov_copy and reduce lengths to exactly match cutoff.
* After the cutoff is satisfied, following iov entries will be set to 0 length.
*/
for (int i = 0; i < iovcnt; ++i) {
size_t len = iov_copy[i].iov_len;
if (len == 0) {
/* keep zero-length entries as zero, they do not consume remaining */
continue;
}
if (remaining == 0) {
/* drop the rest */
iov_copy[i].iov_len = 0;
continue;
}
if (len <= remaining) {
/* fully include this iovec */
remaining -= len;
/* keep iov_copy[i].iov_len as-is */
} else {
/* partial include: shorten this iovec to remaining */
iov_copy[i].iov_len = remaining;
remaining = 0;
}
}
/* Compute new iovcnt to avoid passing trailing zero-length iovecs */
int new_iovcnt = iovcnt;
while (new_iovcnt > 0 && iov_copy[new_iovcnt - 1].iov_len == 0) {
new_iovcnt--;
}
/* Defensive: cutoff >= 1 so new_iovcnt should be > 0; This should always be true*/
if (new_iovcnt > 0) {
printf("%s: injecting fault SHORT WRITE cutoff=%zu of %zu (new_iovcnt=%d)\n",
__func__, cutoff, total, new_iovcnt);
return libc_pwritev(fd, iov_copy, new_iovcnt, offset);
}
}
}
if (inject_fault(ENOSPC)) {
printf("%s: injecting fault NOSPC\n", __func__);
return -1;