diff --git a/meson.build b/meson.build index 632b1c90c6..8637437873 100644 --- a/meson.build +++ b/meson.build @@ -696,6 +696,28 @@ foreach target : target_dirs suite: 'lat-pr-fast', ) + aot_cache_reader_test = executable( + 'test-latx-aot-cache-reader', + files( + 'target/i386/latx/sbt/tests/aot-cache-reader-test.c', + 'target/i386/latx/sbt/aot_reader.c', + 'target/i386/latx/sbt/aot_lib.c', + 'target/i386/latx/sbt/file_ctx.c' + ) + genh + tcg_trace_genh + [syscall_nr_generated], + c_args: smc_reload_test_c_args, + dependencies: [glib], + include_directories: target_inc, + link_args: smc_reload_test_link_args + [ + '-Wl,--wrap=fdopen', + '-Wl,--wrap=fclose' + ] + ) + test( + 'latx-aot-cache-reader', + aot_cache_reader_test, + suite: 'lat-pr-fast', + ) + aot_exit_worker_test = executable( 'test-latx-aot-exit-worker', files( diff --git a/target/i386/latx/include/aot_reader.h b/target/i386/latx/include/aot_reader.h new file mode 100644 index 0000000000..a55ba243d1 --- /dev/null +++ b/target/i386/latx/include/aot_reader.h @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2021-2026 LAT Project Authors + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#ifndef LATX_AOT_READER_H +#define LATX_AOT_READER_H + +#include "aot.h" + +int aot_get_tb_num(char *lib_name, char *aot_file_name, CPUState *cpu); + +#endif diff --git a/target/i386/latx/include/file_ctx.h b/target/i386/latx/include/file_ctx.h index 4e0c5e7346..554fa4adf4 100644 --- a/target/i386/latx/include/file_ctx.h +++ b/target/i386/latx/include/file_ctx.h @@ -12,11 +12,13 @@ #ifndef AOT_FILE_CTX_H #define AOT_FILE_CTX_H #include "aot.h" + int aot_file_ctx(uint64_t maxSize, uint64_t leftMinSize); int aot_file_get_tmp_path(const char *aot_file, char *tmp_path, size_t tmp_path_size); int aot_file_get_lock_path(const char *aot_file, char *lock_path, size_t lock_path_size); +bool aot_file_has_footer(FILE *file, const char *footer); int aot_file_complete_write(FILE *file, const char *tmp_path); /* * Negative: rename failed. Zero: rename and directory sync succeeded. diff --git a/target/i386/latx/sbt/aot.c b/target/i386/latx/sbt/aot.c index 91d6c19e14..3aa6292cfa 100644 --- a/target/i386/latx/sbt/aot.c +++ b/target/i386/latx/sbt/aot.c @@ -22,6 +22,7 @@ #include "qemu.h" #include "lsenv.h" #include "file_ctx.h" +#include "aot_reader.h" #include "aot_merge.h" #include "aot_recover_tb.h" #include "aot_smc.h" @@ -657,36 +658,6 @@ static uint8_t *fill_ir1_buff(uint64_t ir1_table_offset, aot_tb *p_aot_tbs, return ir1_buffer; } -int get_aot_path(const char *lib_name, char *file_path, - size_t file_path_size) -{ - const char *home; - char *escaped_name; - int len; - - if (!lib_name || !file_path || !file_path_size) { - return -EINVAL; - } - escaped_name = g_strdup(lib_name); - if (!escaped_name) { - return -ENOMEM; - } - for (char *p = escaped_name; *p; p++) { - if (*p == '/') { - *p = '+'; - } - } - home = getenv("HOME"); - len = snprintf(file_path, file_path_size, "%s/.cache/latx/%s.aot2", - home ? home : "", escaped_name); - g_free(escaped_name); - if (len < 0 || (size_t)len >= file_path_size) { - file_path[0] = '\0'; - return -ENAMETOOLONG; - } - return 0; -} - static long get_fileSize(FILE* file) { long fileSize = -1; @@ -888,74 +859,6 @@ char in_white_list(char *lib) return in_list(lib, lib_white_list); } -static int get_tb_num(char *lib_name, char *aot_file_name, CPUState *cpu) -{ - if (get_aot_path(aot_file_name, aot_file_path, PATH_MAX) < 0) { - return 0; - } - if (access(aot_file_path, 0) < 0) { - return 0; - } - int fd = open(aot_file_path, O_RDONLY); - FILE *pf = fdopen(fd, "r"); - lsassert(pf && ("open aot file failed!")); - /* Get file size */ - fseek(pf, 0, SEEK_END); /* seek to end of file */ - size_t file_sz = ftell(pf); /* get current file pointer */ - char aot_version[strlen(AOT_VERSION) + 1]; - /*check aot complete.*/ - if (fseek(pf, -strlen(AOT_VERSION), SEEK_END) != 0) { - qemu_log_mask(LAT_LOG_AOT, "can't fseek aot file\n"); - fclose(pf); - return 0; - } - if (fread(aot_version, strlen(AOT_VERSION), 1, pf) != 1) { - qemu_log_mask(LAT_LOG_AOT, "get error.\n"); - fclose(pf); - return 0; - } - if (!strstr(aot_version, AOT_VERSION)) { - qemu_log_mask(LAT_LOG_AOT, "aot file is not complete %s\n", lib_name); - remove(aot_file_path); - return 0; - } - fseek(pf, 0, SEEK_SET); /* seek back to beginning of file */ - - /* Read aot file */ - /* buffer = malloc(file_sz); */ - void *buffer = mmap(NULL, file_sz, PROT_READ, MAP_SHARED, fd, 0); - if (buffer < 0) { - qemu_log_mask(LAT_LOG_AOT, "aot file mmap error\n"); - return 0; - } - assert(buffer); - aot_header *p_header = (aot_header *)buffer; - /* dump_aot_buffer(p_header); */ - struct stat statbuf; - if ((p_header->aot_file_type & (ELF_AOT_FILE | PE_AOT_FILE)) - && (stat(lib_name, &statbuf) - || p_header->lib_size != statbuf.st_size - || p_header->last_modify_time.tv_sec != statbuf.st_mtim.tv_sec - || p_header->last_modify_time.tv_nsec != statbuf.st_mtim.tv_nsec)) { - qemu_log_mask(LAT_LOG_AOT, "need remove old aot file. %s lib_size %d %ld\n", - aot_file_path, p_header->lib_size, statbuf.st_size); - remove(aot_file_path); - qemu_log_mask(LAT_LOG_AOT, "remove end\n"); - return 0; - } - - int aim_tb_num = 0; - if (cpu->tcg_cflags & CF_PARALLEL) { - aim_tb_num = p_header->parallel_tb_num; - } else { - aim_tb_num = p_header->unparallel_tb_num; - } - - munmap(buffer, file_sz); - fclose(pf); - return aim_tb_num; -} - #define PROLIFERATION_RATE 10 static inline int need_gen_aot(CPUState *cpu, char *lib_name, char *aot_file_name, int *lockfd, uint32_t tb_count) @@ -970,7 +873,7 @@ static inline int need_gen_aot(CPUState *cpu, aim_tb_num = p_head->unparallel_tb_num; } } else { - aim_tb_num = get_tb_num(lib_name, aot_file_name, cpu); + aim_tb_num = aot_get_tb_num(lib_name, aot_file_name, cpu); } /* Too few tb number. */ if (tb_count * PROLIFERATION_RATE < aim_tb_num) { @@ -1275,96 +1178,8 @@ void dump_aot_buffer(aot_header *p_header) } -static void remove_curr_aot_file(int fd) -{ - char lock_path[PATH_MAX]; - - if (aot_file_get_lock_path(aot_file_path, lock_path, - sizeof(lock_path)) < 0) { - return; - } - aot_file_unlink_if_same(aot_file_path, fd, lock_path); -} - time_t aot_st_ctime; -lib_info *aot_load(char *lib_name, char *aot_file_name, - void **curr_aot_buffer) -{ - /* Get aot_file path and lock file. */ - assert(lib_name); - if (get_aot_path(aot_file_name, aot_file_path, PATH_MAX) < 0) { - return NULL; - } - if (access(aot_file_path, 0) < 0) { - return NULL; - } - - /* Open aot_file. */ - void *buffer = MAP_FAILED; - struct stat statbuf; - lib_info *curr_lib_info = NULL; - size_t file_sz = 0; - char aot_version[strlen(AOT_VERSION) + 1]; - int fd = open(aot_file_path, O_RDONLY); - FILE *pf = NULL; - if (fd < 0) { - goto exit_aot_load; - } - pf = fdopen(fd, "r"); - lsassert(pf && ("open aot file failed!")); - fseek(pf, 0, SEEK_END); /* seek to end of file */ - file_sz = ftell(pf); /* get current file pointer */ - - /*check aot complete.*/ - if (fseek(pf, -strlen(AOT_VERSION), SEEK_END) != 0 - || fread(aot_version, strlen(AOT_VERSION), 1, pf) != 1) { - goto exit_aot_load; - } - if (!strstr(aot_version, AOT_VERSION)) { - qemu_log_mask(LAT_LOG_AOT, "aot file is not complete %s\n", lib_name); - remove_curr_aot_file(fd); - goto exit_aot_load; - } - - /* Read aot file */ - fseek(pf, 0, SEEK_SET); /* seek back to beginning of file */ - buffer = mmap(NULL, file_sz, PROT_READ, MAP_SHARED, fd, 0); - if (buffer == MAP_FAILED) { - qemu_log_mask(LAT_LOG_AOT, "aot file mmap error\n"); - goto exit_aot_load; - } - assert(buffer); - aot_header *p_header = (aot_header *)buffer; - - /* Test original file state. */ - if (p_header->aot_file_type & (ELF_AOT_FILE | PE_AOT_FILE)) { - if (stat(lib_name, &statbuf) - || p_header->lib_size != statbuf.st_size - || p_header->last_modify_time.tv_sec != statbuf.st_mtim.tv_sec - || p_header->last_modify_time.tv_nsec != statbuf.st_mtim.tv_nsec) { - qemu_log_mask(LAT_LOG_AOT, "need remove old aot file. %s lib_size %d %ld\n", - aot_file_path, p_header->lib_size, statbuf.st_size); - remove_curr_aot_file(fd); - goto exit_aot_load; - } - } - - /* dump_aot_buffer(p_header); */ - *curr_aot_buffer = buffer; - curr_lib_info = lib_tree_insert(aot_file_name, buffer, file_sz); - -exit_aot_load: - if (!curr_lib_info && buffer != MAP_FAILED) { - munmap(buffer, file_sz); - } - if (likely(pf)) { - fclose(pf); - } - close(fd); - return curr_lib_info; -} - struct aot_segment *aot_find_segment(char *path, int offset, void *curr_aot_buffer) { struct aot_header *p_header = (struct aot_header *)curr_aot_buffer; @@ -1645,7 +1460,6 @@ void aot_do_tb_reloc(TranslationBlock *tb, struct aot_tb *stb, } } } - static aot_segment *get_segment(seg_info *seg, char *lib_name, uint64_t aot_offset, abi_long start, abi_long end, void **curr_aot_buffer) diff --git a/target/i386/latx/sbt/aot_reader.c b/target/i386/latx/sbt/aot_reader.c new file mode 100644 index 0000000000..2273bc84fb --- /dev/null +++ b/target/i386/latx/sbt/aot_reader.c @@ -0,0 +1,184 @@ +/* + * SPDX-FileCopyrightText: 2021-2026 LAT Project Authors + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include "qemu-def.h" +#include "aot.h" +#include "aot_reader.h" +#include "file_ctx.h" +#include "qemu.h" + +#ifdef CONFIG_LATX_AOT + +int aot_get_tb_num(char *lib_name, char *aot_file_name, CPUState *cpu) +{ + void *buffer = MAP_FAILED; + FILE *pf = NULL; + long file_size; + size_t file_sz = 0; + int aim_tb_num = 0; + int fd; + + if (get_aot_path(aot_file_name, aot_file_path, PATH_MAX) < 0) { + return 0; + } + if (access(aot_file_path, 0) < 0) { + return 0; + } + fd = open(aot_file_path, O_RDONLY); + if (fd < 0) { + return 0; + } + pf = fdopen(fd, "r"); + if (!pf) { + close(fd); + return 0; + } + + /* Get file size */ + if (fseek(pf, 0, SEEK_END) || (file_size = ftell(pf)) < 0) { + goto out; + } + file_sz = file_size; + if (file_sz < sizeof(aot_header)) { + qemu_log_mask(LAT_LOG_AOT, "aot file is too short %s\n", lib_name); + remove(aot_file_path); + goto out; + } + + /* Check that the AOT file was completely written. */ + if (!aot_file_has_footer(pf, AOT_VERSION)) { + qemu_log_mask(LAT_LOG_AOT, "aot file is not complete %s\n", lib_name); + remove(aot_file_path); + goto out; + } + fseek(pf, 0, SEEK_SET); + + buffer = mmap(NULL, file_sz, PROT_READ, MAP_SHARED, fd, 0); + if (buffer == MAP_FAILED) { + qemu_log_mask(LAT_LOG_AOT, "aot file mmap error\n"); + goto out; + } + assert(buffer); + aot_header *p_header = (aot_header *)buffer; + struct stat statbuf; + + if ((p_header->aot_file_type & (ELF_AOT_FILE | PE_AOT_FILE)) + && (stat(lib_name, &statbuf) + || p_header->lib_size != statbuf.st_size + || p_header->last_modify_time.tv_sec != statbuf.st_mtim.tv_sec + || p_header->last_modify_time.tv_nsec != statbuf.st_mtim.tv_nsec)) { + qemu_log_mask(LAT_LOG_AOT, + "need remove old aot file. %s lib_size %d %ld\n", + aot_file_path, p_header->lib_size, statbuf.st_size); + remove(aot_file_path); + qemu_log_mask(LAT_LOG_AOT, "remove end\n"); + goto out; + } + + if (cpu->tcg_cflags & CF_PARALLEL) { + aim_tb_num = p_header->parallel_tb_num; + } else { + aim_tb_num = p_header->unparallel_tb_num; + } + +out: + if (buffer != MAP_FAILED) { + munmap(buffer, file_sz); + } + fclose(pf); + return aim_tb_num; +} + +static void remove_curr_aot_file(int fd) +{ + char lock_path[PATH_MAX]; + + if (aot_file_get_lock_path(aot_file_path, lock_path, + sizeof(lock_path)) < 0) { + return; + } + aot_file_unlink_if_same(aot_file_path, fd, lock_path); +} + +lib_info *aot_load(char *lib_name, char *aot_file_name, + void **curr_aot_buffer) +{ + void *buffer = MAP_FAILED; + struct stat statbuf; + lib_info *curr_lib_info = NULL; + size_t file_sz = 0; + long file_size; + int fd; + FILE *pf = NULL; + + assert(lib_name); + if (get_aot_path(aot_file_name, aot_file_path, PATH_MAX) < 0) { + return NULL; + } + if (access(aot_file_path, 0) < 0) { + return NULL; + } + + fd = open(aot_file_path, O_RDONLY); + if (fd < 0) { + return NULL; + } + pf = fdopen(fd, "r"); + if (!pf) { + close(fd); + return NULL; + } + + if (fseek(pf, 0, SEEK_END) || (file_size = ftell(pf)) < 0) { + goto out; + } + if ((size_t)file_size < sizeof(aot_header)) { + qemu_log_mask(LAT_LOG_AOT, "aot file is too short %s\n", lib_name); + remove_curr_aot_file(fd); + goto out; + } + file_sz = file_size; + + if (!aot_file_has_footer(pf, AOT_VERSION)) { + qemu_log_mask(LAT_LOG_AOT, "aot file is not complete %s\n", lib_name); + remove_curr_aot_file(fd); + goto out; + } + + fseek(pf, 0, SEEK_SET); + buffer = mmap(NULL, file_sz, PROT_READ, MAP_SHARED, fd, 0); + if (buffer == MAP_FAILED) { + qemu_log_mask(LAT_LOG_AOT, "aot file mmap error\n"); + goto out; + } + assert(buffer); + aot_header *p_header = (aot_header *)buffer; + + if (p_header->aot_file_type & (ELF_AOT_FILE | PE_AOT_FILE)) { + if (stat(lib_name, &statbuf) + || p_header->lib_size != statbuf.st_size + || p_header->last_modify_time.tv_sec != statbuf.st_mtim.tv_sec + || p_header->last_modify_time.tv_nsec != statbuf.st_mtim.tv_nsec) { + qemu_log_mask(LAT_LOG_AOT, + "need remove old aot file. %s lib_size %d %ld\n", + aot_file_path, p_header->lib_size, statbuf.st_size); + remove_curr_aot_file(fd); + goto out; + } + } + + *curr_aot_buffer = buffer; + curr_lib_info = lib_tree_insert(aot_file_name, buffer, file_sz); + +out: + if (!curr_lib_info && buffer != MAP_FAILED) { + munmap(buffer, file_sz); + } + fclose(pf); + return curr_lib_info; +} + +#endif diff --git a/target/i386/latx/sbt/file_ctx.c b/target/i386/latx/sbt/file_ctx.c index 7a765a7945..0ce7b35f96 100644 --- a/target/i386/latx/sbt/file_ctx.c +++ b/target/i386/latx/sbt/file_ctx.c @@ -27,6 +27,36 @@ struct aot_info { time_t st_actime; }; +int get_aot_path(const char *lib_name, char *file_path, + size_t file_path_size) +{ + const char *home; + char *escaped_name; + int len; + + if (!lib_name || !file_path || !file_path_size) { + return -EINVAL; + } + escaped_name = g_strdup(lib_name); + if (!escaped_name) { + return -ENOMEM; + } + for (char *p = escaped_name; *p; p++) { + if (*p == '/') { + *p = '+'; + } + } + home = getenv("HOME"); + len = snprintf(file_path, file_path_size, "%s/.cache/latx/%s.aot2", + home ? home : "", escaped_name); + g_free(escaped_name); + if (len < 0 || (size_t)len >= file_path_size) { + file_path[0] = '\0'; + return -ENAMETOOLONG; + } + return 0; +} + int aot_file_get_tmp_path(const char *aot_file, char *tmp_path, size_t tmp_path_size) { @@ -49,6 +79,28 @@ int aot_file_get_lock_path(const char *aot_file, char *lock_path, return 0; } +bool aot_file_has_footer(FILE *file, const char *footer) +{ + size_t footer_len; + char *actual; + bool matches; + + if (!file || !footer) { + return false; + } + + footer_len = strlen(footer); + if (!footer_len || fseek(file, -(long)footer_len, SEEK_END) != 0) { + return false; + } + + actual = g_malloc(footer_len); + matches = fread(actual, footer_len, 1, file) == 1 && + !memcmp(actual, footer, footer_len); + g_free(actual); + return matches; +} + int aot_file_complete_write(FILE *file, const char *tmp_path) { int saved_errno = 0; diff --git a/target/i386/latx/sbt/meson.build b/target/i386/latx/sbt/meson.build index 568845b9be..23dde43fd8 100644 --- a/target/i386/latx/sbt/meson.build +++ b/target/i386/latx/sbt/meson.build @@ -1,6 +1,7 @@ i386_ss.add(when: 'CONFIG_LATX', if_true: files( 'segment.c', 'aot.c', + 'aot_reader.c', 'file_ctx.c', 'aot_link_seg.c', 'aot_merge.c', diff --git a/target/i386/latx/sbt/tests/aot-cache-reader-test.c b/target/i386/latx/sbt/tests/aot-cache-reader-test.c new file mode 100644 index 0000000000..f78d1df77b --- /dev/null +++ b/target/i386/latx/sbt/tests/aot-cache-reader-test.c @@ -0,0 +1,200 @@ +#include "qemu/osdep.h" + +#include + +#include "aot.h" +#include "aot_reader.h" +#include "aot_lib.h" +#include "file_ctx.h" + +char aot_file_path_buffer[PATH_MAX]; +char aot_file_lock_buffer[PATH_MAX]; +char *aot_file_path = aot_file_path_buffer; +char *aot_file_lock = aot_file_lock_buffer; +int qemu_loglevel; +static bool fail_fdopen; +static int tracked_fd; +static int sentinel_fd; +static unsigned int fdopen_count; +static unsigned int fclose_count; + +FILE *__real_fdopen(int fd, const char *mode); +int __real_fclose(FILE *stream); +FILE *__wrap_fdopen(int fd, const char *mode); +int __wrap_fclose(FILE *stream); + +FILE *__wrap_fdopen(int fd, const char *mode) +{ + fdopen_count++; + tracked_fd = fd; + if (fail_fdopen) { + errno = EMFILE; + return NULL; + } + return __real_fdopen(fd, mode); +} + +int __wrap_fclose(FILE *stream) +{ + int ret; + + ret = __real_fclose(stream); + fclose_count++; + sentinel_fd = open("/dev/null", O_RDONLY); + g_assert_cmpint(sentinel_fd, ==, tracked_fd); + return ret; +} + +int qemu_log(const char *fmt G_GNUC_UNUSED, ...) +{ + return 0; +} + +void print_stack_trace(void) +{ +} + +void pstrcpy(char *buf, int buf_size, const char *str) +{ + g_strlcpy(buf, str, buf_size); +} + +static void reset_stream_counts(void) +{ + fail_fdopen = false; + tracked_fd = -1; + sentinel_fd = -1; + fdopen_count = 0; + fclose_count = 0; +} + +static void assert_tracked_fd_is_closed(void) +{ + g_assert_cmpint(tracked_fd, >=, 0); + errno = 0; + g_assert_cmpint(fcntl(tracked_fd, F_GETFD), ==, -1); + g_assert_cmpint(errno, ==, EBADF); +} + +static void assert_stream_closed(void) +{ + g_assert_cmpuint(fdopen_count, ==, 1); + g_assert_cmpuint(fclose_count, ==, 1); + g_assert_cmpint(sentinel_fd, ==, tracked_fd); + g_assert_cmpint(fcntl(sentinel_fd, F_GETFD), !=, -1); + g_assert_cmpint(close(sentinel_fd), ==, 0); + sentinel_fd = -1; +} + +static void write_cache(const char *name, bool has_header, bool has_footer, + char *path) +{ + g_autofree char *dir = NULL; + g_autofree uint8_t *contents = NULL; + size_t footer_size = strlen(AOT_VERSION); + size_t size = (has_header ? sizeof(aot_header) : 0) + + (has_footer ? footer_size : 0); + + g_assert(get_aot_path(name, path, PATH_MAX) == 0); + dir = g_path_get_dirname(path); + g_assert(g_mkdir_with_parents(dir, 0700) == 0); + + contents = g_malloc0(size); + if (has_header) { + ((aot_header *)contents)->aot_file_type = CACHE_AOT_FILE; + } + if (has_footer) { + memcpy(contents + size - footer_size, AOT_VERSION, footer_size); + } + g_assert(g_file_set_contents(path, (char *)contents, size, NULL)); +} + +static void remove_cache(const char *name) +{ + char path[PATH_MAX]; + char lock_path[PATH_MAX]; + + g_assert(get_aot_path(name, path, sizeof(path)) == 0); + if (g_file_test(path, G_FILE_TEST_EXISTS)) { + g_assert(g_remove(path) == 0); + } + g_assert(aot_file_get_lock_path(path, lock_path, sizeof(lock_path)) == 0); + if (g_file_test(lock_path, G_FILE_TEST_EXISTS)) { + g_assert(g_remove(lock_path) == 0); + } +} + +int main(void) +{ + g_autofree char *cache_dir = NULL; + g_autofree char *cache_parent = NULL; + g_autofree char *test_dir = NULL; + g_autofree char *old_home = NULL; + char lib_name[] = "test-library"; + char bad_footer_name[] = "bad-footer"; + char truncated_name[] = "truncated"; + char complete_name[] = "complete"; + char fdopen_failure_name[] = "fdopen-failure"; + char cache_path[PATH_MAX]; + void *buffer; + lib_info *lib; + + test_dir = g_dir_make_tmp("latx-aot-reader-XXXXXX", NULL); + g_assert(test_dir != NULL); + old_home = g_strdup(g_getenv("HOME")); + g_assert(g_setenv("HOME", test_dir, true)); + + lib_tree_init(); + for (int i = 0; i < 16; i++) { + reset_stream_counts(); + write_cache(bad_footer_name, true, false, cache_path); + g_assert_cmpint(aot_get_tb_num(lib_name, bad_footer_name, NULL), + ==, 0); + g_assert(!g_file_test(cache_path, G_FILE_TEST_EXISTS)); + assert_stream_closed(); + + reset_stream_counts(); + buffer = NULL; + write_cache(truncated_name, false, true, cache_path); + g_assert(aot_load(lib_name, truncated_name, &buffer) == NULL); + g_assert(buffer == NULL); + g_assert(!g_file_test(cache_path, G_FILE_TEST_EXISTS)); + assert_stream_closed(); + } + + reset_stream_counts(); + buffer = NULL; + write_cache(complete_name, true, true, cache_path); + lib = aot_load(lib_name, complete_name, &buffer); + g_assert(lib != NULL); + g_assert(buffer != NULL); + assert_stream_closed(); + g_assert(lib_tree_remove(complete_name)); + + reset_stream_counts(); + fail_fdopen = true; + buffer = NULL; + write_cache(fdopen_failure_name, true, true, cache_path); + g_assert(aot_load(lib_name, fdopen_failure_name, &buffer) == NULL); + g_assert(buffer == NULL); + g_assert_cmpuint(fdopen_count, ==, 1); + g_assert_cmpuint(fclose_count, ==, 0); + assert_tracked_fd_is_closed(); + + remove_cache(bad_footer_name); + remove_cache(truncated_name); + remove_cache(complete_name); + remove_cache(fdopen_failure_name); + cache_dir = g_build_filename(test_dir, ".cache", "latx", NULL); + g_assert(g_rmdir(cache_dir) == 0); + cache_parent = g_build_filename(test_dir, ".cache", NULL); + g_assert(g_rmdir(cache_parent) == 0); + + if (old_home) { + g_assert(g_setenv("HOME", old_home, true)); + } else { + g_unsetenv("HOME"); + } + g_assert(g_rmdir(test_dir) == 0); + return 0; +} diff --git a/target/i386/latx/sbt/tests/aot-file-publish-test.c b/target/i386/latx/sbt/tests/aot-file-publish-test.c index 4bea1bcf79..b304e49f51 100644 --- a/target/i386/latx/sbt/tests/aot-file-publish-test.c +++ b/target/i386/latx/sbt/tests/aot-file-publish-test.c @@ -90,6 +90,15 @@ int main(void) g_assert(aot_file_get_tmp_path(aot_path, tmp_path, sizeof(tmp_path)) == 0); + file = fopen(tmp_path, "w+"); + g_assert(file != NULL); + g_assert(fputs("payload:Version: current", file) >= 0); + g_assert(aot_file_has_footer(file, "Version: current")); + g_assert(!aot_file_has_footer(file, "Version: currenT")); + g_assert(!aot_file_has_footer(file, "payload:Version: current+extra")); + g_assert(fclose(file) == 0); + g_assert(unlink(tmp_path) == 0); + g_assert(g_file_set_contents(aot_path, "old", -1, NULL)); file = fopen(tmp_path, "w"); g_assert(file != NULL);