X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=java_strings.py;h=1987c10e58db6d3915cdf7e2ba7f8fe1aafb1a2f;hb=798362a31590a4c5626db086566c083088ef0861;hp=96d6909678ce7e58997f7866a4af65b0db8b40ef;hpb=753d902bc977acbf08b3166f054673236c39c01b;p=ldk-java diff --git a/java_strings.py b/java_strings.py index 96d69096..1987c10e 100644 --- a/java_strings.py +++ b/java_strings.py @@ -37,9 +37,21 @@ public class bindings { System.loadLibrary(\"lightningjni\"); init(java.lang.Enum.class, VecOrSliceDef.class); init_class_cache(); + if (!get_lib_version_string().equals(get_ldk_java_bindings_version())) + throw new IllegalArgumentException("Compiled LDK library and LDK class failes do not match"); + // Fetching the LDK versions from C also checks that the header and binaries match + get_ldk_c_bindings_version(); + get_ldk_version(); } static native void init(java.lang.Class c, java.lang.Class slicedef); static native void init_class_cache(); + static native String get_lib_version_string(); + + public static String get_ldk_java_bindings_version() { + return ""; + } + public static native String get_ldk_c_bindings_version(); + public static native String get_ldk_version(); public static native boolean deref_bool(long ptr); public static native long deref_long(long ptr); @@ -60,6 +72,7 @@ public class bindings { self.util_fn_pfx = """package org.ldk.structs; import org.ldk.impl.bindings; import java.util.Arrays; +import org.ldk.enums.*; public class UtilMethods { """ @@ -75,7 +88,6 @@ class CommonBase { """ self.c_file_pfx = """#include \"org_ldk_impl_bindings.h\" -#include #include #include #include @@ -83,6 +95,35 @@ class CommonBase { """ + if self.target == Target.ANDROID: + self.c_file_pfx = self.c_file_pfx + """ +#include +#define DEBUG_PRINT(...) __android_log_print(ANDROID_LOG_ERROR, "LDK", __VA_ARGS__) + +#include +#include +static void* redirect_stderr(void* ignored) { + int pipes[2]; + pipe(pipes); + dup2(pipes[1], STDERR_FILENO); + char buf[8192]; + memset(buf, 0, 8192); + ssize_t len; + while ((len = read(pipes[0], buf, 8191)) > 0) { + DEBUG_PRINT("%s\\n", buf); + memset(buf, 0, 8192); + } + DEBUG_PRINT("End of stderr???\\n"); + return 0; +} +void __attribute__((constructor)) spawn_stderr_redirection() { + pthread_t thread; + pthread_create(&thread, NULL, &redirect_stderr, NULL); +} +""" + else: + self.c_file_pfx = self.c_file_pfx + "#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)\n" + if not DEBUG: self.c_file_pfx = self.c_file_pfx + """#define MALLOC(a, _) malloc(a) #define FREE(p) if ((long)(p) > 1024) { free(p); } @@ -96,12 +137,66 @@ class CommonBase { // Assert a is true or do nothing #define CHECK(a) DO_ASSERT(a) +void __attribute__((constructor)) debug_log_version() { + if (check_get_ldk_version() == NULL) + DEBUG_PRINT("LDK version did not match the header we built against\\n"); + if (check_get_ldk_bindings_version() == NULL) + DEBUG_PRINT("LDK C Bindings version did not match the header we built against\\n"); + DEBUG_PRINT("Loaded LDK-Java Bindings with LDK %s and LDK-C-Bindings %s\\n", check_get_ldk_version(), check_get_ldk_bindings_version()); +} + // Running a leak check across all the allocations and frees of the JDK is a mess, // so instead we implement our own naive leak checker here, relying on the -wrap // linker option to wrap malloc/calloc/realloc/free, tracking everyhing allocated // and free'd in Rust or C across the generated bindings shared library. #include -#include +""" + + if self.target == Target.ANDROID: + self.c_file_pfx = self.c_file_pfx + """ +#include +#include + +// Implement the execinfo functions using _Unwind_backtrace. This seems to miss many Rust +// symbols, so we only use it on Android, where execinfo.h is unavailable. + +struct BacktraceState { + void** current; + void** end; +}; +static _Unwind_Reason_Code unwind_callback(struct _Unwind_Context* context, void* arg) { + struct BacktraceState* state = (struct BacktraceState*)arg; + uintptr_t pc = _Unwind_GetIP(context); + if (pc) { + if (state->current == state->end) { + return _URC_END_OF_STACK; + } else { + *state->current++ = (void*)(pc); + } + } + return _URC_NO_REASON; +} + +int backtrace(void** buffer, int max) { + struct BacktraceState state = { buffer, buffer + max }; + _Unwind_Backtrace(unwind_callback, &state); + return state.current - buffer; +} + +void backtrace_symbols_fd(void ** buffer, int count, int _fd) { + for (int idx = 0; idx < count; ++idx) { + Dl_info info; + if (dladdr(buffer[idx], &info) && info.dli_sname) { + DEBUG_PRINT("%p: %s", buffer[idx], info.dli_sname); + } else { + DEBUG_PRINT("%p: ???", buffer[idx]); + } + } +} +""" + else: + self.c_file_pfx = self.c_file_pfx + "#include \n" + self.c_file_pfx = self.c_file_pfx + """ #include static mtx_t allocation_mtx; @@ -116,7 +211,7 @@ typedef struct allocation { const char* struct_name; void* bt[BT_MAX]; int bt_len; - size_t alloc_len; + unsigned long alloc_len; } allocation; static allocation* allocation_ll = NULL; @@ -146,11 +241,11 @@ static void alloc_freed(void* ptr) { while (it->ptr != ptr) { p = it; it = it->next; if (it == NULL) { - fprintf(stderr, "Tried to free unknown pointer %p at:\\n", ptr); + DEBUG_PRINT("Tried to free unknown pointer %p at:\\n", ptr); void* bt[BT_MAX]; int bt_len = backtrace(bt, BT_MAX); backtrace_symbols_fd(bt, bt_len, STDERR_FILENO); - fprintf(stderr, "\\n\\n"); + DEBUG_PRINT("\\n\\n"); DO_ASSERT(mtx_unlock(&allocation_mtx) == thrd_success); return; // addrsan should catch malloc-unknown and print more info than we have } @@ -195,21 +290,21 @@ void __wrap_reallocarray(void* ptr, size_t new_sz) { } void __attribute__((destructor)) check_leaks() { - size_t alloc_count = 0; - size_t alloc_size = 0; - fprintf(stderr, "The following LDK-allocated blocks still remain.\\n"); - fprintf(stderr, "Note that this is only accurate if System.gc(); System.runFinalization()\\n"); - fprintf(stderr, "was called prior to exit after all LDK objects were out of scope.\\n"); + unsigned long alloc_count = 0; + unsigned long alloc_size = 0; + DEBUG_PRINT("The following LDK-allocated blocks still remain.\\n"); + DEBUG_PRINT("Note that this is only accurate if System.gc(); System.runFinalization()\\n"); + DEBUG_PRINT("was called prior to exit after all LDK objects were out of scope.\\n"); for (allocation* a = allocation_ll; a != NULL; a = a->next) { - fprintf(stderr, "%s %p (%lu bytes) remains:\\n", a->struct_name, a->ptr, a->alloc_len); + DEBUG_PRINT("%s %p (%lu bytes) remains:\\n", a->struct_name, a->ptr, a->alloc_len); backtrace_symbols_fd(a->bt, a->bt_len, STDERR_FILENO); - fprintf(stderr, "\\n\\n"); + DEBUG_PRINT("\\n\\n"); alloc_count++; alloc_size += a->alloc_len; } - fprintf(stderr, "%lu allocations remained for %lu bytes.\\n", alloc_count, alloc_size); - fprintf(stderr, "Note that this is only accurate if System.gc(); System.runFinalization()\\n"); - fprintf(stderr, "was called prior to exit after all LDK objects were out of scope.\\n"); + DEBUG_PRINT("%lu allocations remained for %lu bytes.\\n", alloc_count, alloc_size); + DEBUG_PRINT("Note that this is only accurate if System.gc(); System.runFinalization()\\n"); + DEBUG_PRINT("was called prior to exit after all LDK objects were out of scope.\\n"); } """ self.c_file_pfx = self.c_file_pfx + """ @@ -308,12 +403,12 @@ typedef jbyteArray int8_tArray; static inline jstring str_ref_to_java(JNIEnv *env, const char* chars, size_t len) { // Sadly we need to create a temporary because Java can't accept a char* without a 0-terminator - char* err_buf = MALLOC(len + 1, "str conv buf"); - memcpy(err_buf, chars, len); - err_buf[len] = 0; - jstring err_conv = (*env)->NewStringUTF(env, chars); - FREE(err_buf); - return err_conv; + char* conv_buf = MALLOC(len + 1, "str conv buf"); + memcpy(conv_buf, chars, len); + conv_buf[len] = 0; + jstring ret = (*env)->NewStringUTF(env, conv_buf); + FREE(conv_buf); + return ret; } static inline LDKStr java_to_owned_str(JNIEnv *env, jstring str) { uint64_t str_len = (*env)->GetStringUTFLength(env, str); @@ -329,6 +424,16 @@ static inline LDKStr java_to_owned_str(JNIEnv *env, jstring str) { }; return res; } + +JNIEXPORT jstring JNICALL Java_org_ldk_impl_bindings_get_1lib_1version_1string(JNIEnv *env, jclass _c) { + return str_ref_to_java(env, "", strlen("")); +} +JNIEXPORT jstring JNICALL Java_org_ldk_impl_bindings_get_1ldk_1c_1bindings_1version(JNIEnv *env, jclass _c) { + return str_ref_to_java(env, check_get_ldk_bindings_version(), strlen(check_get_ldk_bindings_version())); +} +JNIEXPORT jstring JNICALL Java_org_ldk_impl_bindings_get_1ldk_1version(JNIEnv *env, jclass _c) { + return str_ref_to_java(env, check_get_ldk_version(), strlen(check_get_ldk_version())); +} """ self.hu_struct_file_prefix = """package org.ldk.structs;