CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
537 lines
15 KiB
C
537 lines
15 KiB
C
/*
|
|
This file is part of GOTCHA. For copyright information see the COPYRIGHT
|
|
file in the top level directory, or at
|
|
https://github.com/LLNL/gotcha/blob/master/COPYRIGHT
|
|
This program is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU Lesser General Public License (as published by the Free
|
|
Software Foundation) version 2.1 dated February 1999. This program is
|
|
distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
without even the IMPLIED WARRANTY OF MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the terms and conditions of the GNU Lesser General Public License
|
|
for more details. You should have received a copy of the GNU Lesser General
|
|
Public License along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#define BUILDING_LIBC_WRAPPERS
|
|
|
|
#include "libc_wrappers.h"
|
|
|
|
#include <assert.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/types.h>
|
|
#include <syscall.h>
|
|
#include <unistd.h>
|
|
|
|
#include "gotcha_auxv.h"
|
|
|
|
typedef struct malloc_header_t {
|
|
size_t size;
|
|
} malloc_header_t;
|
|
|
|
typedef struct malloc_link_t {
|
|
malloc_header_t header;
|
|
struct malloc_link_t *next;
|
|
} malloc_link_t;
|
|
|
|
#define MIN_SIZE (sizeof(malloc_link_t) - sizeof(malloc_header_t))
|
|
#define MIN_BLOCK_SIZE (1024 * 32)
|
|
|
|
static malloc_link_t *free_list = NULL;
|
|
|
|
static void split_allocation(malloc_link_t *allocation, size_t new_size) {
|
|
size_t orig_size = allocation->header.size;
|
|
malloc_link_t *newalloc = NULL;
|
|
|
|
if (orig_size - new_size <= sizeof(malloc_link_t)) return;
|
|
|
|
allocation->header.size = new_size;
|
|
newalloc = (malloc_link_t *)(((unsigned char *)&allocation->next) + new_size);
|
|
newalloc->header.size = (orig_size - new_size) - sizeof(malloc_header_t);
|
|
newalloc->next = free_list;
|
|
free_list = newalloc;
|
|
}
|
|
|
|
void *gotcha_malloc(size_t size) {
|
|
malloc_link_t *cur = NULL, *prev = NULL, *newalloc = NULL;
|
|
malloc_link_t *best_fit = NULL, *best_fit_prev = NULL;
|
|
ssize_t best_fit_diff = SIZE_MAX, diff = 0, block_size = 0;
|
|
void *result = NULL;
|
|
|
|
if (size < MIN_SIZE) size = MIN_SIZE;
|
|
if (size % 8) size += 8 - (size % 8);
|
|
|
|
// Find the tightest fit allocation in the free list
|
|
for (prev = NULL, cur = free_list; cur; cur = cur->next) {
|
|
diff = cur->header.size - size;
|
|
if (diff >= 0 && (!best_fit || diff < best_fit_diff)) {
|
|
best_fit = cur;
|
|
best_fit_prev = prev;
|
|
best_fit_diff = diff;
|
|
if (!diff) break;
|
|
}
|
|
prev = cur;
|
|
}
|
|
|
|
// Removes the best fit from the free list, split if needed, and return
|
|
if (best_fit) {
|
|
if (best_fit_prev)
|
|
best_fit_prev->next = best_fit->next;
|
|
else
|
|
free_list = best_fit->next;
|
|
split_allocation(best_fit, size);
|
|
return (void *)&best_fit->next;
|
|
}
|
|
|
|
// Create a new allocation area
|
|
if (size + sizeof(malloc_header_t) > MIN_BLOCK_SIZE) {
|
|
block_size = size + sizeof(malloc_header_t);
|
|
diff = block_size % gotcha_getpagesize();
|
|
if (diff) block_size += gotcha_getpagesize() - diff;
|
|
} else {
|
|
block_size = MIN_BLOCK_SIZE;
|
|
}
|
|
|
|
result = gotcha_mmap(NULL, block_size, PROT_READ | PROT_WRITE,
|
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
if (result == MAP_FAILED) return NULL; // GCOVR_EXCL_LINE
|
|
newalloc = (malloc_link_t *)result;
|
|
newalloc->header.size = block_size - sizeof(malloc_header_t);
|
|
split_allocation(newalloc, size);
|
|
return (void *)&newalloc->next;
|
|
}
|
|
|
|
void *gotcha_realloc(void *buffer, size_t size) {
|
|
void *newbuffer = NULL;
|
|
malloc_link_t *alloc = NULL;
|
|
|
|
alloc = (malloc_link_t *)(((malloc_header_t *)buffer) - 1);
|
|
|
|
if (size <= alloc->header.size) return buffer;
|
|
|
|
newbuffer = gotcha_malloc(size);
|
|
if (!newbuffer) return NULL; // GCOVR_EXCL_LINE
|
|
gotcha_memcpy(newbuffer, buffer, alloc->header.size);
|
|
|
|
gotcha_free(buffer);
|
|
|
|
return newbuffer;
|
|
}
|
|
|
|
void gotcha_free(void *buffer) {
|
|
malloc_link_t *alloc = NULL;
|
|
alloc = (malloc_link_t *)(((malloc_header_t *)buffer) - 1);
|
|
|
|
alloc->next = free_list;
|
|
free_list = alloc;
|
|
}
|
|
|
|
void gotcha_memcpy(void *dest, void *src, size_t size) {
|
|
size_t i = 0;
|
|
for (i = 0; i < size; i++) {
|
|
((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
|
}
|
|
}
|
|
|
|
int gotcha_strncmp(const char *in_one, const char *in_two, int max_length) {
|
|
int i = 0;
|
|
for (; i < max_length; i++) {
|
|
if (in_one[i] == '\0') {
|
|
return (in_two[i] == '\0') ? 0 : 1;
|
|
}
|
|
if (in_one[i] != in_two[i]) {
|
|
return in_one[i] - in_two[i];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int gotcha_strcmp(const char *in_one, const char *in_two) {
|
|
int i = 0;
|
|
for (;; i++) {
|
|
if (in_one[i] == '\0') {
|
|
return (in_two[i] == '\0') ? 0 : 1;
|
|
}
|
|
if (in_one[i] != in_two[i]) {
|
|
return in_one[i] - in_two[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
char *gotcha_strstr(const char *searchIn, const char *searchFor) {
|
|
int i = 0, j = 0;
|
|
if (!searchFor[0]) return NULL; // GCOVR_EXCL_LINE
|
|
|
|
for (i = 0; searchIn[i]; i++) {
|
|
if (searchIn[i] != searchFor[0]) continue;
|
|
for (j = 1;; j++) {
|
|
if (!searchFor[j]) return (char *)(searchFor + i);
|
|
if (!searchIn[i + j]) return NULL;
|
|
if (searchFor[j] != searchIn[i + j]) break;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ssize_t gotcha_write(int fd, const void *buf, size_t count) {
|
|
return syscall(SYS_write, fd, buf, count);
|
|
}
|
|
|
|
size_t gotcha_strlen(const char *s) {
|
|
size_t i = 0;
|
|
for (i = 0; s[i]; i++)
|
|
;
|
|
return i;
|
|
}
|
|
|
|
size_t gotcha_strnlen(const char *s, size_t max_length) {
|
|
size_t i = 0;
|
|
for (i = 0; i < max_length && s[i]; i++)
|
|
;
|
|
return i;
|
|
}
|
|
|
|
static int ulong_to_hexstr(unsigned long num, char *str, int strlen,
|
|
int uppercase) {
|
|
int len = 0, i = 0;
|
|
unsigned long val = 0UL;
|
|
char base_char = uppercase ? 'A' : 'a';
|
|
|
|
if (num == 0) {
|
|
if (strlen < 2) return -1; // GCOVR_EXCL_LINE
|
|
str[0] = '0';
|
|
str[1] = '\0';
|
|
return 1;
|
|
}
|
|
|
|
for (len = 0, val = num; val; val = val / 16, len++)
|
|
;
|
|
if (len + 1 >= strlen) return -1; // GCOVR_EXCL_LINE
|
|
|
|
str[len] = '\0';
|
|
val = num;
|
|
for (i = 1; i <= len; i++) {
|
|
str[len - i] =
|
|
(val % 16 <= 9) ? ('0' + val % 16) : (base_char + (val % 16 - 10));
|
|
val = val / 16;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static int ulong_to_str(unsigned long num, char *str, int strlen) {
|
|
int len = 0, i = 0;
|
|
unsigned long val = 0UL;
|
|
|
|
if (num == 0) {
|
|
if (strlen < 2) return -1; // GCOVR_EXCL_LINE
|
|
str[0] = '0';
|
|
str[1] = '\0';
|
|
return 1;
|
|
}
|
|
|
|
for (len = 0, val = num; val; val = val / 10, len++)
|
|
;
|
|
if (len + 1 >= strlen) return -1; // GCOVR_EXCL_LINE
|
|
|
|
str[len] = '\0';
|
|
val = num;
|
|
for (i = 1; i <= len; i++) {
|
|
str[len - i] = '0' + val % 10;
|
|
val = val / 10;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static int slong_to_str(signed long num, char *str, int strlen) {
|
|
int result = 0;
|
|
if (num >= 0) return ulong_to_str((unsigned long)num, str, strlen);
|
|
|
|
result = ulong_to_str((unsigned long)(num * -1), str + 1, strlen - 1);
|
|
if (result == -1) return -1; // GCOVR_EXCL_LINE
|
|
str[0] = '-';
|
|
return result + 1;
|
|
}
|
|
// GCOVR_EXCL_START
|
|
void gotcha_assert_fail(const char *s, const char *file, unsigned int line,
|
|
const char *function) {
|
|
char linestr[64] = {'\0'};
|
|
int result = 0;
|
|
|
|
result = ulong_to_str(line, linestr, sizeof(linestr) - 1);
|
|
if (result == -1) linestr[0] = '\0';
|
|
|
|
gotcha_write(2, file, gotcha_strlen(file));
|
|
gotcha_write(2, ":", 1);
|
|
gotcha_write(2, linestr, gotcha_strlen(linestr));
|
|
gotcha_write(2, ": ", 2);
|
|
gotcha_write(2, function, gotcha_strlen(function));
|
|
gotcha_write(2, ": Assertion `", 13);
|
|
gotcha_write(2, s, gotcha_strlen(s));
|
|
gotcha_write(2, "' failed.\n", 10);
|
|
syscall(SYS_kill, gotcha_getpid(), SIGABRT);
|
|
}
|
|
// GCOVR_EXCL_STOP
|
|
|
|
extern char **__environ;
|
|
char *gotcha_getenv(const char *name) {
|
|
char **s = NULL;
|
|
int name_len = 0;
|
|
|
|
name_len = gotcha_strlen(name);
|
|
for (s = __environ; *s; s++) {
|
|
if (gotcha_strncmp(name, *s, name_len) != 0) continue;
|
|
if ((*s)[name_len] != '=') continue; // GCOVR_EXCL_LINE
|
|
return (*s) + name_len + 1;
|
|
}
|
|
return NULL; // GCOVR_EXCL_LINE
|
|
}
|
|
|
|
pid_t gotcha_getpid() { return syscall(SYS_getpid); }
|
|
|
|
pid_t gotcha_gettid() { return syscall(SYS_gettid); }
|
|
|
|
unsigned int gotcha_getpagesize() {
|
|
static unsigned int pagesz = 0;
|
|
if (pagesz) return pagesz;
|
|
|
|
pagesz = get_auxv_pagesize();
|
|
if (!pagesz) pagesz = 4096; // GCOVR_EXCL_LINE
|
|
return pagesz;
|
|
}
|
|
|
|
int gotcha_open(const char *pathname, int flags, ...) {
|
|
mode_t mode;
|
|
va_list args;
|
|
long result = 0;
|
|
|
|
va_start(args, flags);
|
|
if (flags & O_CREAT) {
|
|
mode = va_arg(args, mode_t); // GCOVR_EXCL_LINE
|
|
} else {
|
|
mode = 0;
|
|
}
|
|
va_end(args);
|
|
|
|
#if defined(SYS_open)
|
|
result = syscall(SYS_open, pathname, flags, mode);
|
|
#else
|
|
result = syscall(SYS_openat, AT_FDCWD, pathname, flags, mode);
|
|
#endif
|
|
|
|
if (result >= 0) return (int)result;
|
|
|
|
return -1; // GCOVR_EXCL_LINE
|
|
}
|
|
|
|
void *gotcha_mmap(void *addr, size_t length, int prot, int flags, int fd,
|
|
off_t offset) {
|
|
long result = 0;
|
|
|
|
result = syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
|
|
return (void *)result;
|
|
}
|
|
|
|
int gotcha_atoi(const char *nptr) {
|
|
int neg = 1, len, val = 0, mult = 1;
|
|
const char *cur = NULL;
|
|
|
|
while (*nptr == '-') {
|
|
neg = neg * -1;
|
|
nptr++;
|
|
}
|
|
|
|
for (len = 0; nptr[len] >= '0' && nptr[len] <= '9'; len++)
|
|
;
|
|
|
|
for (cur = nptr + len - 1; cur != nptr - 1; cur--) {
|
|
val += mult * (*cur - '0');
|
|
mult *= 10;
|
|
}
|
|
|
|
return val * neg;
|
|
}
|
|
|
|
int gotcha_close(int fd) { return syscall(SYS_close, fd); }
|
|
|
|
int gotcha_mprotect(void *addr, size_t len, int prot) {
|
|
return syscall(SYS_mprotect, addr, len, prot);
|
|
}
|
|
|
|
ssize_t gotcha_read(int fd, void *buf, size_t count) {
|
|
return syscall(SYS_read, fd, buf, count);
|
|
}
|
|
|
|
static const char *add_to_buffer(const char *str, int fd, int *pos,
|
|
char *buffer, int buffer_size,
|
|
int *num_printed, int print_percent) {
|
|
for (; *str && (print_percent || *str != '%'); str++) {
|
|
if (*pos >= buffer_size) { // GCOVR_EXCL_START
|
|
gotcha_write(fd, buffer, buffer_size);
|
|
*num_printed += buffer_size;
|
|
*pos = 0;
|
|
} // GCOVR_EXCL_STOP
|
|
else {
|
|
buffer[*pos] = *str;
|
|
}
|
|
*pos = *pos + 1;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
int gotcha_int_printf(int fd, const char *format, ...) {
|
|
#define inc(S) \
|
|
do { \
|
|
S++; \
|
|
if (*(S) == '\0') goto done; \
|
|
} while (0)
|
|
va_list args;
|
|
const char *str = format;
|
|
int buffer_pos = 0;
|
|
int char_width = 0, short_width = 0, long_width = 0, long_long_width = 0;
|
|
int size_width = 0;
|
|
int num_printed = 0;
|
|
char buffer[4096] = {'\0'};
|
|
|
|
va_start(args, format);
|
|
while (*str) {
|
|
str = add_to_buffer(str, fd, &buffer_pos, buffer, sizeof(buffer),
|
|
&num_printed, 0);
|
|
if (!*str) break;
|
|
|
|
gotcha_assert(*str == '%');
|
|
inc(str);
|
|
|
|
char_width = short_width = long_width = long_long_width = size_width = 0;
|
|
if (*str == 'h' && *(str + 1) == 'h') {
|
|
char_width = 1;
|
|
inc(str);
|
|
inc(str);
|
|
} else if (*str == 'h') {
|
|
short_width = 1;
|
|
inc(str);
|
|
} else if (*str == 'l' && *(str + 1) == 'l') {
|
|
long_long_width = 1;
|
|
inc(str);
|
|
inc(str);
|
|
} else if (*str == 'l') {
|
|
long_width = 1;
|
|
inc(str);
|
|
} else if (*str == 'z') {
|
|
size_width = 1;
|
|
inc(str);
|
|
}
|
|
|
|
if (*str == 'd' || *str == 'i') {
|
|
signed long val = 0;
|
|
char numstr[64] = {'\0'};
|
|
if (char_width)
|
|
val = (signed long)(signed char)va_arg(args, signed int);
|
|
else if (short_width)
|
|
val = (signed long)(signed short)va_arg(args, signed int);
|
|
else if (long_width)
|
|
val = (signed long)va_arg(args, signed long);
|
|
else if (long_long_width)
|
|
val = (signed long)va_arg(args, signed long long);
|
|
else if (size_width)
|
|
val = (signed long)va_arg(args, ssize_t);
|
|
else
|
|
val = (signed long)va_arg(args, signed int);
|
|
slong_to_str(val, numstr, 64);
|
|
add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer),
|
|
&num_printed, 1);
|
|
} else if (*str == 'u') {
|
|
unsigned long val = 0;
|
|
char numstr[64] = {'\0'};
|
|
if (char_width)
|
|
val = (unsigned long)(unsigned char)va_arg(args, unsigned int);
|
|
else if (short_width)
|
|
val = (unsigned long)(unsigned short)va_arg(args, unsigned int);
|
|
else if (long_width)
|
|
val = (unsigned long)va_arg(args, unsigned long);
|
|
else if (long_long_width)
|
|
val = (unsigned long)va_arg(args, unsigned long long);
|
|
else if (size_width)
|
|
val = (unsigned long)va_arg(args, ssize_t);
|
|
else
|
|
val = (unsigned long)va_arg(args, unsigned int);
|
|
ulong_to_str(val, numstr, 64);
|
|
add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer),
|
|
&num_printed, 1);
|
|
} else if (*str == 'x' || *str == 'X' || *str == 'p') {
|
|
unsigned long val = 0;
|
|
char numstr[64] = {'\0'};
|
|
if (*str != 'p') {
|
|
if (char_width)
|
|
val = (unsigned long)(unsigned char)va_arg(args, unsigned int);
|
|
else if (short_width)
|
|
val = (unsigned long)(unsigned short)va_arg(args, unsigned int);
|
|
else if (long_width)
|
|
val = (unsigned long)va_arg(args, unsigned long);
|
|
else if (long_long_width)
|
|
val = (unsigned long)va_arg(args, unsigned long long);
|
|
else if (size_width)
|
|
val = (unsigned long)va_arg(args, ssize_t);
|
|
else
|
|
val = (unsigned long)va_arg(args, unsigned int);
|
|
} else {
|
|
val = (unsigned long)va_arg(args, void *);
|
|
add_to_buffer("0x", fd, &buffer_pos, buffer, sizeof(buffer),
|
|
&num_printed, 1);
|
|
}
|
|
ulong_to_hexstr(val, numstr, 64, (*str == 'X'));
|
|
add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer),
|
|
&num_printed, 1);
|
|
} else if (*str == 'c') {
|
|
char cbuf[2] = {'\0'};
|
|
cbuf[0] = (unsigned char)va_arg(args, unsigned int);
|
|
cbuf[1] = '\0';
|
|
add_to_buffer(cbuf, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed,
|
|
1);
|
|
} else if (*str == 's') {
|
|
char *s = (char *)va_arg(args, char *);
|
|
add_to_buffer(s, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed,
|
|
1);
|
|
} else if (*str == '%') {
|
|
add_to_buffer("%", fd, &buffer_pos, buffer, sizeof(buffer), &num_printed,
|
|
1);
|
|
} else {
|
|
char s[3] = {'\0'};
|
|
s[0] = '%';
|
|
s[1] = *str;
|
|
s[2] = '\0';
|
|
add_to_buffer(s, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed,
|
|
1);
|
|
}
|
|
inc(str);
|
|
}
|
|
|
|
done: // GCOVR_EXCL_LINE
|
|
gotcha_write(fd, buffer, buffer_pos);
|
|
num_printed += buffer_pos;
|
|
va_end(args);
|
|
return num_printed;
|
|
}
|
|
|
|
void *gotcha_memset(void *s, int c, size_t n) {
|
|
size_t i = 0;
|
|
unsigned char byte = (unsigned char)c;
|
|
for (i = 0; i < n; i++) {
|
|
((unsigned char *)s)[i] = byte;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
char *gotcha_strncat(char *dest, const char *src, size_t n) {
|
|
char *dest_begin = dest;
|
|
dest = dest + gotcha_strlen(dest);
|
|
size_t dest_stop = gotcha_strnlen(src, n);
|
|
dest[dest_stop] = '\0';
|
|
gotcha_memcpy(dest, (void *)src, n);
|
|
return dest_begin;
|
|
}
|