From 0c9b9c148735bfb92c5f56a902e2a3b9fbbd82f2 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Tue, 20 Dec 2022 20:41:14 -0600 Subject: [PATCH] Third-party libraries reorganized to make adding more easier. Start of SSH/SFTP code. libgcrypt, libgpg-error, libz, added. --- .gitattributes | 2 + .gitignore | 5 +- CMakeLists.txt | 58 +- com.kangaroopunch.JoeyDev.yaml | 22 +- include/ssh.h | 55 + src/ssh.c | 320 ++++ thirdparty/libgcrypt-1.10.1.tar.bz2 | 3 + thirdparty/libgpg-error-1.46.tar.bz2 | 3 + thirdparty/memwatch.tar.bz2 | 3 + thirdparty/memwatch/FAQ | 133 -- thirdparty/memwatch/Makefile | 2 - thirdparty/memwatch/README | 99 - thirdparty/memwatch/USING | 213 -- thirdparty/memwatch/gpl.txt | 340 ---- thirdparty/memwatch/memwatch.c | 2664 -------------------------- thirdparty/memwatch/memwatch.h | 710 ------- thirdparty/memwatch/memwatch.lsm | 15 - thirdparty/memwatch/test.C | 116 -- thirdparty/zlib-1.2.13.tar.gz | 3 + tools/prebuild.sh | 104 +- 20 files changed, 510 insertions(+), 4360 deletions(-) create mode 100644 include/ssh.h create mode 100644 src/ssh.c create mode 100644 thirdparty/libgcrypt-1.10.1.tar.bz2 create mode 100644 thirdparty/libgpg-error-1.46.tar.bz2 create mode 100644 thirdparty/memwatch.tar.bz2 delete mode 100644 thirdparty/memwatch/FAQ delete mode 100644 thirdparty/memwatch/Makefile delete mode 100644 thirdparty/memwatch/README delete mode 100644 thirdparty/memwatch/USING delete mode 100644 thirdparty/memwatch/gpl.txt delete mode 100644 thirdparty/memwatch/memwatch.c delete mode 100644 thirdparty/memwatch/memwatch.h delete mode 100644 thirdparty/memwatch/memwatch.lsm delete mode 100644 thirdparty/memwatch/test.C create mode 100644 thirdparty/zlib-1.2.13.tar.gz diff --git a/.gitattributes b/.gitattributes index d2ac973..8085873 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ +*.gz filter=lfs diff=lfs merge=lfs -text *.tgz filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text *.png filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore index 317fe59..b16568d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,11 @@ .idea/ .flatpak-builder/ crapForLater/ -thirdparty/scintilla/ -thirdparty/lexilla/ -thirdparty/libssh2-1.10.0/ +thirdparty-installed/ ui/generated/ cmake-build-debug/ flatpak-build/ flatpak-repo/ -crapForLater/ *~ joeydev.flatpak diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a55742..a0ae62e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,19 +37,20 @@ option(DEBUG_MODE "Enable debugging output and memory tracing?" ON) set(CMAKE_C_STANDARD 99) set(SOURCE_FILES - thirdparty/memwatch/memwatch.c - ui/generated/resources.c - src/main.c - src/utils.c - src/joeydev.c - src/vector.c - src/array.c - src/draw.c - src/image.c - src/vecparse.c - src/color.c - src/palette.c - src/project.c + thirdparty-installed/memwatch/memwatch.c + ui/generated/resources.c + src/main.c + src/utils.c + src/joeydev.c + src/vector.c + src/array.c + src/draw.c + src/image.c + src/vecparse.c + src/color.c + src/palette.c + src/project.c + src/ssh.c ) configure_file(include/config.h.in config.h) @@ -60,9 +61,13 @@ add_executable(${CMAKE_PROJECT_NAME} ${SOURCE_FILES}) add_custom_target(GENERATE_UI_HEADERS COMMAND ${CMAKE_SOURCE_DIR}/tools/prebuild.sh "${CMAKE_SOURCE_DIR}" BYPRODUCTS - ${CMAKE_SOURCE_DIR}/thirdparty/scintilla/bin/scintilla.a - ${CMAKE_SOURCE_DIR}/thirdparty/lexilla/bin/liblexilla.a - ${CMAKE_SOURCE_DIR}/thirdparty/libssh2-1.10.0/src/libssh2.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/memwatch/memwatch.c + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/scintilla.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/liblexilla.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libgpg-error.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libgcrypt.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libssh2.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libz.a ) add_dependencies(${CMAKE_PROJECT_NAME} GENERATE_UI_HEADERS) @@ -77,10 +82,7 @@ include_directories( ${PROJECT_BINARY_DIR} include ui/generated - thirdparty/libssh2-1.10.0/include - thirdparty/scintilla/include - thirdparty/lexilla/include - thirdparty/memwatch + thirdparty-installed/include ) add_definitions( @@ -98,16 +100,16 @@ target_link_directories(${CMAKE_PROJECT_NAME} PUBLIC target_link_libraries(${CMAKE_PROJECT_NAME} -rdynamic - ${CMAKE_SOURCE_DIR}/thirdparty/scintilla/bin/scintilla.a - ${CMAKE_SOURCE_DIR}/thirdparty/lexilla/bin/liblexilla.a - ${CMAKE_SOURCE_DIR}/thirdparty/libssh2-1.10.0/src/libssh2.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/scintilla.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/liblexilla.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libssh2.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libgcrypt.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libgpg-error.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libz.a ${GTK3_LIBRARIES} -# -lgpg-error # -lssl -# -lcrypto -# -ldl -# -pthread -# -lz + -ldl + -pthread -lm -lstdc++ ) diff --git a/com.kangaroopunch.JoeyDev.yaml b/com.kangaroopunch.JoeyDev.yaml index 53ccee3..efdaa55 100644 --- a/com.kangaroopunch.JoeyDev.yaml +++ b/com.kangaroopunch.JoeyDev.yaml @@ -36,27 +36,7 @@ modules: dest: tools - type: dir - path: thirdparty/memwatch - dest: thirdparty/memwatch - - - type: file - path: thirdparty/stb_ds.h - dest: thirdparty/ - - - type: file - path: thirdparty/stb_image.h - dest: thirdparty/ - - - type: file - path: thirdparty/scintilla531.tgz - dest: thirdparty/ - - - type: file - path: thirdparty/lexilla520.tgz - dest: thirdparty/ - - - type: file - path: thirdparty/libssh2-1.10.0.tar.gz + path: thirdparty/ dest: thirdparty/ - type: file diff --git a/include/ssh.h b/include/ssh.h new file mode 100644 index 0000000..cd783f7 --- /dev/null +++ b/include/ssh.h @@ -0,0 +1,55 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef SSH_H +#define SSH_H + + +#include "common.h" + + +struct SSHS; + + +typedef void (*SSHCallback)(struct SSHS*); + + +typedef struct SSHS { + LIBSSH2_SESSION *session; + LIBSSH2_CHANNEL *channel; + int sock; + int result; + gboolean finished; + char *title; + SSHCallback callback; + GtkWidget *status; +} SSHT; + + +SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password); +void sshDisconnect(SSHT **sshData); +int sshExecute(SSHT *sshData, char *command, char **output); +void sshShutdown(void); +void sshStartup(void); + + +#endif // SSH_H diff --git a/src/ssh.c b/src/ssh.c new file mode 100644 index 0000000..2d0e720 --- /dev/null +++ b/src/ssh.c @@ -0,0 +1,320 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include +#include +#include + +#include "libssh2.h" +#include "libssh2_sftp.h" + +#include "ssh.h" +#include "utils.h" +#include "array.h" + + +#ifdef _WIN32 +#define socketclose closesocket +closesocket(data->sock); +#else +#define socketclose close +#endif + + +static SSHT **_activeSSHs = NULL; + + +gboolean sshUpdate(gpointer userData); // Not static +static int sshWaitSocket(int socket_fd, LIBSSH2_SESSION *session); + + +SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) { + int rc; + unsigned long hostaddr; + struct sockaddr_in sin; + SSHT *data = NULL; + + data = NEW(SSHT); + + if (data) { + hostaddr = inet_addr(hostname); + data->sock = socket(AF_INET, SOCK_STREAM, 0); + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = hostaddr; + if (connect(data->sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) { + debug("Failed to connect!\n"); + DEL(data); + return NULL; + } + + data->session = libssh2_session_init(); + if (!data->session) { + socketclose(data->sock); + DEL(data); + return NULL; + } + + libssh2_session_set_blocking(data->session, 0); + + while ((rc = libssh2_session_handshake(data->session, data->sock)) == LIBSSH2_ERROR_EAGAIN) + ; + if (rc) { + printf("Failure establishing SSH session: %d\n", rc); + libssh2_session_free(data->session); + socketclose(data->sock); + DEL(data); + return NULL; + } + + while ((rc = libssh2_userauth_password(data->session, user, password)) == LIBSSH2_ERROR_EAGAIN) + ; + if (rc) { + debug("Failure authenticating SSH session: %d\n", rc); + while(libssh2_session_disconnect(data->session, "Error") == LIBSSH2_ERROR_EAGAIN) + ; + libssh2_session_free(data->session); + socketclose(data->sock); + DEL(data); + return NULL; + } + } + + return data; +} + + +void sshDisconnect(SSHT **sshData) { + SSHT *data = *sshData; + + libssh2_session_disconnect(data->session, "Normal Shutdown."); + libssh2_session_free(data->session); + socketclose(data->sock); + + DEL(data); +} + + +int sshExecute(SSHT *sshData, char *command, char **output) { + int rc; + unsigned char buffer[0x4000]; + int exitcode = 127; + char *exitsignal = (char *)"none"; + int outputLen = 0; + + utilEnsureBufferSize((unsigned char **)output, &outputLen, 1024); + *output[0] = 0; + + while ((sshData->channel = libssh2_channel_open_session(sshData->session)) == NULL && libssh2_session_last_error(sshData->session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(sshData->sock, sshData->session); + } + if (sshData->channel == NULL) { + return exitcode; + } + while((rc = libssh2_channel_exec(sshData->channel, command)) == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(sshData->sock, sshData->session); + } + if (rc != 0) { + return exitcode; + } + + for (;;) { + do { + rc = libssh2_channel_read(sshData->channel, (char *)buffer, sizeof(buffer)); + if (rc > 0) { + utilEnsureBufferSize((unsigned char **)output, &outputLen, strlen((const char *)*output) + rc); + strncat(*output, (char *)buffer, rc); + } + } while (rc > 0); + + if (rc == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(sshData->sock, sshData->session); + } else { + break; + } + } + + while ((rc = libssh2_channel_close(sshData->channel)) == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(sshData->sock, sshData->session); + } + if (rc == 0) { + exitcode = libssh2_channel_get_exit_status(sshData->channel); + libssh2_channel_get_exit_signal(sshData->channel, &exitsignal, NULL, NULL, NULL, NULL, NULL); + } + + libssh2_channel_free(sshData->channel); + + return exitcode; +} + + +SSHT *sshExecuteVerbose(SSHT *sshData, char *title, char *command, SSHCallback callback) { + int rc; + + sshData->title = strdup(title); + sshData->callback = callback; + sshData->finished = FALSE; + + while ((sshData->channel = libssh2_channel_open_session(sshData->session)) == NULL && libssh2_session_last_error(sshData->session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(sshData->sock, sshData->session); + } + if (sshData->channel == NULL) { + return NULL; + } + while ((rc = libssh2_channel_exec(sshData->channel, command)) == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(sshData->sock, sshData->session); + } + if (rc != 0) { + return NULL; + } + + //***TODO*** SSH Progress Dialog Here + //sshData->status = new SSHStatus(sshData); + arrpush(_activeSSHs, sshData); + + return sshData; +} + + +void sshShutdown(void) { + //curl_multi_cleanup(_curlMulti); + //curl_global_cleanup(); + + libssh2_exit(); + + g_idle_remove_by_data(sshUpdate); +} + + +void sshStartup(void) { + int err; + + //curl_global_init(CURL_GLOBAL_ALL); + //_curlMulti = curl_multi_init(); + +#ifdef WIN32 + err = WSAStartup(MAKEWORD(2, 0), &_wsadata); + if (err != 0) { + printf("WSAStartup failed with error: %d\n", err); + } +#endif + + err = libssh2_init(0); + if (err != 0) { + printf("libssh2 initialization failed: %d\n", err); + } + + g_idle_add(sshUpdate, sshUpdate); +} + + +gboolean sshUpdate(gpointer userData) { + int rc; + char buffer[0x4000]; + int exitcode = 127; + char *exitsignal = (char *)"none"; + char *output = NULL; + int outputLen = 0; + SSHT *s; + int i; + + (void)userData; + + utilEnsureBufferSize((unsigned char **)&output, &outputLen, 1024); + output[0] = 0; + + for (i=0; ifinished) { + rc = libssh2_channel_read(s->channel, buffer, sizeof(buffer)); + if (rc > 0) { + utilEnsureBufferSize((unsigned char **)&output, &outputLen, rc + 1); + output[0] = 0; + strncat(output, (char *)buffer, rc); + //***TODO*** Display in status dialog + //s->status->AddOutput(output); + } else { + if (rc == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(s->sock, s->session); + } else { + while ((rc = libssh2_channel_close(s->channel)) == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(s->sock, s->session); + } + DEL(output); + output = strdup("\n\nUH OH! Something wrong happened. Check the output for errors."); + if (rc == 0) { + exitcode = libssh2_channel_get_exit_status(s->channel); + libssh2_channel_get_exit_signal(s->channel, &exitsignal, NULL, NULL, NULL, NULL, NULL); + if (exitcode == 0) { + DEL(output); + output = strdup("\n\nFINISHED! You can close this window anytime."); + } + } + //***TODO*** Display in status dialog + //s->status->AddOutput(output); + libssh2_channel_free(s->channel); + s->result = exitcode; + //s->finished = true; + //s->status->Finished(); // No close + if (s->callback) s->callback(s); + arrdel(_activeSSHs, i); + break; // Exit for loop + // We don't delete "s" because it will be handled by utilSSHDisconnect + } + } + } + } + + return G_SOURCE_CONTINUE; +} + + +static int sshWaitSocket(int socket_fd, LIBSSH2_SESSION *session) { + struct timeval timeout; + int rc; + fd_set fd; + fd_set *writefd = NULL; + fd_set *readfd = NULL; + int dir; + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + FD_ZERO(&fd); + FD_SET(socket_fd, &fd); + + // Make sure we wait in the correct direction. + dir = libssh2_session_block_directions(session); + + if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) { + readfd = &fd; + } + + if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) { + writefd = &fd; + } + + rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout); + + return rc; +} diff --git a/thirdparty/libgcrypt-1.10.1.tar.bz2 b/thirdparty/libgcrypt-1.10.1.tar.bz2 new file mode 100644 index 0000000..86d2d88 --- /dev/null +++ b/thirdparty/libgcrypt-1.10.1.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef14ae546b0084cd84259f61a55e07a38c3b53afc0f546bffcef2f01baffe9de +size 3778457 diff --git a/thirdparty/libgpg-error-1.46.tar.bz2 b/thirdparty/libgpg-error-1.46.tar.bz2 new file mode 100644 index 0000000..320a138 --- /dev/null +++ b/thirdparty/libgpg-error-1.46.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7e11a64246bbe5ef37748de43b245abd72cfcd53c9ae5e7fc5ca59f1c81268d +size 1014291 diff --git a/thirdparty/memwatch.tar.bz2 b/thirdparty/memwatch.tar.bz2 new file mode 100644 index 0000000..6f23f40 --- /dev/null +++ b/thirdparty/memwatch.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6734fc1a104f195d686c4b75ea078cb06fa5c9e6b8120546958c4b4bf5407156 +size 35878 diff --git a/thirdparty/memwatch/FAQ b/thirdparty/memwatch/FAQ deleted file mode 100644 index efcec58..0000000 --- a/thirdparty/memwatch/FAQ +++ /dev/null @@ -1,133 +0,0 @@ -Frequently Asked Questions for memwatch - -Q. I'm not getting any log file! What's wrong?? - -A. Did you define MEMWATCH when compiling all files? - Did you include memwatch.h in all the files? - If you did, then...: - - Memwatch creates the file when it initializes. If you're not - getting the log file, it's because a) memwatch is not - initializing or b) it's initializing, but can't create the - file. - - Memwatch has two functions, mwInit() and mwTerm(), that - initialize and terminate memwatch, respectively. They are - nestable. You USUALLY don't need to call mwInit() and - mwTerm(), since memwatch will auto-initialize on the first - call to a memory function, and then add mwTerm() to the - atexit() list. - - You can call mwInit() and mwTerm() manually, if it's not - initializing properly or if your system doesn't support - atexit(). Call mwInit() as soon as you can, and mwTerm() at - the logical no-error ending of your program. Call mwAbort() - if the program is stopping due to an error; this will - terminate memwatch even if more than one call to mwTerm() is - outstanding. - - If you are using C++, remember that global and static C++ - objects constructors execute before main() when considering - where to put mwInit(). Also, their destructors execute after - main(). You may want to create a global object very early - with mwInit() in the constructor and mwTerm() in the - destructor. Too bad C++ does not guarantee initialization - order for global objects. - - If this didn't help, try adding a call to mwDoFlush(1) after - mwInit(). If THAT didn't help, then memwatch is unable to - create the log file. Check write permissions. - - If you can't use a log file, you can still use memwatch by - redirecting the output to a function of your choice. See the - next question. - -Q. I'd like memwatch's output to pipe to my fave debugger! How? - -A. Call mwSetOutFunc() with the address of a "void func(int c)" - function. You should also consider doing something about - the ARI handler, see memwatch.h for more details about that. - -Q. Why isn't there any C++ support? - -A. Because C++ is for sissies! =) Just kidding. - C++ comes with overridable allocation/deallocation - built-in. You can define your own new/delete operators - for any class, and thus circumvent memwatch, or confuse - it to no end. Also, the keywords "new" and "delete" may - appear in declarations in C++, making the preprocessor - replacement approach shaky. You can do it, but it's not - very stable. - - If someone were to write a rock solid new/delete checker - for C++, there is no conflict with memwatch; use them both. - -Q. I'm getting "WILD free" errors, but the code is bug-free! - -A. If memwatch's free() recieves a pointer that wasn't allocated - by memwatch, a "WILD free" message appears. If the source of - the memory buffer is outside of memwatch (a non-standard - library function, for instance), you can use mwFree_() to - release it. mwFree_() calls free() on the pointer given if - memwatch can't recognize it, instead of blocking it. - - Another source of "WILD free" messages is that if memwatch - is terminated before all memory allocated is freed, memwatch - will have forgotten about it, and thus generate the errors. - This is commonly caused by having memwatch auto-initialize, - and then using atexit() to clean up. When auto-initializing, - memwatch registers mwTerm() with atexit(), but if mwTerm() - runs before all memory is freed, then you will get "unfreed" - and "WILD free" messages when your own atexit()-registered - cleanup code runs, and frees the memory. - -Q. I'm getting "unfreed" errors, but the code is bug-free! - -A. You can get erroneous "unfreed" messages if memwatch - terminates before all memory has been freed. Try using - mwInit() and mwTerm() instead of auto-initialization. - - If you _are_ using mwInit() and mwTerm(), it may be that - some code in your program executes before mwInit() or - after mwTerm(). Make sure that mwInit() is the first thing - executed, and mwTerm() the last. - -Q. When compiling memwatch I get these 'might get clobbered' - errors, and something about a longjmp() inside memwatch. - -A. When using gcc or egcs with the optimization to inline - functions, this warning occurs. This is because gcc and - egcs inlines memwatch's functions with setjmp/longjmp, - causing the calling functions to become unstable. - - The gcc/egcs maintainers have been informed of this - problem, but until they modify the inline optimization - so that it leaves setjmp functions alone, make sure to - compile memwatch without inline function optimizations. - - gcc 2.95.2 can be patched for this, and I have been told - it will be fixed in an upcoming version. - -Q. My program crashes with SIGSEGV or alignment errors, but - only when I compile with memwatch enabled! - -A. You are using a 64-bit (or higher) platform, and memwatch - was unable to detect and adjust for this. You'll have to - either compile with a suitable define for mwROUNDALLOC, - I suggest (number of bits / 8), or define mwROUNDALLOC - directly in memwatch.c. - - Also, please check your limits.h file for the relevant - #defines, and tell me what they are. - -Q. When I include string.h after memwatch.h, I get errors - related to strdup(), what gives? - -A. Most, but probably not all, platforms are nice about - including files multiple times, so I could probably - avoid these errors by including string.h from memwatch.h. - But since I want to be on the safe side, I don't. - - To fix this, simply include string.h before memwatch.h, - or modify memwatch.h to include string.h. - diff --git a/thirdparty/memwatch/Makefile b/thirdparty/memwatch/Makefile deleted file mode 100644 index bc1be19..0000000 --- a/thirdparty/memwatch/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -test: - $(CC) -DMEMWATCH -DMW_STDIO test.c memwatch.c diff --git a/thirdparty/memwatch/README b/thirdparty/memwatch/README deleted file mode 100644 index aeb86ce..0000000 --- a/thirdparty/memwatch/README +++ /dev/null @@ -1,99 +0,0 @@ -README for MEMWATCH 2.69 - - This file should be enough to get you started, and should be - enough for small projects. For more info, see the files USING - and the FAQ. If this is not enough, see memwatch.h, which is - well documented. - - Memwatch is licensed under the GPL from version 2.69 - onwards. Please read the file gpl.txt for more details. - - If you choose to use memwatch to validate your projects, I - would like to hear about it. Please drop me a line at - johan@linkdata.se about the project itself, the hardware, - operating system, compiler and any URL(s) you feel is - appropriate. - -***** To run the test program: - - Look at the source code for test.c first. It does some really - nasty things, and I want you to be aware of that. If memwatch - can't capture SIGSEGV (General Protection Fault for Windoze), - your program will dump core (crash for Windoze). - - Once you've done that, you can build the test program. - - Linux and other *nixes with gcc: - - gcc -o test -DMEMWATCH -DMEMWATCH_STDIO test.c memwatch.c - - Windows 95, Windows NT with MS Visual C++: - - cl -DMEMWATCH -DMEMWATCH_STDIO test.c memwatch.c - - Then simply run the test program. - - ./test - - -***** Quick-start instructions: - - 1. Make sure that memwatch.h is included in all of the - source code files. If you have an include file that - all of the source code uses, you might be able to include - memwatch.h from there. - - 2. Recompile the program with MEMWATCH defined. See your - compiler's documentation if you don't know how to do this. - The usual switch looks like "-DMEMWATCH". To have MEMWATCH - use stderr for some output (like, "Abort, Retry, Ignore?"), - please also define MW_STDIO (or MEMWATCH_STDIO, same thing). - - 3. Run the program and examine the output in the - log file "memwatch.log". If you didn't get a log file, - you probably didn't do step 1 and 2 correctly, or your - program crashed before memwatch flushed the file buffer. - To have memwatch _always_ flush the buffer, add a call - to "mwDoFlush(1)" at the top of your main function. - - 4. There is no fourth step... but remember that there - are limits to what memwatch can do, and that you need - to be aware of them: - -***** Limits to memwatch: - - Memwatch cannot catch all wild pointer writes. It can catch - those it could make itself due to your program trashing - memwatch's internal data structures. It can catch, sort of, - wild writes into No Mans Land buffers (see the header file for - more info). Anything else and you're going to get core dumped, - or data corruption if you're lucky. - - There are other limits of course, but that one is the most - serious one, and the one that you're likely to be suffering - from. - -***** Can use memwatch with XXXXX? - - Probably the answer is yes. It's been tested with several - different platforms and compilers. It may not work on yours - though... but there's only one way to find out. - -***** Need more assistance? - - I don't want e-mail on "how to program in C", or "I've got a - bug, help me". I _do_ want you to send email to me if you - find a bug in memwatch, or if it won't compile cleanly on your - system (assuming it's an ANSI-C compiler of course). - - If you need help with using memwatch, read the header file. - If, after reading the header file, you still can't resolve the - problem, please mail me with the details. - - I can be reached at "johan@linkdata.se". - - The latest version of memwatch should be found at - "http://www.linkdata.se/". - - Johan Lindh - diff --git a/thirdparty/memwatch/USING b/thirdparty/memwatch/USING deleted file mode 100644 index 3d78e95..0000000 --- a/thirdparty/memwatch/USING +++ /dev/null @@ -1,213 +0,0 @@ -Using memwatch -============== - -What is it? - - Memwatch is primarily a memory leak detector for C. Besides - detecting leaks, it can do a bunch of other stuff, but lets - stay to the basics. If you _really_ want to know all the - gory details, you should check out the header file, - memwatch.h, and the source code. It's actually got some - comments! (Whoa, what a concept!) - -How do I get the latest version? - - http://www.linkdata.se/sourcecode.html - ftp://ftp.linkdata.se/pub/memwatch/ - -How does it work? - - Using the C preprocessor, memwatch replaces all your - programs calls to ANSI C memory allocation functions with - calls to it's own functions, which keeps a record of all - allocations. - - Memwatch is very unobtrusive; unless the define MEMWATCH is - defined, memwatch removes all traces of itself from the - code (using the preprocessor). - - Memwatch normally writes it's data to the file - memwatch.log, but this can be overridden; see the section - on I/O, later. - -Can I use it for my C++ sources? - - You can, but it's not recommended. C++ allows individual - classes to have their own memory management, and the - preprocessor approach used by memwatch can cause havoc - with such class declarations if improperly used. - - If you have no such classes, or have them but still want - to test it, you can give it a try. - - First, re-enable the C++ support code in memwatch. - If you can't find it, you probably shouldn't be using - it. Then, in your source code, after including ALL - header files: - - #define new mwNew - #define delete mwDelete - - This will cause calls to new and delete in that source file - to be directed to memwatch. Also, be sure to read all the - text in memwatch.h regarding C++ support. - -Is this stuff thread-safe? - - I doubt it. As of version 2.66, there is rudimentary support - for threads, if you happen to be using Win32 or if you have - pthreads. Define WIN32 or MW_PTHREADS to signify this fact. - - This will cause a global mutex to be created, and memwatch - will lock it when accessing the global memory chain, but it's - still far from certified threadsafe. - -Initialization and cleanup - - In order to do it's work in a timely fashion, memwatch - needs to do some startup and cleanup work. mwInit() - initializes memwatch and mwTerm() terminates it. Memwatch - can auto-initialize, and will do so if you don't call - mwInit() yourself. If this is the case, memwatch will use - atexit() to register mwTerm() to the atexit-queue. - - The auto-init technique has a caveat; if you are using - atexit() yourself to do cleanup work, memwatch may - terminate before your program is done. To be on the safe - side, use mwInit() and mwTerm(). - - mwInit() and mwTerm() is nestable, so you can call mwInit() - several times, requiring mwTerm() to be called an equal - number of times to terminate memwatch. - - In case of the program aborting in a controlled way, you - may want to call mwAbort() instead of mwTerm(). mwAbort() - will terminate memwatch even if there are outstanding calls - to mwTerm(). - -I/O operations - - During normal operations, memwatch creates a file named - memwatch.log. Sometimes, memwatch.log can't be created; - then memwatch tries to create files name memwatNN.log, - where NN is between 01 and 99. If that fails, no log will - be produced. - - If you can't use a file log, or don't want to, no worry. - Just call mwSetOutFunc() with the address of a "void - func(int c)" function, and all output will be directed - there, character by character. - - Memwatch also has an Abort/Retry/Ignore handler that is - used when an ASSERT or VERIFY fails. The default handler - does no I/O, but automatically aborts the program. You can - use any handler you want; just send the address of a "int - func(const char*)" to mwSetAriFunc(). For more details on - that, see memwatch.h. - -TRACE/ASSERT/VERIFY macros - - Memwatch defines (if not already defined) the macros TRACE, - ASSERT and VERIFY. If you are already using macros with - these names, memwatch 2.61 and later will not override - them. Memwatch 2.61 and later will also always define the - macros mwTRACE, mwASSERT and mwVERIFY, so you can use these - to make sure you're talking to memwatch. Versions prior - to 2.61 will *OVERRIDE* existing TRACE, ASSERT and VERIFY. - - To make sure that existing TRACE, ASSERT and VERIFY macros - are preserved, you can define MW_NOTRACE, MW_NOASSERT and - MW_NOVERIFY. All versions of memwatch will abide by these. - -How slow can you go? - - Memwatch slows things down. Large allocations aren't - affected so that you can measure it, but small allocations - that would utilize a compilers small-allocator function - suddenly cannot, and so gets slowed down alot. As a worst - case, expect it to be 3-5 times slower. - - Free'ing gets hit worse, I'm afraid, as memwatch checks - a lot of stuff when freeing. Expect it to be 5-7 times - slower, no matter what the size of the allocation. - -Stress-testing the application - - You can simulate low-memory conditions using mwLimit(). - mwLimit() takes the maximum number of bytes to be - allocated; when the limit is hit, allocation requests will - fail, and a "limit" message will be logged. - - If you hit a real low-memory situation, memwatch logs that - too. Memwatch itself has some reserve memory tucked away so - it should continue running even in the worst conditions. - -Hunting down wild writes and other Nasty Things - - Wild writes are usually caused by using pointers that arent - initialized, or that were initialized, but then the memory - they points to is moved or freed. The best way to avoid - these kind of problems is to ALWAYS initialize pointers to - NULL, and after freeing a memory buffer, setting all - pointers that pointed to it to NULL. - - To aid in tracking down uninitialized pointers memwatch - zaps all memory with certain values. Recently allocated - memory (unless calloc'd, of course), contains 0xFE. - Recently freed memory contains 0xFD. So if your program - crashes when using memwatch and not without memwatch, it's - most likely because you are not initializing your allocated - buffers, or using the buffers after they've been freed. - - In the event that a wild pointer should damage memwatch's - internal data structures, memwatch employs checksums, - multiple copies of some values, and can also repair it's - own data structures. - - If you are a paranoid person, and as programmer you should - be, you can use memwatch's mwIsReadAddr() and - mwIsSafeAddr() functions to check the accessibility of - memory. These are implemented for both ANSI C systems and - Win32 systems. Just put an mwASSERT() around the check and - forget about it. - -Can I help? - - Well, sure. For instance, I like memwatch to compile - without any warnings or errors. If you are using an ANSI C - compliant compiler, and are getting warnings or errors, - please mail me the details and instructions on how to fix - them, if you can. - - Another thing you can do if you decide to use memwatch is - to mail me the name of the project(s) (and URL, if any), - hardware and operating system, compiler and what user - (organization). I will then post this info on the list of - memwatch users. - (http://www.linkdata.se/memwatchusers.html) - -Top five problems using memwatch - - 5. Passed a non-memwatch allocated pointer to memwatch's - free(). Symtom: Causes an erroneous "WILD free" log - entry to appear. Cure: Either include memwatch.h for - the file that allocates, or use mwFree_() to free it. - - 4. Relied on auto-initialization when using atexit(). - Symptom: Causes incorrect "unfreed" and "WILD free" - messages. Cure: Use mwInit() and mwTerm(). - - 3. Forgot to include memwatch.h in all files. Symptom: - Tends to generate "WILD free" and "unfreed" messages. - Cure: Make sure to include memwatch.h! - - 2. No write permissions in currect directory. Symptom: - Seems like memwatch 'just aint working'. Cure: Use - mwSetOutFunc() to redirect output. - - ...and the number one problem is... - - 1. Didn't define MEMWATCH when compiling. Symptom: - Memwatch dutifully disables itself. Cure: Try adding - -DMEMWATCH to the command line. - diff --git a/thirdparty/memwatch/gpl.txt b/thirdparty/memwatch/gpl.txt deleted file mode 100644 index 5b6e7c6..0000000 --- a/thirdparty/memwatch/gpl.txt +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/thirdparty/memwatch/memwatch.c b/thirdparty/memwatch/memwatch.c deleted file mode 100644 index ae0f6ab..0000000 --- a/thirdparty/memwatch/memwatch.c +++ /dev/null @@ -1,2664 +0,0 @@ -/* -** MEMWATCH.C -** Nonintrusive ANSI C memory leak / overwrite detection -** Copyright (C) 1992-2003 Johan Lindh -** All rights reserved. -** Version 2.71 - - This file is part of MEMWATCH. - - MEMWATCH is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - MEMWATCH 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 - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MEMWATCH; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -** -** 920810 JLI [1.00] -** 920830 JLI [1.10 double-free detection] -** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit] -** 921022 JLI [1.20 ASSERT and VERIFY] -** 921105 JLI [1.30 C++ support and TRACE] -** 921116 JLI [1.40 mwSetOutFunc] -** 930215 JLI [1.50 modified ASSERT/VERIFY] -** 930327 JLI [1.51 better auto-init & PC-lint support] -** 930506 JLI [1.55 MemWatch class, improved C++ support] -** 930507 JLI [1.60 mwTest & CHECK()] -** 930809 JLI [1.65 Abort/Retry/Ignore] -** 930820 JLI [1.70 data dump when unfreed] -** 931016 JLI [1.72 modified C++ new/delete handling] -** 931108 JLI [1.77 mwSetAssertAction() & some small changes] -** 940110 JLI [1.80 no-mans-land alloc/checking] -** 940328 JLI [2.00 version 2.0 rewrite] -** Improved NML (no-mans-land) support. -** Improved performance (especially for free()ing!). -** Support for 'read-only' buffers (checksums) -** ^^ NOTE: I never did this... maybe I should? -** FBI (free'd block info) tagged before freed blocks -** Exporting of the mwCounter variable -** mwBreakOut() localizes debugger support -** Allocation statistics (global, per-module, per-line) -** Self-repair ability with relinking -** 950913 JLI [2.10 improved garbage handling] -** 951201 JLI [2.11 improved auto-free in emergencies] -** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()] -** 960514 JLI [2.12 undefining of existing macros] -** 960515 JLI [2.13 possibility to use default new() & delete()] -** 960516 JLI [2.20 suppression of file flushing on unfreed msgs] -** 960516 JLI [2.21 better support for using MEMWATCH with DLL's] -** 960710 JLI [X.02 multiple logs and mwFlushNow()] -** 960801 JLI [2.22 merged X.01 version with current] -** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's] -** 960805 JLI [2.31 merged X.02 version with current] -** 961002 JLI [2.32 support for realloc() + fixed STDERR bug] -** 961222 JLI [2.40 added mwMark() & mwUnmark()] -** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY] -** 970113 JLI [2.42 added support for PC-Lint 7.00g] -** 970207 JLI [2.43 added support for strdup()] -** 970209 JLI [2.44 changed default filename to lowercase] -** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers] -** 970723 JLI [2.46 added MW_ARI_NULLREAD flag] -** 970813 JLI [2.47 stabilized marker handling] -** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway] -** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support] -** 980417 JLI [2.51 more checks for invalid addresses] -** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting] -** 990112 JLI [2.53 added check for empty heap to mwIsOwned] -** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML] -** 990224 JLI [2.56 changed ordering of members in structures] -** 990303 JLI [2.57 first maybe-fixit-for-hpux test] -** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit] -** 990517 JLI [2.59 fixed some high-sensitivity warnings] -** 990610 JLI [2.60 fixed some more high-sensitivity warnings] -** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names] -** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()] -** 991007 JLI [2.63 first shot at a 64-bit compatible version] -** 991009 JLI [2.64 undef's strdup() if defined, mwStrdup made const] -** 000704 JLI [2.65 added some more detection for 64-bits] -** 010502 JLI [2.66 incorporated some user fixes] -** [mwRelink() could print out garbage pointer (thanks mac@phobos.ca)] -** [added array destructor for C++ (thanks rdasilva@connecttel.com)] -** [added mutex support (thanks rdasilva@connecttel.com)] -** 010531 JLI [2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined] -** 010619 JLI [2.68 fix: mwRealloc() could leave the mutex locked] -** 020918 JLI [2.69 changed to GPL, added C++ array allocation by Howard Cohen] -** 030212 JLI [2.70 mwMalloc() bug for very large allocations (4GB on 32bits)] -** 030520 JLI [2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)] -*/ - -#define __MEMWATCH_C 1 - -#ifdef MW_NOCPP -#define MEMWATCH_NOCPP -#endif -#ifdef MW_STDIO -#define MEMWATCH_STDIO -#endif - -/*********************************************************************** -** Include files -***********************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "memwatch.h" - -#ifndef toupper -#include -#endif - -#if defined(WIN32) || defined(__WIN32__) -#define MW_HAVE_MUTEX 1 -#include -#endif - -#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H) -#define MW_HAVE_MUTEX 1 -#include -#endif - -/*********************************************************************** -** Defines & other weird stuff -***********************************************************************/ - -/*lint -save -e767 */ -#define VERSION "2.71" /* the current version number */ -#define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line) -#define FLUSH() mwFlush() -#define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1) -#define PRECHK 0x01234567L -#define POSTCHK 0x76543210L -#define mwBUFFER_TO_MW(p) ( (mwData*) (void*) ( ((char*)p)-mwDataSize-mwOverflowZoneSize ) ) -/*lint -restore */ - -#define MW_NML 0x0001 - -#ifdef _MSC_VER -#define COMMIT "c" /* Microsoft C requires the 'c' to perform as desired */ -#else -#define COMMIT "" /* Normal ANSI */ -#endif /* _MSC_VER */ - -#ifdef __cplusplus -#define CPPTEXT "++" -#else -#define CPPTEXT "" -#endif /* __cplusplus */ - -#ifdef MEMWATCH_STDIO -#define mwSTDERR stderr -#else -#define mwSTDERR mwLog -#endif - -#ifdef MW_HAVE_MUTEX -#define MW_MUTEX_INIT() mwMutexInit() -#define MW_MUTEX_TERM() mwMutexTerm() -#define MW_MUTEX_LOCK() mwMutexLock() -#define MW_MUTEX_UNLOCK() mwMutexUnlock() -#else -#define MW_MUTEX_INIT() -#define MW_MUTEX_TERM() -#define MW_MUTEX_LOCK() -#define MW_MUTEX_UNLOCK() -#endif - -/*********************************************************************** -** If you really, really know what you're doing, -** you can predefine these things yourself. -***********************************************************************/ - -#ifndef mwBYTE_DEFINED -# if CHAR_BIT != 8 -# error need CHAR_BIT to be 8! -# else -typedef unsigned char mwBYTE; -# define mwBYTE_DEFINED 1 -# endif -#endif - -#if defined(ULONGLONG_MAX) || defined(ULLONG_MAX) || defined(_UI64_MAX) || defined(ULONG_LONG_MAX) -# define mw64BIT 1 -# define mwROUNDALLOC_DEFAULT 8 -#else -# if UINT_MAX <= 0xFFFFUL -# define mw16BIT 1 -# define mwROUNDALLOC_DEFAULT 2 -# else -# if ULONG_MAX > 0xFFFFFFFFUL -# define mw64BIT 1 -# define mwROUNDALLOC_DEFAULT 8 -# else -# define mw32BIT 1 -# define mwROUNDALLOC_DEFAULT 4 -# endif -# endif -#endif - -/* mwROUNDALLOC is the number of bytes to */ -/* round up to, to ensure that the end of */ -/* the buffer is suitable for storage of */ -/* any kind of object */ -#ifndef mwROUNDALLOC -# define mwROUNDALLOC mwROUNDALLOC_DEFAULT -#endif - -#ifndef mwDWORD_DEFINED -#if ULONG_MAX == 0xFFFFFFFFUL -typedef unsigned long mwDWORD; -#define mwDWORD_DEFINED "unsigned long" -#endif -#endif - -#ifndef mwDWORD_DEFINED -#if UINT_MAX == 0xFFFFFFFFUL -typedef unsigned int mwDWORD; -#define mwDWORD_DEFINED "unsigned int" -#endif -#endif - -#ifndef mwDWORD_DEFINED -#if USHRT_MAX == 0xFFFFFFFFUL -typedef unsigned short mwDWORD; -#define mwDWORD_DEFINED "unsigned short" -#endif -#endif - -#ifndef mwBYTE_DEFINED -#error "can't find out the correct type for a 8 bit scalar" -#endif - -#ifndef mwDWORD_DEFINED -#error "can't find out the correct type for a 32 bit scalar" -#endif - -/*********************************************************************** -** Typedefs & structures -***********************************************************************/ - -/* main data holding area, precedes actual allocation */ -typedef struct mwData_ mwData; -struct mwData_ { - mwData* prev; /* previous allocation in chain */ - mwData* next; /* next allocation in chain */ - const char* file; /* file name where allocated */ - long count; /* action count */ - long check; /* integrity check value */ -#if 0 - long crc; /* data crc value */ -#endif - size_t size; /* size of allocation */ - int line; /* line number where allocated */ - unsigned flag; /* flag word */ - }; - -/* statistics structure */ -typedef struct mwStat_ mwStat; -struct mwStat_ { - mwStat* next; /* next statistic buffer */ - const char* file; - long total; /* total bytes allocated */ - long num; /* total number of allocations */ - long max; /* max allocated at one time */ - long curr; /* current allocations */ - int line; - }; - -/* grabbing structure, 1K in size */ -typedef struct mwGrabData_ mwGrabData; -struct mwGrabData_ { - mwGrabData* next; - int type; - char blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ]; - }; - -typedef struct mwMarker_ mwMarker; -struct mwMarker_ { - void *host; - char *text; - mwMarker *next; - int level; - }; - -#if defined(WIN32) || defined(__WIN32__) -typedef HANDLE mwMutex; -#endif - -#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H) -typedef pthread_mutex_t mwMutex; -#endif - -/*********************************************************************** -** Static variables -***********************************************************************/ - -static int mwInited = 0; -static int mwInfoWritten = 1; -static int mwUseAtexit = 0; -static FILE* mwLog = NULL; -static int mwFlushing = 0; -static int mwStatLevel = MW_STAT_DEFAULT; -static int mwNML = MW_NML_DEFAULT; -static int mwFBI = 0; -static long mwAllocLimit = 0L; -static int mwUseLimit = 0; - -static long mwNumCurAlloc = 0L; -static mwData* mwHead = NULL; -static mwData* mwTail = NULL; -static int mwDataSize = 0; -static unsigned char mwOverflowZoneTemplate[] = "mEmwAtch"; -static int mwOverflowZoneSize = mwROUNDALLOC; - -static void (*mwOutFunction)(int) = NULL; -static int (*mwAriFunction)(const char*) = NULL; -static int mwAriAction = MW_ARI_ABORT; - -static char mwPrintBuf[MW_TRACE_BUFFER+8]; - -static unsigned long mwCounter = 0L; -static long mwErrors = 0L; - -static int mwTestFlags = 0; -static int mwTestAlways = 0; - -static FILE* mwLogB1 = NULL; -static int mwFlushingB1 = 0; - -static mwStat* mwStatList = NULL; -static long mwStatTotAlloc = 0L; -static long mwStatMaxAlloc = 0L; -static long mwStatNumAlloc = 0L; -static long mwStatCurAlloc = 0L; -static long mwNmlNumAlloc = 0L; -static long mwNmlCurAlloc = 0L; - -static mwGrabData* mwGrabList = NULL; -static long mwGrabSize = 0L; - -static void * mwLastFree[MW_FREE_LIST]; -static const char *mwLFfile[MW_FREE_LIST]; -static int mwLFline[MW_FREE_LIST]; -static int mwLFcur = 0; - -static mwMarker* mwFirstMark = NULL; - -static FILE* mwLogB2 = NULL; -static int mwFlushingB2 = 0; - -#ifdef MW_HAVE_MUTEX -static mwMutex mwGlobalMutex; -#endif - -/*********************************************************************** -** Static function declarations -***********************************************************************/ - -static void mwAutoInit( void ); -static FILE* mwLogR( void ); -/* static */ void mwLogW( FILE* ); -static int mwFlushR( void ); -static void mwFlushW( int ); -static void mwFlush( void ); -static void mwIncErr( void ); -static void mwUnlink( mwData*, const char* file, int line ); -static int mwRelink( mwData*, const char* file, int line ); -static int mwIsHeapOK( mwData *mw ); -static int mwIsOwned( mwData* mw, const char* file, int line ); -static int mwTestBuf( mwData* mw, const char* file, int line ); -static void mwDefaultOutFunc( int ); -static void mwWrite( const char* format, ... ); -static void mwLogFile( const char* name ); -static size_t mwFreeUp( size_t, int ); -static const void *mwTestMem( const void *, unsigned, int ); -static int mwStrCmpI( const char *s1, const char *s2 ); -static int mwTestNow( const char *file, int line, int always_invoked ); -static void mwDropAll( void ); -static const char *mwGrabType( int type ); -static unsigned mwGrab_( unsigned kb, int type, int silent ); -static unsigned mwDrop_( unsigned kb, int type, int silent ); -static int mwARI( const char* text ); -static void mwStatReport( void ); -static mwStat* mwStatGet( const char*, int, int ); -static void mwStatAlloc( size_t, const char*, int ); -static void mwStatFree( size_t, const char*, int ); -static int mwCheckOF( const void * p ); -static void mwWriteOF( void * p ); -static char mwDummy( char c ); -#ifdef MW_HAVE_MUTEX -static void mwMutexInit( void ); -static void mwMutexTerm( void ); -static void mwMutexLock( void ); -static void mwMutexUnlock( void ); -#endif - -/*********************************************************************** -** System functions -***********************************************************************/ - -void mwInit( void ) { - time_t tid; - - if( mwInited++ > 0 ) return; - - MW_MUTEX_INIT(); - - /* start a log if none is running */ - if( mwLogR() == NULL ) mwLogFile( "memwatch.log" ); - if( mwLogR() == NULL ) { - int i; - char buf[32]; - /* oops, could not open it! */ - /* probably because it's already open */ - /* so we try some other names */ - for( i=1; i<100; i++ ) { - sprintf( buf, "memwat%02d.log", i ); - mwLogFile( buf ); - if( mwLogR() != NULL ) break; - } - } - - /* initialize the statistics */ - mwStatList = NULL; - mwStatTotAlloc = 0L; - mwStatCurAlloc = 0L; - mwStatMaxAlloc = 0L; - mwStatNumAlloc = 0L; - mwNmlCurAlloc = 0L; - mwNmlNumAlloc = 0L; - - /* calculate the buffer size to use for a mwData */ - mwDataSize = sizeof(mwData); - while( mwDataSize % mwROUNDALLOC ) mwDataSize ++; - - /* write informational header if needed */ - if( !mwInfoWritten ) { - mwInfoWritten = 1; - (void) time( &tid ); - mwWrite( - "\n=============" - " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh " - "=============\n"); - mwWrite( "\nStarted at %s\n", ctime( &tid ) ); - -/**************************************************************** Generic */ - mwWrite( "Modes: " ); -#ifdef mwNew - mwWrite( "C++ " ); -#endif /* mwNew */ -#ifdef __STDC__ - mwWrite( "__STDC__ " ); -#endif /* __STDC__ */ -#ifdef mw16BIT - mwWrite( "16-bit " ); -#endif -#ifdef mw32BIT - mwWrite( "32-bit " ); -#endif -#ifdef mw64BIT - mwWrite( "64-bit " ); -#endif - mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" ); - mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n", - mwROUNDALLOC, sizeof(mwData), mwDataSize ); -/**************************************************************** Generic */ - -/************************************************************ Microsoft C */ -#ifdef _MSC_VER - mwWrite( "Compiled using Microsoft C" CPPTEXT - " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 ); -#endif /* _MSC_VER */ -/************************************************************ Microsoft C */ - -/************************************************************** Borland C */ -#ifdef __BORLANDC__ - mwWrite( "Compiled using Borland C" -#ifdef __cplusplus - "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 ); -#else - " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 ); -#endif /* __cplusplus */ -#endif /* __BORLANDC__ */ -/************************************************************** Borland C */ - -/************************************************************** Watcom C */ -#ifdef __WATCOMC__ - mwWrite( "Compiled using Watcom C %d.%02d ", - __WATCOMC__/100, __WATCOMC__%100 ); -#ifdef __FLAT__ - mwWrite( "(32-bit flat model)" ); -#endif /* __FLAT__ */ - mwWrite( "\n" ); -#endif /* __WATCOMC__ */ -/************************************************************** Watcom C */ - - mwWrite( "\n" ); - FLUSH(); - } - - if( mwUseAtexit ) (void) atexit( mwAbort ); - return; - } - -void mwAbort( void ) { - mwData *mw; - mwMarker *mrk; - char *data; - time_t tid; - int c, i, j; - int errors; - - tid = time( NULL ); - mwWrite( "\nStopped at %s\n", ctime( &tid) ); - - if( !mwInited ) - mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" ); - - /* release the grab list */ - mwDropAll(); - - /* report mwMarked items */ - while( mwFirstMark ) { - mrk = mwFirstMark->next; - mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text ); - free( mwFirstMark->text ); - free( mwFirstMark ); - mwFirstMark = mrk; - mwErrors ++; - } - - /* release all still allocated memory */ - errors = 0; - while( mwHead != NULL && errors < 3 ) { - if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) { - if( errors < 3 ) - { - errors ++; - mwWrite( "internal: NML/unfreed scan restarting\n" ); - FLUSH(); - mwHead = mwHead; - continue; - } - mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" ); - FLUSH(); - break; - } - mwFlushW(0); - if( !(mwHead->flag & MW_NML) ) { - mwErrors++; - data = ((char*)mwHead)+mwDataSize; - mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ", - mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+mwOverflowZoneSize ); - if( mwCheckOF( data ) ) { - mwWrite( "[underflowed] "); - FLUSH(); - } - if( mwCheckOF( (data+mwOverflowZoneSize+mwHead->size) ) ) { - mwWrite( "[overflowed] "); - FLUSH(); - } - mwWrite( " \t{" ); - j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size; - for( i=0;i<16;i++ ) { - if( i 126 ) c = '.'; - mwWrite( "%c", c ); - } - mwWrite( "}\n" ); - mw = mwHead; - mwUnlink( mw, __FILE__, __LINE__ ); - free( mw ); - } - else { - data = ((char*)mwHead) + mwDataSize + mwOverflowZoneSize; - if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) { - mwErrors++; - mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", - mwHead->count, data + mwOverflowZoneSize, mwHead->file, mwHead->line ); - FLUSH(); - } - mwNmlNumAlloc --; - mwNmlCurAlloc -= mwHead->size; - mw = mwHead; - mwUnlink( mw, __FILE__, __LINE__ ); - free( mw ); - } - } - - if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc ); - if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc ); - - /* report statistics */ - mwStatReport(); - FLUSH(); - - mwInited = 0; - mwHead = mwTail = NULL; - if( mwErrors ) - fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors); - mwLogFile( NULL ); - mwErrors = 0; - - MW_MUTEX_TERM(); - - } - -void mwTerm( void ) { - if( mwInited == 1 ) - { - mwAbort(); - return; - } - if( !mwInited ) - mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n"); - else - mwInited --; - } - -void mwStatistics( int level ) -{ - mwAutoInit(); - if( level<0 ) level=0; - if( mwStatLevel != level ) - { - mwWrite( "statistics: now collecting on a %s basis\n", - level<1?"global":(level<2?"module":"line") ); - mwStatLevel = level; - } -} - -void mwAutoCheck( int onoff ) { - mwAutoInit(); - mwTestAlways = onoff; - if( onoff ) mwTestFlags = MW_TEST_ALL; - } - -void mwSetOutFunc( void (*func)(int) ) { - mwAutoInit(); - mwOutFunction = func; - } - -static void mwWriteOF( void *p ) -{ - int i; - unsigned char *ptr; - ptr = (unsigned char*) p; - for( i=0; inext is not always set? -*/ -void * mwMark( void *p, const char *desc, const char *file, unsigned line ) { - mwMarker *mrk; - unsigned n, isnew; - char *buf; - int tot, oflow = 0; - char wherebuf[128]; - - mwAutoInit(); - TESTS(NULL,0); - - if( desc == NULL ) desc = "unknown"; - if( file == NULL ) file = "unknown"; - - tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line ); - if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; } - - if( p == NULL ) { - mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc ); - return p; - } - - if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) ) - { - mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n", - file, line, mwFirstMark, desc ); - return p; - } - - for( mrk=mwFirstMark; mrk; mrk=mrk->next ) - { - if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) ) - { - mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n", - file, line, mrk, mrk->next, desc ); - return p; - } - if( mrk->host == p ) break; - } - - if( mrk == NULL ) { - isnew = 1; - mrk = (mwMarker*) malloc( sizeof( mwMarker ) ); - if( mrk == NULL ) { - mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); - return p; - } - mrk->next = NULL; - n = 0; - } - else { - isnew = 0; - n = strlen( mrk->text ); - } - - n += strlen( wherebuf ); - buf = (char*) malloc( n+3 ); - if( buf == NULL ) { - if( isnew ) free( mrk ); - mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); - return p; - } - - if( isnew ) { - memcpy( buf, wherebuf, n+1 ); - mrk->next = mwFirstMark; - mrk->host = p; - mrk->text = buf; - mrk->level = 1; - mwFirstMark = mrk; - } - else { - strcpy( buf, mrk->text ); - strcat( buf, ", " ); - strcat( buf, wherebuf ); - free( mrk->text ); - mrk->text = buf; - mrk->level ++; - } - - if( oflow ) { - mwIncErr(); - mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); - } - return p; - } - -void* mwUnmark( void *p, const char *file, unsigned line ) { - mwMarker *mrk, *prv; - mrk = mwFirstMark; - prv = NULL; - while( mrk ) { - if( mrk->host == p ) { - if( mrk->level < 2 ) { - if( prv ) prv->next = mrk->next; - else mwFirstMark = mrk->next; - free( mrk->text ); - free( mrk ); - return p; - } - mrk->level --; - return p; - } - prv = mrk; - mrk = mrk->next; - } - mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p ); - return p; - } - - -/*********************************************************************** -** Abort/Retry/Ignore handlers -***********************************************************************/ - -static int mwARI( const char *estr ) { - char inbuf[81]; - int c; - fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr); - (void) fgets(inbuf,sizeof(inbuf),stdin); - for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ; - c = inbuf[c]; - if( c == 'R' || c == 'r' ) { - mwBreakOut( estr ); - return MW_ARI_RETRY; - } - if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE; - return MW_ARI_ABORT; - } - -/* standard ARI handler (exported) */ -int mwAriHandler( const char *estr ) { - mwAutoInit(); - return mwARI( estr ); - } - -/* used to set the ARI function */ -void mwSetAriFunc( int (*func)(const char *) ) { - mwAutoInit(); - mwAriFunction = func; - } - -/*********************************************************************** -** Allocation handlers -***********************************************************************/ - -void* mwMalloc( size_t size, const char* file, int line) { - size_t needed; - mwData *mw; - char *ptr; - void *p; - - mwAutoInit(); - - MW_MUTEX_LOCK(); - - TESTS(file,line); - - mwCounter ++; - needed = mwDataSize + mwOverflowZoneSize*2 + size; - if( needed < size ) - { - /* theoretical case: req size + mw overhead exceeded size_t limits */ - return NULL; - } - - /* if this allocation would violate the limit, fail it */ - if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) { - mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", - mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc ); - mwIncErr(); - FLUSH(); - MW_MUTEX_UNLOCK(); - return NULL; - } - - mw = (mwData*) malloc( needed ); - if( mw == NULL ) { - if( mwFreeUp(needed,0) >= needed ) { - mw = (mwData*) malloc(needed); - if( mw == NULL ) { - mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed ); - mwIncErr(); - FLUSH(); - } - } - if( mw == NULL ) { - mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n", - mwCounter, file, line, (long)size, mwStatCurAlloc ); - mwIncErr(); - FLUSH(); - MW_MUTEX_UNLOCK(); - return NULL; - } - } - - mw->count = mwCounter; - mw->prev = NULL; - mw->next = mwHead; - mw->file = file; - mw->size = size; - mw->line = line; - mw->flag = 0; - mw->check = CHKVAL(mw); - - if( mwHead ) mwHead->prev = mw; - mwHead = mw; - if( mwTail == NULL ) mwTail = mw; - - ptr = ((char*)mw) + mwDataSize; - mwWriteOF( ptr ); /* '*(long*)ptr = PRECHK;' */ - ptr += mwOverflowZoneSize; - p = ptr; - memset( ptr, MW_VAL_NEW, size ); - ptr += size; - mwWriteOF( ptr ); /* '*(long*)ptr = POSTCHK;' */ - - mwNumCurAlloc ++; - mwStatCurAlloc += (long) size; - mwStatTotAlloc += (long) size; - if( mwStatCurAlloc > mwStatMaxAlloc ) - mwStatMaxAlloc = mwStatCurAlloc; - mwStatNumAlloc ++; - - if( mwStatLevel ) mwStatAlloc( size, file, line ); - - MW_MUTEX_UNLOCK(); - return p; - } - -void* mwRealloc( void *p, size_t size, const char* file, int line) { - int oldUseLimit, i; - mwData *mw; - char *ptr; - - mwAutoInit(); - - if( p == NULL ) return mwMalloc( size, file, line ); - if( size == 0 ) { mwFree( p, file, line ); return NULL; } - - MW_MUTEX_LOCK(); - - /* do the quick ownership test */ - mw = (mwData*) mwBUFFER_TO_MW( p ); - if( mwIsOwned( mw, file, line ) ) { - - /* if the buffer is an NML, treat this as a double-free */ - if( mw->flag & MW_NML ) - { - mwIncErr(); - if( *((unsigned char*)(mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML ) - { - mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", - mwCounter, file, line, mw ); - } - goto check_dbl_free; - } - - /* if this allocation would violate the limit, fail it */ - if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) { - TESTS(file,line); - mwCounter ++; - mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", - mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc ); - mwIncErr(); - FLUSH(); - MW_MUTEX_UNLOCK(); - return NULL; - } - - /* fake realloc operation */ - oldUseLimit = mwUseLimit; - mwUseLimit = 0; - ptr = (char*) mwMalloc( size, file, line ); - if( ptr != NULL ) { - if( size < mw->size ) - memcpy( ptr, p, size ); - else - memcpy( ptr, p, mw->size ); - mwFree( p, file, line ); - } - mwUseLimit = oldUseLimit; - MW_MUTEX_UNLOCK(); - return (void*) ptr; - } - - /* Unknown pointer! */ - - /* using free'd pointer? */ -check_dbl_free: - for(i=0;i %s(%d), %p was" - " freed from %s(%d)\n", - mwCounter, file, line, p, - mwLFfile[i], mwLFline[i] ); - FLUSH(); - MW_MUTEX_UNLOCK(); - return NULL; - } - } - - /* some weird pointer */ - mwIncErr(); - mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n", - mwCounter, file, line, p ); - FLUSH(); - MW_MUTEX_UNLOCK(); - return NULL; - } - -char *mwStrdup( const char* str, const char* file, int line ) { - size_t len; - char *newstring; - - MW_MUTEX_LOCK(); - - if( str == NULL ) { - mwIncErr(); - mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n", - mwCounter, file, line ); - FLUSH(); - MW_MUTEX_UNLOCK(); - return NULL; - } - - len = strlen( str ) + 1; - newstring = (char*) mwMalloc( len, file, line ); - if( newstring != NULL ) memcpy( newstring, str, len ); - MW_MUTEX_UNLOCK(); - return newstring; - } - -void mwFree( void* p, const char* file, int line ) { - int i; - mwData* mw; - char buffer[ sizeof(mwData) + (mwROUNDALLOC*3) + 64 ]; - - /* this code is in support of C++ delete */ - if( file == NULL ) { - mwFree_( p ); - MW_MUTEX_UNLOCK(); - return; - } - - mwAutoInit(); - - MW_MUTEX_LOCK(); - TESTS(file,line); - mwCounter ++; - - /* on NULL free, write a warning and return */ - if( p == NULL ) { - mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n", - mwCounter, file, line ); - FLUSH(); - MW_MUTEX_UNLOCK(); - return; - } - - /* do the quick ownership test */ - mw = (mwData*) mwBUFFER_TO_MW( p ); - - if( mwIsOwned( mw, file, line ) ) { - (void) mwTestBuf( mw, file, line ); - - /* if the buffer is an NML, treat this as a double-free */ - if( mw->flag & MW_NML ) - { - if( *(((unsigned char*)mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML ) - { - mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", - mwCounter, file, line, mw ); - } - goto check_dbl_free; - } - - /* update the statistics */ - mwNumCurAlloc --; - mwStatCurAlloc -= (long) mw->size; - if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line ); - - /* we should either free the allocation or keep it as NML */ - if( mwNML ) { - mw->flag |= MW_NML; - mwNmlNumAlloc ++; - mwNmlCurAlloc += (long) mw->size; - memset( ((char*)mw)+mwDataSize+mwOverflowZoneSize, MW_VAL_NML, mw->size ); - } - else { - /* unlink the allocation, and enter the post-free data */ - mwUnlink( mw, file, line ); - memset( mw, MW_VAL_DEL, - mw->size + mwDataSize+mwOverflowZoneSize+mwOverflowZoneSize ); - if( mwFBI ) { - memset( mw, '.', mwDataSize + mwOverflowZoneSize ); - sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line ); - strncpy( (char*)(void*)mw, buffer, mwDataSize + mwOverflowZoneSize ); - } - free( mw ); - } - - /* add the pointer to the last-free track */ - mwLFfile[ mwLFcur ] = file; - mwLFline[ mwLFcur ] = line; - mwLastFree[ mwLFcur++ ] = p; - if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0; - - MW_MUTEX_UNLOCK(); - return; - } - - /* check for double-freeing */ -check_dbl_free: - for(i=0;i %s(%d), %p was" - " freed from %s(%d)\n", - mwCounter, file, line, p, - mwLFfile[i], mwLFline[i] ); - FLUSH(); - MW_MUTEX_UNLOCK(); - return; - } - } - - /* some weird pointer... block the free */ - mwIncErr(); - mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n", - mwCounter, file, line, p ); - FLUSH(); - MW_MUTEX_UNLOCK(); - return; - } - -void* mwCalloc( size_t a, size_t b, const char *file, int line ) { - void *p; - size_t size = a * b; - p = mwMalloc( size, file, line ); - if( p == NULL ) return NULL; - memset( p, 0, size ); - return p; - } - -void mwFree_( void *p ) { - MW_MUTEX_LOCK(); - TESTS(NULL,0); - MW_MUTEX_UNLOCK(); - free(p); - } - -void* mwMalloc_( size_t size ) { - MW_MUTEX_LOCK(); - TESTS(NULL,0); - MW_MUTEX_UNLOCK(); - return malloc( size ); - } - -void* mwRealloc_( void *p, size_t size ) { - MW_MUTEX_LOCK(); - TESTS(NULL,0); - MW_MUTEX_UNLOCK(); - return realloc( p, size ); - } - -void* mwCalloc_( size_t a, size_t b ) { - MW_MUTEX_LOCK(); - TESTS(NULL,0); - MW_MUTEX_UNLOCK(); - return calloc( a, b ); - } - -void mwFlushNow( void ) { - if( mwLogR() ) fflush( mwLogR() ); - return; - } - -void mwDoFlush( int onoff ) { - mwFlushW( onoff<1?0:onoff ); - if( onoff ) if( mwLogR() ) fflush( mwLogR() ); - return; - } - -void mwLimit( long lim ) { - TESTS(NULL,0); - mwWrite("limit: old limit = "); - if( !mwAllocLimit ) mwWrite( "none" ); - else mwWrite( "%ld bytes", mwAllocLimit ); - mwWrite( ", new limit = "); - if( !lim ) { - mwWrite( "none\n" ); - mwUseLimit = 0; - } - else { - mwWrite( "%ld bytes\n", lim ); - mwUseLimit = 1; - } - mwAllocLimit = lim; - FLUSH(); - } - -void mwSetAriAction( int action ) { - MW_MUTEX_LOCK(); - TESTS(NULL,0); - mwAriAction = action; - MW_MUTEX_UNLOCK(); - return; - } - -int mwAssert( int exp, const char *exps, const char *fn, int ln ) { - int i; - char buffer[MW_TRACE_BUFFER+8]; - if( exp ) { - return 0; - } - mwAutoInit(); - MW_MUTEX_LOCK(); - TESTS(fn,ln); - mwIncErr(); - mwCounter++; - mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); - if( mwAriFunction != NULL ) { - sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps ); - i = (*mwAriFunction)(buffer); - switch( i ) { - case MW_ARI_IGNORE: - mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter ); - MW_MUTEX_UNLOCK(); - return 0; - case MW_ARI_RETRY: - mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter ); - MW_MUTEX_UNLOCK(); - return 1; - } - } - else { - if( mwAriAction & MW_ARI_IGNORE ) { - mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); - MW_MUTEX_UNLOCK(); - return 0; - } - fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps ); - } - - FLUSH(); - (void) mwTestNow( fn, ln, 1 ); - FLUSH(); - - if( mwAriAction & MW_ARI_NULLREAD ) { - /* This is made in an attempt to kick in */ - /* any debuggers or OS stack traces */ - FLUSH(); - /*lint -save -e413 */ - i = *((int*)NULL); - mwDummy( (char)i ); - /*lint -restore */ - } - - MW_MUTEX_UNLOCK(); - exit(255); - /* NOT REACHED - the return statement is in to keep */ - /* stupid compilers from squeaking about differing return modes. */ - /* Smart compilers instead say 'code unreachable...' */ - /*lint -save -e527 */ - return 0; - /*lint -restore */ - } - -int mwVerify( int exp, const char *exps, const char *fn, int ln ) { - int i; - char buffer[MW_TRACE_BUFFER+8]; - if( exp ) { - return 0; - } - mwAutoInit(); - MW_MUTEX_LOCK(); - TESTS(fn,ln); - mwIncErr(); - mwCounter++; - mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); - if( mwAriFunction != NULL ) { - sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps ); - i = (*mwAriFunction)(buffer); - if( i == 0 ) { - mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter ); - MW_MUTEX_UNLOCK(); - return 0; - } - if( i == 1 ) { - mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter ); - MW_MUTEX_UNLOCK(); - return 1; - } - } - else { - if( mwAriAction & MW_ARI_NULLREAD ) { - /* This is made in an attempt to kick in */ - /* any debuggers or OS stack traces */ - FLUSH(); - /*lint -save -e413 */ - i = *((int*)NULL); - mwDummy( (char)i ); - /*lint -restore */ - } - if( mwAriAction & MW_ARI_IGNORE ) { - mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); - MW_MUTEX_UNLOCK(); - return 0; - } - fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps ); - } - FLUSH(); - (void) mwTestNow( fn, ln, 1 ); - FLUSH(); - MW_MUTEX_UNLOCK(); - exit(255); - /* NOT REACHED - the return statement is in to keep */ - /* stupid compilers from squeaking about differing return modes. */ - /* Smart compilers instead say 'code unreachable...' */ - /*lint -save -e527 */ - return 0; - /*lint -restore */ - } - -void mwTrace( const char *format, ... ) { - int tot, oflow = 0; - va_list mark; - - mwAutoInit(); - MW_MUTEX_LOCK(); - TESTS(NULL,0); - if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; - - va_start( mark, format ); - tot = vsprintf( mwPrintBuf, format, mark ); - va_end( mark ); - if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } - for(tot=0;mwPrintBuf[tot];tot++) - (*mwOutFunction)( mwPrintBuf[tot] ); - if( oflow ) { - mwIncErr(); - mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); - } - - FLUSH(); - MW_MUTEX_UNLOCK(); - } - - -/*********************************************************************** -** Grab & Drop -***********************************************************************/ - -unsigned mwGrab( unsigned kb ) { - TESTS(NULL,0); - return mwGrab_( kb, MW_VAL_GRB, 0 ); - } - -unsigned mwDrop( unsigned kb ) { - TESTS(NULL,0); - return mwDrop_( kb, MW_VAL_GRB, 0 ); - } - -static void mwDropAll() { - TESTS(NULL,0); - (void) mwDrop_( 0, MW_VAL_GRB, 0 ); - (void) mwDrop_( 0, MW_VAL_NML, 0 ); - if( mwGrabList != NULL ) - mwWrite( "internal: the grab list is not empty after mwDropAll()\n"); - } - -static const char *mwGrabType( int type ) { - switch( type ) { - case MW_VAL_GRB: - return "grabbed"; - case MW_VAL_NML: - return "no-mans-land"; - default: - /* do nothing */ - ; - } - return ""; - } - -static unsigned mwGrab_( unsigned kb, int type, int silent ) { - unsigned i = kb; - mwGrabData *gd; - if( !kb ) i = kb = 65000U; - - for(;kb;kb--) { - if( mwUseLimit && - (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) { - if( !silent ) { - mwWrite("grabbed: all allowed memory to %s (%u kb)\n", - mwGrabType(type), i-kb); - FLUSH(); - } - return i-kb; - } - gd = (mwGrabData*) malloc( sizeof(mwGrabData) ); - if( gd == NULL ) { - if( !silent ) { - mwWrite("grabbed: all available memory to %s (%u kb)\n", - mwGrabType(type), i-kb); - FLUSH(); - } - return i-kb; - } - mwGrabSize += (long) sizeof(mwGrabData); - gd->next = mwGrabList; - memset( gd->blob, type, sizeof(gd->blob) ); - gd->type = type; - mwGrabList = gd; - } - if( !silent ) { - mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) ); - FLUSH(); - } - return i; - } - -static unsigned mwDrop_( unsigned kb, int type, int silent ) { - unsigned i = kb; - mwGrabData *gd,*tmp,*pr; - const void *p; - - if( mwGrabList == NULL && kb == 0 ) return 0; - if( !kb ) i = kb = 60000U; - - pr = NULL; - gd = mwGrabList; - for(;kb;) { - if( gd == NULL ) { - if( i-kb > 0 && !silent ) { - mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb); - FLUSH(); - } - return i-kb; - } - if( gd->type == type ) { - if( pr ) pr->next = gd->next; - kb --; - tmp = gd; - if( mwGrabList == gd ) mwGrabList = gd->next; - gd = gd->next; - p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type ); - if( p != NULL ) { - mwWrite( "wild pointer: <%ld> %s memory hit at %p\n", - mwCounter, mwGrabType(type), p ); - FLUSH(); - } - mwGrabSize -= (long) sizeof(mwGrabData); - free( tmp ); - } - else { - pr = gd; - gd = gd->next; - } - } - if( !silent ) { - mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) ); - FLUSH(); - } - return i; - } - -/*********************************************************************** -** No-Mans-Land -***********************************************************************/ - -void mwNoMansLand( int level ) { - mwAutoInit(); - TESTS(NULL,0); - switch( level ) { - case MW_NML_NONE: - (void) mwDrop_( 0, MW_VAL_NML, 0 ); - break; - case MW_NML_FREE: - break; - case MW_NML_ALL: - (void) mwGrab_( 0, MW_VAL_NML, 0 ); - break; - default: - return; - } - mwNML = level; - } - -/*********************************************************************** -** Static functions -***********************************************************************/ - -static void mwAutoInit( void ) -{ - if( mwInited ) return; - mwUseAtexit = 1; - mwInit(); - return; -} - -static FILE *mwLogR() { - if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog; - if( mwLog == mwLogB1 ) mwLogB2 = mwLog; - if( mwLog == mwLogB2 ) mwLogB1 = mwLog; - if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1; - if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) { - mwWrite("internal: log file handle damaged and recovered\n"); - FLUSH(); - return mwLog; - } - fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" ); - mwLog = mwLogB1 = mwLogB2 = mwSTDERR; - return mwSTDERR; - } - -/* static */ void mwLogW( FILE *p ) { - mwLog = mwLogB1 = mwLogB2 = p; - } - -static int mwFlushR() { - if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing; - if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing; - if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing; - if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1; - if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) { - mwWrite("internal: flushing flag damaged and recovered\n"); - FLUSH(); - return mwFlushing; - } - mwWrite("internal: flushing flag destroyed, so set to true\n"); - mwFlushing = mwFlushingB1 = mwFlushingB2 = 1; - return 1; - } - -static void mwFlushW( int n ) { - mwFlushing = mwFlushingB1 = mwFlushingB2 = n; - } - -static void mwIncErr() { - mwErrors++; - mwFlushW( mwFlushR()+1 ); - FLUSH(); - } - -static void mwFlush() { - if( mwLogR() == NULL ) return; -#ifdef MW_FLUSH - fflush( mwLogR() ); -#else - if( mwFlushR() ) fflush( mwLogR() ); -#endif - return; - } - -static void mwUnlink( mwData* mw, const char* file, int line ) { - if( mw->prev == NULL ) { - if( mwHead != mw ) - mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n", - mwCounter, file, line, mw ); - mwHead = mw->next; - } - else { - if( mw->prev->next != mw ) - mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n", - mwCounter, file, line, mw ); - else mw->prev->next = mw->next; - } - if( mw->next == NULL ) { - if( mwTail != mw ) - mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n", - mwCounter, file, line, mw ); - mwTail = mw->prev; - } - else { - if( mw->next->prev != mw ) - mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n", - mwCounter, file, line, mw ); - else mw->next->prev = mw->prev; - } - } - -/* -** Relinking tries to repair a damaged mw block. -** Returns nonzero if it thinks it successfully -** repaired the heap chain. -*/ -static int mwRelink( mwData* mw, const char* file, int line ) { - int fails; - mwData *mw1, *mw2; - long count, size; - mwStat *ms; - - if( file == NULL ) file = "unknown"; - - if( mw == NULL ) { - mwWrite("relink: cannot repair MW at NULL\n"); - FLUSH(); - goto emergency; - } - - if( !mwIsSafeAddr(mw, mwDataSize) ) { - mwWrite("relink: MW-%p is a garbage pointer\n", mw); - FLUSH(); - goto emergency; - } - - mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw ); - FLUSH(); - fails = 0; - - /* Repair from head */ - if( mwHead != mw ) { - if( !mwIsSafeAddr( mwHead, mwDataSize ) ) { - mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw ); - FLUSH(); - goto emergency; - } - for( mw1=mwHead; mw1; mw1=mw1->next ) { - if( mw1->next == mw ) { - mw->prev = mw1; - break; - } - if( mw1->next && - ( !mwIsSafeAddr(mw1->next, mwDataSize ) || mw1->next->prev != mw1) ) { - mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next ); - FLUSH(); - goto emergency; - } - } - if( mw1 == NULL ) { - mwWrite("relink: MW-%p not found in forward chain search\n", mw ); - FLUSH(); - fails ++; - } - } - else - { - mwWrite( "relink: MW-%p is the head (first) allocation\n", mw ); - if( mw->prev != NULL ) - { - mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw ); - mw->prev = NULL; - } - } - - /* Repair from tail */ - if( mwTail != mw ) { - if( !mwIsSafeAddr( mwTail, mwDataSize ) ) { - mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw ); - FLUSH(); - goto emergency; - } - for( mw1=mwTail; mw1; mw1=mw1->prev ) { - if( mw1->prev == mw ) { - mw->next = mw1; - break; - } - if( mw1->prev && (!mwIsSafeAddr(mw1->prev, mwDataSize ) || mw1->prev->next != mw1) ) { - mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev ); - FLUSH(); - goto emergency; - } - } - if( mw1 == NULL ) { - mwWrite("relink: MW-%p not found in reverse chain search\n", mw ); - FLUSH(); - fails ++; - } - } - else - { - mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw ); - if( mw->next != NULL ) - { - mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw ); - mw->next = NULL; - } - } - - if( fails > 1 ) { - mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw ); - FLUSH(); - goto verifyok; - } - - /* restore MW info where possible */ - if( mwIsReadAddr( mw->file, 1 ) ) { - ms = mwStatGet( mw->file, -1, 0 ); - if( ms == NULL ) mw->file = ""; - } - mw->check = CHKVAL(mw); - goto verifyok; - - /* Emergency repair */ - emergency: - - if( mwHead == NULL && mwTail == NULL ) - { - if( mwStatCurAlloc == 0 ) - mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line ); - else - mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line ); - FLUSH(); - return 0; - } - - mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line ); - FLUSH(); - - if( mwHead == NULL || mwTail == NULL ) - { - if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail ); - else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead ); - } - - mw1=NULL; - if( mwHead != NULL ) - { - if( !mwIsReadAddr( mwHead, mwDataSize ) || mwHead->check != CHKVAL(mwHead) ) - { - mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead ); - mwHead = NULL; - goto scan_reverse; - } - if( mwHead->prev != NULL ) - { - mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev ); - } - for( mw1=mwHead; mw1; mw1=mw1->next ) - { - if( mw1->next ) - { - if( !mwIsReadAddr(mw1->next,mwDataSize) || - (!mw1->next->check) != CHKVAL(mw1) || - mw1->next->prev != mw1 ) - { - mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", - mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line ); - if( mwIsReadAddr(mw1->next,mwDataSize ) ) - { - mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", - mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", - mwIsReadAddr(mw1->file,16)?mw1->file:"", mw1->line ); - } - else - { - mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n", - mw1->next ); - } - break; - } - } - } - } - - -scan_reverse: - mw2=NULL; - if( mwTail != NULL ) - { - if( !mwIsReadAddr(mwTail,mwDataSize) || mwTail->check != CHKVAL(mwTail) ) - { - mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail ); - mwTail = NULL; - goto analyze; - } - if( mwTail->next != NULL ) - { - mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next ); - } - for( mw2=mwTail; mw2; mw2=mw2->prev ) - { - if( mw2->prev ) - { - if( !mwIsReadAddr(mw2->prev,mwDataSize) || - (!mw2->prev->check) != CHKVAL(mw2) || - mw2->prev->next != mw2 ) - { - mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", - mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line ); - if( mwIsReadAddr(mw2->prev,mwDataSize ) ) - { - mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", - mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", - mwIsReadAddr(mw2->file,16)?mw2->file:"", mw2->line ); - } - else - { - mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n", - mw2->prev ); - } - break; - } - } - } - } - -analyze: - if( mwHead == NULL && mwTail == NULL ) - { - mwWrite("relink: both head and tail pointers damaged, aborting program\n"); - mwFlushW(1); - FLUSH(); - abort(); - } - if( mwHead == NULL ) - { - mwHead = mw2; - mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 ); - mw2->prev = NULL; - mw1 = mw2 = NULL; - } - if( mwTail == NULL ) - { - mwTail = mw1; - mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 ); - mw1->next = NULL; - mw1 = mw2 = NULL; - } - if( mw1 == NULL && mw2 == NULL && - mwHead->prev == NULL && mwTail->next == NULL ) { - mwWrite("relink: verifying heap integrity...\n" ); - FLUSH(); - goto verifyok; - } - if( mw1 && mw2 && mw1 != mw2 ) { - mw1->next = mw2; - mw2->prev = mw1; - mwWrite("relink: emergency repairs successful, assessing damage...\n"); - FLUSH(); - } - else { - mwWrite("relink: heap totally destroyed, aborting program\n"); - mwFlushW(1); - FLUSH(); - abort(); - } - - /* Verify by checking that the number of active allocations */ - /* match the number of entries in the chain */ -verifyok: - if( !mwIsHeapOK( NULL ) ) { - mwWrite("relink: heap verification FAILS - aborting program\n"); - mwFlushW(1); - FLUSH(); - abort(); - } - for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) { - count ++; - size += (long) mw1->size; - } - if( count == mwNumCurAlloc ) { - mwWrite("relink: successful, "); - if( size == mwStatCurAlloc ) { - mwWrite("no allocations lost\n"); - } - else { - if( mw != NULL ) { - mwWrite("size information lost for MW-%p\n", mw); - mw->size = 0; - } - } - } - else { - mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n", - mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size ); - return 0; - } - - return 1; - } - -/* -** If mwData* is NULL: -** Returns 0 if heap chain is broken. -** Returns 1 if heap chain is intact. -** If mwData* is not NULL: -** Returns 0 if mwData* is missing or if chain is broken. -** Returns 1 if chain is intact and mwData* is found. -*/ -static int mwIsHeapOK( mwData *includes_mw ) { - int found = 0; - mwData *mw; - - for( mw = mwHead; mw; mw=mw->next ) { - if( includes_mw == mw ) found++; - if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0; - if( mw->prev ) { - if( !mwIsSafeAddr( mw->prev, mwDataSize ) ) return 0; - if( mw==mwHead || mw->prev->next != mw ) return 0; - } - if( mw->next ) { - if( !mwIsSafeAddr( mw->next, mwDataSize ) ) return 0; - if( mw==mwTail || mw->next->prev != mw ) return 0; - } - else if( mw!=mwTail ) return 0; - } - - if( includes_mw != NULL && !found ) return 0; - - return 1; - } - -static int mwIsOwned( mwData* mw, const char *file, int line ) { - int retv; - mwStat *ms; - - /* see if the address is legal according to OS */ - if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0; - - /* make sure we have _anything_ allocated */ - if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 ) - return 0; - - /* calculate checksum */ - if( mw->check != CHKVAL(mw) ) { - /* may be damaged checksum, see if block is in heap */ - if( mwIsHeapOK( mw ) ) { - /* damaged checksum, repair it */ - mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n", - mwCounter, file, line, mw ); - mwIncErr(); - if( mwIsReadAddr( mw->file, 1 ) ) { - ms = mwStatGet( mw->file, -1, 0 ); - if( ms == NULL ) mw->file = ""; - } - else mw->file = ""; - mw->size = 0; - mw->check = CHKVAL(mw); - return 1; - } - /* no, it's just some garbage data */ - return 0; - } - - /* check that the non-NULL pointers are safe */ - if( mw->prev && !mwIsSafeAddr( mw->prev, mwDataSize ) ) mwRelink( mw, file, line ); - if( mw->next && !mwIsSafeAddr( mw->next, mwDataSize ) ) mwRelink( mw, file, line ); - - /* safe address, checksum OK, proceed with heap checks */ - - /* see if the block is in the heap */ - retv = 0; - if( mw->prev ) { if( mw->prev->next == mw ) retv ++; } - else { if( mwHead == mw ) retv++; } - if( mw->next ) { if( mw->next->prev == mw ) retv ++; } - else { if( mwTail == mw ) retv++; } - if( mw->check == CHKVAL(mw) ) retv ++; - if( retv > 2 ) return 1; - - /* block not in heap, check heap for corruption */ - - if( !mwIsHeapOK( mw ) ) { - if( mwRelink( mw, file, line ) ) - return 1; - } - - /* unable to repair */ - mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n", - mwCounter, file, line, mw ); - mwIncErr(); - - return 0; - } - -/* -** mwTestBuf: -** Checks a buffers links and pre/postfixes. -** Writes errors found to the log. -** Returns zero if no errors found. -*/ -static int mwTestBuf( mwData* mw, const char* file, int line ) { - int retv = 0; - char *p; - - if( file == NULL ) file = "unknown"; - - if( !mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) ) { - mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n", - mwCounter, file, line, mw ); - mwIncErr(); - return 2; - } - - if( mw->check != CHKVAL(mw) ) { - mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n", - mwCounter, file, line ); - mwIncErr(); - if( !mwRelink( mw, file, line ) ) return 2; - } - - if( mw->prev && mw->prev->next != mw ) { - mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n", - mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); - mwIncErr(); - if( !mwRelink( mw, file, line ) ) retv = 2; - } - if( mw->next && mw->next->prev != mw ) { - mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n", - mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); - mwIncErr(); - if( !mwRelink( mw, file, line ) ) retv = 2; - } - - p = ((char*)mw) + mwDataSize; - if( mwCheckOF( p ) ) { - mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", - mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); - mwIncErr(); - retv = 1; - } - p += mwOverflowZoneSize + mw->size; - if( mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) ) { - mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", - mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); - mwIncErr(); - retv = 1; - } - - return retv; - } - -static void mwDefaultOutFunc( int c ) { - if( mwLogR() ) fputc( c, mwLogR() ); - } - -static void mwWrite( const char *format, ... ) { - int tot, oflow = 0; - va_list mark; - mwAutoInit(); - if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; - va_start( mark, format ); - tot = vsprintf( mwPrintBuf, format, mark ); - va_end( mark ); - if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } - for(tot=0;mwPrintBuf[tot];tot++) - (*mwOutFunction)( mwPrintBuf[tot] ); - if( oflow ) { - mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 ); - FLUSH(); - } - return; - } - -static void mwLogFile( const char *name ) { - time_t tid; - (void) time( &tid ); - if( mwLogR() != NULL ) { - fclose( mwLogR() ); - mwLogW( NULL ); - } - if( name == NULL ) return; - mwLogW( fopen( name, "a" COMMIT ) ); - if( mwLogR() == NULL ) - mwWrite( "logfile: failed to open/create file '%s'\n", name ); - } - -/* -** Try to free NML memory until a contiguous allocation of -** 'needed' bytes can be satisfied. If this is not enough -** and the 'urgent' parameter is nonzero, grabbed memory is -** also freed. -*/ -static size_t mwFreeUp( size_t needed, int urgent ) { - void *p; - mwData *mw, *mw2; - char *data; - - /* free grabbed NML memory */ - for(;;) { - if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break; - p = malloc( needed ); - if( p == NULL ) continue; - free( p ); - return needed; - } - - /* free normal NML memory */ - mw = mwHead; - while( mw != NULL ) { - if( !(mw->flag & MW_NML) ) mw = mw->next; - else { - data = ((char*)mw)+mwDataSize+mwOverflowZoneSize; - if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { - mwIncErr(); - mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", - mw->count, data + mwOverflowZoneSize, mw->file, mw->line ); - } - mw2 = mw->next; - mwUnlink( mw, "mwFreeUp", 0 ); - free( mw ); - mw = mw2; - p = malloc( needed ); - if( p == NULL ) continue; - free( p ); - return needed; - } - } - - /* if not urgent (for internal purposes), fail */ - if( !urgent ) return 0; - - /* free grabbed memory */ - for(;;) { - if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break; - p = malloc( needed ); - if( p == NULL ) continue; - free( p ); - return needed; - } - - return 0; - } - -static const void * mwTestMem( const void *p, unsigned len, int c ) { - const unsigned char *ptr; - ptr = (const unsigned char *) p; - while( len-- ) { - if( *ptr != (unsigned char)c ) return (const void*)ptr; - ptr ++; - } - return NULL; - } - -static int mwStrCmpI( const char *s1, const char *s2 ) { - if( s1 == NULL || s2 == NULL ) return 0; - while( *s1 ) { - if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; } - return 1; - } - return 0; - } - -#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; } - -static int mwTestNow( const char *file, int line, int always_invoked ) { - int retv = 0; - mwData *mw; - char *data; - - if( file && !always_invoked ) - mwWrite("check: <%ld> %s(%d), checking %s%s%s\n", - mwCounter, file, line, - (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "", - (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "", - (mwTestFlags & MW_TEST_NML) ? "nomansland ": "" - ); - - if( mwTestFlags & MW_TEST_CHAIN ) { - for( mw = mwHead; mw; mw=mw->next ) { - if( !mwIsSafeAddr(mw, mwDataSize) ) { - AIPH(); - mwWrite("check: heap corruption detected\n"); - mwIncErr(); - return retv + 1; - } - if( mw->prev ) { - if( !mwIsSafeAddr(mw->prev, mwDataSize) ) { - AIPH(); - mwWrite("check: heap corruption detected\n"); - mwIncErr(); - return retv + 1; - } - if( mw==mwHead || mw->prev->next != mw ) { - AIPH(); - mwWrite("check: heap chain broken, prev link incorrect\n"); - mwIncErr(); - retv ++; - } - } - if( mw->next ) { - if( !mwIsSafeAddr(mw->next, mwDataSize) ) { - AIPH(); - mwWrite("check: heap corruption detected\n"); - mwIncErr(); - return retv + 1; - } - if( mw==mwTail || mw->next->prev != mw ) { - AIPH(); - mwWrite("check: heap chain broken, next link incorrect\n"); - mwIncErr(); - retv ++; - } - } - else if( mw!=mwTail ) { - AIPH(); - mwWrite("check: heap chain broken, tail incorrect\n"); - mwIncErr(); - retv ++; - } - } - } - if( mwTestFlags & MW_TEST_ALLOC ) { - for( mw = mwHead; mw; mw=mw->next ) { - if( mwTestBuf( mw, file, line ) ) retv ++; - } - } - if( mwTestFlags & MW_TEST_NML ) { - for( mw = mwHead; mw; mw=mw->next ) { - if( (mw->flag & MW_NML) ) { - data = ((char*)mw)+mwDataSize+mwOverflowZoneSize; - if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { - mwIncErr(); - mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", - mw->count, data + mwOverflowZoneSize, mw->file, mw->line ); - } - } - } - } - - - if( file && !always_invoked && !retv ) - mwWrite("check: <%ld> %s(%d), complete; no errors\n", - mwCounter, file, line ); - return retv; - } - -/********************************************************************** -** Statistics -**********************************************************************/ - -static void mwStatReport() -{ - mwStat* ms, *ms2; - const char *modname; - int modnamelen; - - /* global statistics report */ - mwWrite( "\nMemory usage statistics (global):\n" ); - mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc ); - mwWrite( " L)argest memory usage : %ld\n", mwStatMaxAlloc ); - mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc ); - mwWrite( " U)nfreed bytes totals : %ld\n", mwStatCurAlloc ); - FLUSH(); - - if( mwStatLevel < 1 ) return; - - /* on a per-module basis */ - mwWrite( "\nMemory usage statistics (detailed):\n"); - mwWrite( " Module/Line Number Largest Total Unfreed \n"); - for( ms=mwStatList; ms; ms=ms->next ) - { - if( ms->line == -1 ) - { - if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = ""; - else modname = ms->file; - modnamelen = strlen(modname); - if( modnamelen > 42 ) - { - modname = modname + modnamelen - 42; - } - - mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n", - modname, ms->num, ms->max, ms->total, ms->curr ); - if( ms->file && mwStatLevel > 1 ) - { - for( ms2=mwStatList; ms2; ms2=ms2->next ) - { - if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) ) - { - mwWrite( " %-8d %-8ld %-8ld %-8ld %-8ld\n", - ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr ); - } - } - } - } - } -} - -static mwStat* mwStatGet( const char *file, int line, int makenew ) { - mwStat* ms; - - if( mwStatLevel < 2 ) line = -1; - - for( ms=mwStatList; ms!=NULL; ms=ms->next ) { - if( line != ms->line ) continue; - if( file==NULL ) { - if( ms->file == NULL ) break; - continue; - } - if( ms->file == NULL ) continue; - if( !strcmp( ms->file, file ) ) break; - } - - if( ms != NULL ) return ms; - - if( !makenew ) return NULL; - - ms = (mwStat*) malloc( sizeof(mwStat) ); - if( ms == NULL ) { - if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) || - (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) { - mwWrite("internal: memory low, statistics incomplete for '%s'\n", file ); - return NULL; - } - } - ms->file = file; - ms->line = line; - ms->total = 0L; - ms->max = 0L; - ms->num = 0L; - ms->curr = 0L; - ms->next = mwStatList; - mwStatList = ms; - return ms; - } - -static void mwStatAlloc( size_t size, const char* file, int line ) { - mwStat* ms; - - /* update the module statistics */ - ms = mwStatGet( file, -1, 1 ); - if( ms != NULL ) { - ms->total += (long) size; - ms->curr += (long) size; - ms->num ++; - if( ms->curr > ms->max ) ms->max = ms->curr; - } - - /* update the line statistics */ - if( mwStatLevel > 1 && line != -1 && file ) { - ms = mwStatGet( file, line, 1 ); - if( ms != NULL ) { - ms->total += (long) size; - ms->curr += (long) size; - ms->num ++; - if( ms->curr > ms->max ) ms->max = ms->curr; - } - } - - } - -static void mwStatFree( size_t size, const char* file, int line ) { - mwStat* ms; - - /* update the module statistics */ - ms = mwStatGet( file, -1, 1 ); - if( ms != NULL ) ms->curr -= (long) size; - - /* update the line statistics */ - if( mwStatLevel > 1 && line != -1 && file ) { - ms = mwStatGet( file, line, 1 ); - if( ms != NULL ) ms->curr -= (long) size; - } - } - -/*********************************************************************** -** Safe memory checkers -** -** Using ifdefs, implement the operating-system specific mechanism -** of identifying a piece of memory as legal to access with read -** and write priviliges. Default: return nonzero for non-NULL pointers. -***********************************************************************/ - -static char mwDummy( char c ) -{ - return c; -} - -#ifndef MW_SAFEADDR -#ifdef WIN32 -#define MW_SAFEADDR -#define WIN32_LEAN_AND_MEAN -#include -int mwIsReadAddr( const void *p, unsigned len ) -{ - if( p == NULL ) return 0; - if( IsBadReadPtr(p,len) ) return 0; - return 1; -} -int mwIsSafeAddr( void *p, unsigned len ) -{ - /* NOTE: For some reason, under Win95 the IsBad... */ - /* can return false for invalid pointers. */ - if( p == NULL ) return 0; - if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0; - return 1; -} -#endif /* WIN32 */ -#endif /* MW_SAFEADDR */ - -#ifndef MW_SAFEADDR -#ifdef SIGSEGV -#define MW_SAFEADDR - -typedef void (*mwSignalHandlerPtr)( int ); -mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0; -jmp_buf mwSIGSEGVjump; -static void mwSIGSEGV( int n ); - -static void mwSIGSEGV( int n ) -{ - n = n; - longjmp( mwSIGSEGVjump, 1 ); -} - -int mwIsReadAddr( const void *p, unsigned len ) -{ - const char *ptr; - - if( p == NULL ) return 0; - if( !len ) return 1; - - /* set up to catch the SIGSEGV signal */ - mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); - - if( setjmp( mwSIGSEGVjump ) ) - { - signal( SIGSEGV, mwOldSIGSEGV ); - return 0; - } - - /* read all the bytes in the range */ - ptr = (const char *)p; - ptr += len; - - /* the reason for this rather strange construct is that */ - /* we want to keep the number of used parameters and locals */ - /* to a minimum. if we use len for a counter gcc will complain */ - /* it may get clobbered by longjmp() at high warning levels. */ - /* it's a harmless warning, but this way we don't have to see it. */ - do - { - ptr --; - if( *ptr == 0x7C ) (void) mwDummy( (char)0 ); - } while( (const void*) ptr != p ); - - /* remove the handler */ - signal( SIGSEGV, mwOldSIGSEGV ); - - return 1; -} -int mwIsSafeAddr( void *p, unsigned len ) -{ - char *ptr; - - if( p == NULL ) return 0; - if( !len ) return 1; - - /* set up to catch the SIGSEGV signal */ - mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); - - if( setjmp( mwSIGSEGVjump ) ) - { - signal( SIGSEGV, mwOldSIGSEGV ); - return 0; - } - - /* read and write-back all the bytes in the range */ - ptr = (char *)p; - ptr += len; - - /* the reason for this rather strange construct is that */ - /* we want to keep the number of used parameters and locals */ - /* to a minimum. if we use len for a counter gcc will complain */ - /* it may get clobbered by longjmp() at high warning levels. */ - /* it's a harmless warning, but this way we don't have to see it. */ - do - { - ptr --; - *ptr = mwDummy( *ptr ); - } while( (void*) ptr != p ); - - /* remove the handler */ - signal( SIGSEGV, mwOldSIGSEGV ); - - return 1; -} -#endif /* SIGSEGV */ -#endif /* MW_SAFEADDR */ - -#ifndef MW_SAFEADDR -int mwIsReadAddr( const void *p, unsigned len ) -{ - if( p == NULL ) return 0; - if( len == 0 ) return 1; - return 1; -} -int mwIsSafeAddr( void *p, unsigned len ) -{ - if( p == NULL ) return 0; - if( len == 0 ) return 1; - return 1; -} -#endif - -/********************************************************************** -** Mutex handling -**********************************************************************/ - -#if defined(WIN32) || defined(__WIN32__) - -static void mwMutexInit( void ) -{ - mwGlobalMutex = CreateMutex( NULL, FALSE, NULL); - return; -} - -static void mwMutexTerm( void ) -{ - CloseHandle( mwGlobalMutex ); - return; -} - -static void mwMutexLock( void ) -{ - if( WaitForSingleObject(mwGlobalMutex, 1000 ) == WAIT_TIMEOUT ) - { - mwWrite( "mwMutexLock: timed out, possible deadlock\n" ); - } - return; -} - -static void mwMutexUnlock( void ) -{ - ReleaseMutex( mwGlobalMutex ); - return; -} - -#endif - -#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H) - -static void mwMutexInit( void ) -{ - pthread_mutex_init( &mwGlobalMutex, NULL ); - return; -} - -static void mwMutexTerm( void ) -{ - pthread_mutex_destroy( &mwGlobalMutex ); - return; -} - -static void mwMutexLock( void ) -{ - pthread_mutex_lock(&mwGlobalMutex); - return; -} - -static void mwMutexUnlock( void ) -{ - pthread_mutex_unlock(&mwGlobalMutex); - return; -} - -#endif - -/********************************************************************** -** C++ new & delete -**********************************************************************/ - -#if 0 /* 980317: disabled C++ */ - -#ifdef __cplusplus -#ifndef MEMWATCH_NOCPP - -int mwNCur = 0; -const char *mwNFile = NULL; -int mwNLine = 0; - -class MemWatch { -public: - MemWatch(); - ~MemWatch(); - }; - -MemWatch::MemWatch() { - if( mwInited ) return; - mwUseAtexit = 0; - mwInit(); - } - -MemWatch::~MemWatch() { - if( mwUseAtexit ) return; - mwTerm(); - } - -/* -** This global new will catch all 'new' calls where MEMWATCH is -** not active. -*/ -void* operator new( unsigned size ) { - mwNCur = 0; - return mwMalloc( size, "", 0 ); - } - -/* -** This is the new operator that's called when a module uses mwNew. -*/ -void* operator new( unsigned size, const char *file, int line ) { - mwNCur = 0; - return mwMalloc( size, file, line ); - } - -/* -** This is the new operator that's called when a module uses mwNew[]. -** -- hjc 07/16/02 -*/ -void* operator new[] ( unsigned size, const char *file, int line ) { - mwNCur = 0; - return mwMalloc( size, file, line ); - } - -/* -** Since this delete operator will recieve ALL delete's -** even those from within libraries, we must accept -** delete's before we've been initialized. Nor can we -** reliably check for wild free's if the mwNCur variable -** is not set. -*/ -void operator delete( void *p ) { - if( p == NULL ) return; - if( !mwInited ) { - free( p ); - return; - } - if( mwNCur ) { - mwFree( p, mwNFile, mwNLine ); - mwNCur = 0; - return; - } - mwFree_( p ); - } - -void operator delete[]( void *p ) { - if( p == NULL ) return; - if( !mwInited ) { - free( p ); - return; - } - if( mwNCur ) { - mwFree( p, mwNFile, mwNLine ); - mwNCur = 0; - return; - } - mwFree_( p ); - } - -#endif /* MEMWATCH_NOCPP */ -#endif /* __cplusplus */ - -#endif /* 980317: disabled C++ */ - -/* MEMWATCH.C */ diff --git a/thirdparty/memwatch/memwatch.h b/thirdparty/memwatch/memwatch.h deleted file mode 100644 index 4a42cb9..0000000 --- a/thirdparty/memwatch/memwatch.h +++ /dev/null @@ -1,710 +0,0 @@ -/* -** MEMWATCH.H -** Nonintrusive ANSI C memory leak / overwrite detection -** Copyright (C) 1992-2002 Johan Lindh -** All rights reserved. -** Version 2.71 -** -************************************************************************ -** -** PURPOSE: -** -** MEMWATCH has been written to allow guys and gals that like to -** program in C a public-domain memory error control product. -** I hope you'll find it's as advanced as most commercial packages. -** The idea is that you use it during the development phase and -** then remove the MEMWATCH define to produce your final product. -** MEMWATCH is distributed in source code form in order to allow -** you to compile it for your platform with your own compiler. -** It's aim is to be 100% ANSI C, but some compilers are more stingy -** than others. If it doesn't compile without warnings, please mail -** me the configuration of operating system and compiler you are using -** along with a description of how to modify the source, and the version -** number of MEMWATCH that you are using. -** -************************************************************************ - - This file is part of MEMWATCH. - - MEMWATCH is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - MEMWATCH 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 - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MEMWATCH; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -************************************************************************ -** -** REVISION HISTORY: -** -** 920810 JLI [1.00] -** 920830 JLI [1.10 double-free detection] -** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit] -** 921022 JLI [1.20 ASSERT and VERIFY] -** 921105 JLI [1.30 C++ support and TRACE] -** 921116 JLI [1.40 mwSetOutFunc] -** 930215 JLI [1.50 modified ASSERT/VERIFY] -** 930327 JLI [1.51 better auto-init & PC-lint support] -** 930506 JLI [1.55 MemWatch class, improved C++ support] -** 930507 JLI [1.60 mwTest & CHECK()] -** 930809 JLI [1.65 Abort/Retry/Ignore] -** 930820 JLI [1.70 data dump when unfreed] -** 931016 JLI [1.72 modified C++ new/delete handling] -** 931108 JLI [1.77 mwSetAssertAction() & some small changes] -** 940110 JLI [1.80 no-mans-land alloc/checking] -** 940328 JLI [2.00 version 2.0 rewrite] -** Improved NML (no-mans-land) support. -** Improved performance (especially for free()ing!). -** Support for 'read-only' buffers (checksums) -** ^^ NOTE: I never did this... maybe I should? -** FBI (free'd block info) tagged before freed blocks -** Exporting of the mwCounter variable -** mwBreakOut() localizes debugger support -** Allocation statistics (global, per-module, per-line) -** Self-repair ability with relinking -** 950913 JLI [2.10 improved garbage handling] -** 951201 JLI [2.11 improved auto-free in emergencies] -** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()] -** 960514 JLI [2.12 undefining of existing macros] -** 960515 JLI [2.13 possibility to use default new() & delete()] -** 960516 JLI [2.20 suppression of file flushing on unfreed msgs] -** 960516 JLI [2.21 better support for using MEMWATCH with DLL's] -** 960710 JLI [X.02 multiple logs and mwFlushNow()] -** 960801 JLI [2.22 merged X.01 version with current] -** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's] -** 960805 JLI [2.31 merged X.02 version with current] -** 961002 JLI [2.32 support for realloc() + fixed STDERR bug] -** 961222 JLI [2.40 added mwMark() & mwUnmark()] -** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY] -** 970113 JLI [2.42 added support for PC-Lint 7.00g] -** 970207 JLI [2.43 added support for strdup()] -** 970209 JLI [2.44 changed default filename to lowercase] -** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers] -** 970723 JLI [2.46 added MW_ARI_NULLREAD flag] -** 970813 JLI [2.47 stabilized marker handling] -** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway] -** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support] -** 980417 JLI [2.51 more checks for invalid addresses] -** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting] -** 990112 JLI [2.53 added check for empty heap to mwIsOwned] -** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML] -** 990224 JLI [2.56 changed ordering of members in structures] -** 990303 JLI [2.57 first maybe-fixit-for-hpux test] -** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit] -** 990517 JLI [2.59 fixed some high-sensitivity warnings] -** 990610 JLI [2.60 fixed some more high-sensitivity warnings] -** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names] -** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()] -** 991007 JLI [2.63 first shot at a 64-bit compatible version] -** 991009 JLI [2.64 undef's strdup() if defined, mwStrdup made const] -** 000704 JLI [2.65 added some more detection for 64-bits] -** 010502 JLI [2.66 incorporated some user fixes] -** [mwRelink() could print out garbage pointer (thanks mac@phobos.ca)] -** [added array destructor for C++ (thanks rdasilva@connecttel.com)] -** [added mutex support (thanks rdasilva@connecttel.com)] -** 010531 JLI [2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined] -** 010619 JLI [2.68 fix: mwRealloc() could leave the mutex locked] -** 020918 JLI [2.69 changed to GPL, added C++ array allocation by Howard Cohen] -** 030212 JLI [2.70 mwMalloc() bug for very large allocations (4GB on 32bits)] -** 030520 JLI [2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)] -** -** To use, simply include 'MEMWATCH.H' as a header file, -** and add MEMWATCH.C to your list of files, and define the macro -** 'MEMWATCH'. If this is not defined, MEMWATCH will disable itself. -** -** To call the standard C malloc / realloc / calloc / free; use mwMalloc_(), -** mwCalloc_() and mwFree_(). Note that mwFree_() will correctly -** free both malloc()'d memory as well as mwMalloc()'d. -** -** 980317: C++ support has been disabled. -** The code remains, but is not compiled. -** -** For use with C++, which allows use of inlining in header files -** and class specific new/delete, you must also define 'new' as -** 'mwNew' and 'delete' as 'mwDelete'. Do this *after* you include -** C++ header files from libraries, otherwise you can mess up their -** class definitions. If you don't define these, the C++ allocations -** will not have source file and line number information. Also note, -** most C++ class libraries implement their own C++ memory management, -** and don't allow anyone to override them. MFC belongs to this crew. -** In these cases, the only thing to do is to use MEMWATCH_NOCPP. -** -** You can capture output from MEMWATCH using mwSetOutFunc(). -** Just give it the adress of a "void myOutFunc(int c)" function, -** and all characters to be output will be redirected there. -** -** A failing ASSERT() or VERIFY() will normally always abort your -** program. This can be changed using mwSetAriFunc(). Give it a -** pointer to a "int myAriFunc(const char *)" function. Your function -** must ask the user whether to Abort, Retry or Ignore the trap. -** Return 2 to Abort, 1 to Retry or 0 to Ignore. Beware retry; it -** causes the expression to be evaluated again! MEMWATCH has a -** default ARI handler. It's disabled by default, but you can enable -** it by calling 'mwDefaultAri()'. Note that this will STILL abort -** your program unless you define MEMWATCH_STDIO to allow MEMWATCH -** to use the standard C I/O streams. Also, setting the ARI function -** will cause MEMWATCH *NOT* to write the ARI error to stderr. The -** error string is passed to the ARI function instead, as the -** 'const char *' parameter. -** -** You can disable MEMWATCH's ASSERT/VERIFY and/or TRACE implementations. -** This can be useful if you're using a debug terminal or smart debugger. -** Disable them by defining MW_NOASSERT, MW_NOVERIFY or MW_NOTRACE. -** -** MEMWATCH fills all allocated memory with the byte 0xFE, so if -** you're looking at erroneous data which are all 0xFE:s, the -** data probably was not initialized by you. The exception is -** calloc(), which will fill with zero's. All freed buffers are -** zapped with 0xFD. If this is what you look at, you're using -** data that has been freed. If this is the case, be aware that -** MEMWATCH places a 'free'd block info' structure immediately -** before the freed data. This block contains info about where -** the block was freed. The information is in readable text, -** in the format "FBIfilename(line)", for example: -** "FBI<267>test.c(12)". Using FBI's slows down free(), so it's -** disabled by default. Use mwFreeBufferInfo(1) to enable it. -** -** To aid in tracking down wild pointer writes, MEMWATCH can perform -** no-mans-land allocations. No-mans-land will contain the byte 0xFC. -** MEMWATCH will, when this is enabled, convert recently free'd memory -** into NML allocations. -** -** MEMWATCH protects it's own data buffers with checksums. If you -** get an internal error, it means you're overwriting wildly, -** or using an uninitialized pointer. -** -************************************************************************ -** -** Note when compiling with Microsoft C: -** - MSC ignores fflush() by default. This is overridden, so that -** the disk log will always be current. -** -** This utility has been tested with: -** PC-lint 7.0k, passed as 100% ANSI C compatible -** Microsoft Visual C++ on Win16 and Win32 -** Microsoft C on DOS -** SAS C on an Amiga 500 -** Gnu C on a PC running Red Hat Linux -** ...and using an (to me) unknown compiler on an Atari machine. -** -************************************************************************ -** -** Format of error messages in MEMWATCH.LOG: -** message: filename(linenumber), information -** -** Errors caught by MemWatch, when they are detected, and any -** actions taken besides writing to the log file MEMWATCH.LOG: -** -** Double-freeing: -** A pointer that was recently freed and has not since been -** reused was freed again. The place where the previous free() -** was executed is displayed. -** Detect: delete or free() using the offending pointer. -** Action: The delete or free() is cancelled, execution continues. -** Underflow: -** You have written just ahead of the allocated memory. -** The size and place of the allocation is displayed. -** Detect: delete or free() of the damaged buffer. -** Action: The buffer is freed, but there may be secondary damage. -** Overflow: -** Like underflow, but you've written after the end of the buffer. -** Detect: see Underflow. -** Action: see Underflow. -** WILD free: -** An unrecognized pointer was passed to delete or free(). -** The pointer may have been returned from a library function; -** in that case, use mwFree_() to force free() of it. -** Also, this may be a double-free, but the previous free was -** too long ago, causing MEMWATCH to 'forget' it. -** Detect: delete or free() of the offending pointer. -** Action: The delete or free() is cancelled, execution continues. -** NULL free: -** It's unclear to me whether or not freeing of NULL pointers -** is legal in ANSI C, therefore a warning is written to the log file, -** but the error counter remains the same. This is legal using C++, -** so the warning does not appear with delete. -** Detect: When you free(NULL). -** Action: The free() is cancelled. -** Failed: -** A request to allocate memory failed. If the allocation is -** small, this may be due to memory depletion, but is more likely -** to be memory fragmentation problems. The amount of memory -** allocated so far is displayed also. -** Detect: When you new, malloc(), realloc() or calloc() memory. -** Action: NULL is returned. -** Realloc: -** A request to re-allocate a memory buffer failed for reasons -** other than out-of-memory. The specific reason is shown. -** Detect: When you realloc() -** Action: realloc() is cancelled, NULL is returned -** Limit fail: -** A request to allocate memory failed since it would violate -** the limit set using mwLimit(). mwLimit() is used to stress-test -** your code under simulated low memory conditions. -** Detect: At new, malloc(), realloc() or calloc(). -** Action: NULL is returned. -** Assert trap: -** An ASSERT() failed. The ASSERT() macro works like C's assert() -** macro/function, except that it's interactive. See your C manual. -** Detect: On the ASSERT(). -** Action: Program ends with an advisory message to stderr, OR -** Program writes the ASSERT to the log and continues, OR -** Program asks Abort/Retry/Ignore? and takes that action. -** Verify trap: -** A VERIFY() failed. The VERIFY() macro works like ASSERT(), -** but if MEMWATCH is not defined, it still evaluates the -** expression, but it does not act upon the result. -** Detect: On the VERIFY(). -** Action: Program ends with an advisory message to stderr, OR -** Program writes the VERIFY to the log and continues, OR -** Program asks Abort/Retry/Ignore? and takes that action. -** Wild pointer: -** A no-mans-land buffer has been written into. MEMWATCH can -** allocate and distribute chunks of memory solely for the -** purpose of trying to catch random writes into memory. -** Detect: Always on CHECK(), but can be detected in several places. -** Action: The error is logged, and if an ARI handler is installed, -** it is executed, otherwise, execution continues. -** Unfreed: -** A memory buffer you allocated has not been freed. -** You are informed where it was allocated, and whether any -** over or underflow has occured. MemWatch also displays up to -** 16 bytes of the data, as much as it can, in hex and text. -** Detect: When MemWatch terminates. -** Action: The buffer is freed. -** Check: -** An error was detected during a CHECK() operation. -** The associated pointer is displayed along with -** the file and line where the CHECK() was executed. -** Followed immediately by a normal error message. -** Detect: When you CHECK() -** Action: Depends on the error -** Relink: -** After a MEMWATCH internal control block has been trashed, -** MEMWATCH tries to repair the damage. If successful, program -** execution will continue instead of aborting. Some information -** about the block may be gone permanently, though. -** Detect: N/A -** Action: Relink successful: program continues. -** Relink fails: program aborts. -** Internal: -** An internal error is flagged by MEMWATCH when it's control -** structures have been damaged. You are likely using an uninitialized -** pointer somewhere in your program, or are zapping memory all over. -** The message may give you additional diagnostic information. -** If possible, MEMWATCH will recover and continue execution. -** Detect: Various actions. -** Action: Whatever is needed -** Mark: -** The program terminated without umarking all marked pointers. Marking -** can be used to track resources other than memory. mwMark(pointer,text,...) -** when the resource is allocated, and mwUnmark(pointer) when it's freed. -** The 'text' is displayed for still marked pointers when the program -** ends. -** Detect: When MemWatch terminates. -** Action: The error is logged. -** -** -************************************************************************ -** -** The author may be reached by e-mail at the address below. If you -** mail me about source code changes in MEMWATCH, remember to include -** MW's version number. -** -** Johan Lindh -** johan@linkdata.se -** -** The latest version of MEMWATCH may be downloaded from -** http://www.linkdata.se/ -*/ - -#ifndef __MEMWATCH_H -#define __MEMWATCH_H - -/* Make sure that malloc(), realloc(), calloc() and free() are declared. */ -/*lint -save -e537 */ -#include -/*lint -restore */ - -/* strdup() */ -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* -** Constants used -** All MEMWATCH constants start with the prefix MW_, followed by -** a short mnemonic which indicates where the constant is used, -** followed by a descriptive text about it. -*/ - -#define MW_ARI_NULLREAD 0x10 /* Null read (to start debugger) */ -#define MW_ARI_ABORT 0x04 /* ARI handler says: abort program! */ -#define MW_ARI_RETRY 0x02 /* ARI handler says: retry action! */ -#define MW_ARI_IGNORE 0x01 /* ARI handler says: ignore error! */ - -#define MW_VAL_NEW 0xFE /* value in newly allocated memory */ -#define MW_VAL_DEL 0xFD /* value in newly deleted memory */ -#define MW_VAL_NML 0xFC /* value in no-mans-land */ -#define MW_VAL_GRB 0xFB /* value in grabbed memory */ - -#define MW_TEST_ALL 0xFFFF /* perform all tests */ -#define MW_TEST_CHAIN 0x0001 /* walk the heap chain */ -#define MW_TEST_ALLOC 0x0002 /* test allocations & NML guards */ -#define MW_TEST_NML 0x0004 /* test all-NML areas for modifications */ - -#define MW_NML_NONE 0 /* no NML */ -#define MW_NML_FREE 1 /* turn FREE'd memory into NML */ -#define MW_NML_ALL 2 /* all unused memory is NML */ -#define MW_NML_DEFAULT 0 /* the default NML setting */ - -#define MW_STAT_GLOBAL 0 /* only global statistics collected */ -#define MW_STAT_MODULE 1 /* collect statistics on a module basis */ -#define MW_STAT_LINE 2 /* collect statistics on a line basis */ -#define MW_STAT_DEFAULT 0 /* the default statistics setting */ - -/* -** MemWatch internal constants -** You may change these and recompile MemWatch to change the limits -** of some parameters. Respect the recommended minimums! -*/ -#define MW_TRACE_BUFFER 2048 /* (min 160) size of TRACE()'s output buffer */ -#define MW_FREE_LIST 64 /* (min 4) number of free()'s to track */ - -/* -** Exported variables -** In case you have to remove the 'const' keyword because your compiler -** doesn't support it, be aware that changing the values may cause -** unpredictable behaviour. -** - mwCounter contains the current action count. You can use this to -** place breakpoints using a debugger, if you want. -*/ -#ifndef __MEMWATCH_C -extern const unsigned long mwCounter; -#endif - -/* -** System functions -** Normally, it is not nessecary to call any of these. MEMWATCH will -** automatically initialize itself on the first MEMWATCH function call, -** and set up a call to mwAbort() using atexit(). Some C++ implementations -** run the atexit() chain before the program has terminated, so you -** may have to use mwInit() or the MemWatch C++ class to get good -** behaviour. -** - mwInit() can be called to disable the atexit() usage. If mwInit() -** is called directly, you must call mwTerm() to end MemWatch, or -** mwAbort(). -** - mwTerm() is usually not nessecary to call; but if called, it will -** call mwAbort() if it finds that it is cancelling the 'topmost' -** mwInit() call. -** - mwAbort() cleans up after MEMWATCH, reports unfreed buffers, etc. -*/ -void mwInit( void ); -void mwTerm( void ); -void mwAbort( void ); - -/* -** Setup functions -** These functions control the operation of MEMWATCH's protective features. -** - mwFlushNow() causes MEMWATCH to flush it's buffers. -** - mwDoFlush() controls whether MEMWATCH flushes the disk buffers after -** writes. The default is smart flushing: MEMWATCH will not flush buffers -** explicitly until memory errors are detected. Then, all writes are -** flushed until program end or mwDoFlush(0) is called. -** - mwLimit() sets the allocation limit, an arbitrary limit on how much -** memory your program may allocate in bytes. Used to stress-test app. -** Also, in virtual-memory or multitasking environs, puts a limit on -** how much MW_NML_ALL can eat up. -** - mwGrab() grabs up X kilobytes of memory. Allocates actual memory, -** can be used to stress test app & OS both. -** - mwDrop() drops X kilobytes of grabbed memory. -** - mwNoMansLand() sets the behaviour of the NML logic. See the -** MW_NML_xxx for more information. The default is MW_NML_DEFAULT. -** - mwStatistics() sets the behaviour of the statistics collector. See -** the MW_STAT_xxx defines for more information. Default MW_STAT_DEFAULT. -** - mwFreeBufferInfo() enables or disables the tagging of free'd buffers -** with freeing information. This information is written in text form, -** using sprintf(), so it's pretty slow. Disabled by default. -** - mwAutoCheck() performs a CHECK() operation whenever a MemWatch function -** is used. Slows down performance, of course. -** - mwCalcCheck() calculates checksums for all data buffers. Slow! -** - mwDumpCheck() logs buffers where stored & calc'd checksums differ. Slow!! -** - mwMark() sets a generic marker. Returns the pointer given. -** - mwUnmark() removes a generic marker. If, at the end of execution, some -** markers are still in existence, these will be reported as leakage. -** returns the pointer given. -*/ -void mwFlushNow( void ); -void mwDoFlush( int onoff ); -void mwLimit( long bytes ); -unsigned mwGrab( unsigned kilobytes ); -unsigned mwDrop( unsigned kilobytes ); -void mwNoMansLand( int mw_nml_level ); -void mwStatistics( int level ); -void mwFreeBufferInfo( int onoff ); -void mwAutoCheck( int onoff ); -void mwCalcCheck( void ); -void mwDumpCheck( void ); -void * mwMark( void *p, const char *description, const char *file, unsigned line ); -void * mwUnmark( void *p, const char *file, unsigned line ); - -/* -** Testing/verification/tracing -** All of these macros except VERIFY() evaluates to a null statement -** if MEMWATCH is not defined during compilation. -** - mwIsReadAddr() checks a memory area for read privilige. -** - mwIsSafeAddr() checks a memory area for both read & write privilige. -** This function and mwIsReadAddr() is highly system-specific and -** may not be implemented. If this is the case, they will default -** to returning nonzero for any non-NULL pointer. -** - CHECK() does a complete memory integrity test. Slow! -** - CHECK_THIS() checks only selected components. -** - CHECK_BUFFER() checks the indicated buffer for errors. -** - mwASSERT() or ASSERT() If the expression evaluates to nonzero, execution continues. -** Otherwise, the ARI handler is called, if present. If not present, -** the default ARI action is taken (set with mwSetAriAction()). -** ASSERT() can be disabled by defining MW_NOASSERT. -** - mwVERIFY() or VERIFY() works just like ASSERT(), but when compiling without -** MEMWATCH the macro evaluates to the expression. -** VERIFY() can be disabled by defining MW_NOVERIFY. -** - mwTRACE() or TRACE() writes some text and data to the log. Use like printf(). -** TRACE() can be disabled by defining MW_NOTRACE. -*/ -int mwIsReadAddr( const void *p, unsigned len ); -int mwIsSafeAddr( void *p, unsigned len ); -int mwTest( const char *file, int line, int mw_test_flags ); -int mwTestBuffer( const char *file, int line, void *p ); -int mwAssert( int, const char*, const char*, int ); -int mwVerify( int, const char*, const char*, int ); - -/* -** User I/O functions -** - mwTrace() works like printf(), but dumps output either to the -** function specified with mwSetOutFunc(), or the log file. -** - mwPuts() works like puts(), dumps output like mwTrace(). -** - mwSetOutFunc() allows you to give the adress of a function -** where all user output will go. (exeption: see mwSetAriFunc) -** Specifying NULL will direct output to the log file. -** - mwSetAriFunc() gives MEMWATCH the adress of a function to call -** when an 'Abort, Retry, Ignore' question is called for. The -** actual error message is NOT printed when you've set this adress, -** but instead it is passed as an argument. If you call with NULL -** for an argument, the ARI handler is disabled again. When the -** handler is disabled, MEMWATCH will automatically take the -** action specified by mwSetAriAction(). -** - mwSetAriAction() sets the default ARI return value MEMWATCH should -** use if no ARI handler is specified. Defaults to MW_ARI_ABORT. -** - mwAriHandler() is an ANSI ARI handler you can use if you like. It -** dumps output to stderr, and expects input from stdin. -** - mwBreakOut() is called in certain cases when MEMWATCH feels it would -** be nice to break into a debugger. If you feel like MEMWATCH, place -** an execution breakpoint on this function. -*/ -void mwTrace( const char* format_string, ... ); -void mwPuts( const char* text ); -void mwSetOutFunc( void (*func)(int) ); -void mwSetAriFunc( int (*func)(const char*) ); -void mwSetAriAction( int mw_ari_value ); -int mwAriHandler( const char* cause ); -void mwBreakOut( const char* cause ); - -/* -** Allocation/deallocation functions -** These functions are the ones actually to perform allocations -** when running MEMWATCH, for both C and C++ calls. -** - mwMalloc() debugging allocator -** - mwMalloc_() always resolves to a clean call of malloc() -** - mwRealloc() debugging re-allocator -** - mwRealloc_() always resolves to a clean call of realloc() -** - mwCalloc() debugging allocator, fills with zeros -** - mwCalloc_() always resolves to a clean call of calloc() -** - mwFree() debugging free. Can only free memory which has -** been allocated by MEMWATCH. -** - mwFree_() resolves to a) normal free() or b) debugging free. -** Can free memory allocated by MEMWATCH and malloc() both. -** Does not generate any runtime errors. -*/ -void* mwMalloc( size_t, const char*, int ); -void* mwMalloc_( size_t ); -void* mwRealloc( void *, size_t, const char*, int ); -void* mwRealloc_( void *, size_t ); -void* mwCalloc( size_t, size_t, const char*, int ); -void* mwCalloc_( size_t, size_t ); -void mwFree( void*, const char*, int ); -void mwFree_( void* ); -char* mwStrdup( const char *, const char*, int ); - -/* -** Enable/disable precompiler block -** This block of defines and if(n)defs make sure that references -** to MEMWATCH is completely removed from the code if the MEMWATCH -** manifest constant is not defined. -*/ -#ifndef __MEMWATCH_C -#ifdef MEMWATCH - -#define mwASSERT(exp) while(mwAssert((int)(exp),#exp,__FILE__,__LINE__)) -#ifndef MW_NOASSERT -#ifndef ASSERT -#define ASSERT mwASSERT -#endif /* !ASSERT */ -#endif /* !MW_NOASSERT */ -#define mwVERIFY(exp) while(mwVerify((int)(exp),#exp,__FILE__,__LINE__)) -#ifndef MW_NOVERIFY -#ifndef VERIFY -#define VERIFY mwVERIFY -#endif /* !VERIFY */ -#endif /* !MW_NOVERIFY */ -#define mwTRACE mwTrace -#ifndef MW_NOTRACE -#ifndef TRACE -#define TRACE mwTRACE -#endif /* !TRACE */ -#endif /* !MW_NOTRACE */ - -/* some compilers use a define and not a function */ -/* for strdup(). */ -#ifdef strdup -#undef strdup -#endif - -#define malloc(n) mwMalloc(n,__FILE__,__LINE__) -#define strdup(p) mwStrdup(p,__FILE__,__LINE__) -#define realloc(p,n) mwRealloc(p,n,__FILE__,__LINE__) -#define calloc(n,m) mwCalloc(n,m,__FILE__,__LINE__) -#define free(p) mwFree(p,__FILE__,__LINE__) -#define CHECK() mwTest(__FILE__,__LINE__,MW_TEST_ALL) -#define CHECK_THIS(n) mwTest(__FILE__,__LINE__,n) -#define CHECK_BUFFER(b) mwTestBuffer(__FILE__,__LINE__,b) -#define MARK(p) mwMark(p,#p,__FILE__,__LINE__) -#define UNMARK(p) mwUnmark(p,__FILE__,__LINE__) - -#else /* MEMWATCH */ - -#define mwASSERT(exp) -#ifndef MW_NOASSERT -#ifndef ASSERT -#define ASSERT mwASSERT -#endif /* !ASSERT */ -#endif /* !MW_NOASSERT */ - -#define mwVERIFY(exp) exp -#ifndef MW_NOVERIFY -#ifndef VERIFY -#define VERIFY mwVERIFY -#endif /* !VERIFY */ -#endif /* !MW_NOVERIFY */ - -/*lint -esym(773,mwTRACE) */ -#define mwTRACE /*lint -save -e506 */ 1?(void)0:mwDummyTraceFunction /*lint -restore */ -#ifndef MW_NOTRACE -#ifndef TRACE -/*lint -esym(773,TRACE) */ -#define TRACE mwTRACE -#endif /* !TRACE */ -#endif /* !MW_NOTRACE */ - -extern void mwDummyTraceFunction(const char *,...); -/*lint -save -e652 */ -#define mwDoFlush(n) -#define mwPuts(s) -#define mwInit() -#define mwGrab(n) -#define mwDrop(n) -#define mwLimit(n) -#define mwTest(f,l) -#define mwSetOutFunc(f) -#define mwSetAriFunc(f) -#define mwDefaultAri() -#define mwNomansland() -#define mwStatistics(f) -#define mwMark(p,t,f,n) (p) -#define mwUnmark(p,f,n) (p) -#define mwMalloc(n,f,l) malloc(n) -#define mwStrdup(p,f,l) strdup(p) -#define mwRealloc(p,n,f,l) realloc(p,n) -#define mwCalloc(n,m,f,l) calloc(n,m) -#define mwFree(p) free(p) -#define mwMalloc_(n) malloc(n) -#define mwRealloc_(p,n) realloc(p,n) -#define mwCalloc_(n,m) calloc(n,m) -#define mwFree_(p) free(p) -#define mwAssert(e,es,f,l) -#define mwVerify(e,es,f,l) (e) -#define mwTrace mwDummyTrace -#define mwTestBuffer(f,l,b) (0) -#define CHECK() -#define CHECK_THIS(n) -#define CHECK_BUFFER(b) -#define MARK(p) (p) -#define UNMARK(p) (p) -/*lint -restore */ - -#endif /* MEMWATCH */ -#endif /* !__MEMWATCH_C */ - -#ifdef __cplusplus - } -#endif - -#if 0 /* 980317: disabled C++ */ - -/* -** C++ support section -** Implements the C++ support. Please note that in order to avoid -** messing up library classes, C++ support is disabled by default. -** You must NOT enable it until AFTER the inclusion of all header -** files belonging to code that are not compiled with MEMWATCH, and -** possibly for some that are! The reason for this is that a C++ -** class may implement it's own new() function, and the preprocessor -** would substitute this crucial declaration for MEMWATCH new(). -** You can forcibly deny C++ support by defining MEMWATCH_NOCPP. -** To enble C++ support, you must be compiling C++, MEMWATCH must -** be defined, MEMWATCH_NOCPP must not be defined, and finally, -** you must define 'new' to be 'mwNew', and 'delete' to be 'mwDelete'. -** Unlike C, C++ code can begin executing *way* before main(), for -** example if a global variable is created. For this reason, you can -** declare a global variable of the class 'MemWatch'. If this is -** is the first variable created, it will then check ALL C++ allocations -** and deallocations. Unfortunately, this evaluation order is not -** guaranteed by C++, though the compilers I've tried evaluates them -** in the order encountered. -*/ -#ifdef __cplusplus -#ifndef __MEMWATCH_C -#ifdef MEMWATCH -#ifndef MEMWATCH_NOCPP -extern int mwNCur; -extern const char *mwNFile; -extern int mwNLine; -class MemWatch { -public: - MemWatch(); - ~MemWatch(); - }; -void * operator new(size_t); -void * operator new(size_t,const char *,int); -void * operator new[] (size_t,const char *,int); // hjc 07/16/02 -void operator delete(void *); -#define mwNew new(__FILE__,__LINE__) -#define mwDelete (mwNCur=1,mwNFile=__FILE__,mwNLine=__LINE__),delete -#endif /* MEMWATCH_NOCPP */ -#endif /* MEMWATCH */ -#endif /* !__MEMWATCH_C */ -#endif /* __cplusplus */ - -#endif /* 980317: disabled C++ */ - -#endif /* __MEMWATCH_H */ - -/* EOF MEMWATCH.H */ diff --git a/thirdparty/memwatch/memwatch.lsm b/thirdparty/memwatch/memwatch.lsm deleted file mode 100644 index a7742a3..0000000 --- a/thirdparty/memwatch/memwatch.lsm +++ /dev/null @@ -1,15 +0,0 @@ -Begin3 -Title: memwatch -Version: 2.71 -Entered-date: 2002-09-18 -Description: fault tolerant ANSI-C source code memory leak and corruption detection -Keywords: memwatch debugging library memory leak source code ansi c -Author: johan@linkdata.se -Maintained-by: johan@linkdata.se -Primary-site: ftp.linkdata.se /pub/memwatch - 42K memwatch-2.71.tar.gz -Alternate-site: -Original-site: ftp.linkdata.se /pub/memwatch -Platforms: all -Copying-policy: GPL -End diff --git a/thirdparty/memwatch/test.C b/thirdparty/memwatch/test.C deleted file mode 100644 index b4d847c..0000000 --- a/thirdparty/memwatch/test.C +++ /dev/null @@ -1,116 +0,0 @@ - -/* -** NOTE: Running this program in a Win32 or Unix environment -** will probably result in a segmentation fault or protection -** error. These errors may be caused by MEMWATCH when it is -** looking at memory to see if it owns it, or may be caused by -** the test program writing to memory it does not own. -** -** MEMWATCH has two functions called 'mwIsReadAddr()' and -** 'mwIsSafeAddr()', which are system-specific. -** If they are implemented for your system, and works -** correctly, MEMWATCH will identify garbage pointers and -** avoid causing segmentation faults, GP's etc. -** -** If they are NOT implemented, count on getting the core -** dumped when running this test program! As of this writing, -** the safe-address checking has been implemented for Win32 -** and ANSI-C compliant systems. The ANSI-C checking traps -** SIGSEGV and uses setjmp/longjmp to resume processing. -** -** Note for Win95 users: The Win32 IsBadReadPtr() and its -** similar functions can return incorrect values. This has -** not happened under WinNT, though, just Win95. -** -** 991009 Johan Lindh -** -*/ - -#include -#include -#include "memwatch.h" - -#ifndef SIGSEGV -#error "SIGNAL.H does not define SIGSEGV; running this program WILL cause a core dump/crash!" -#endif - -#ifndef MEMWATCH -#error "You really, really don't want to run this without memwatch. Trust me." -#endif - -#if !defined(MW_STDIO) && !defined(MEMWATCH_STDIO) -#error "Define MW_STDIO and try again, please." -#endif - -int main() -{ - char *p; - - /* Collect stats on a line number basis */ - mwStatistics( 2 ); - - /* Slows things down, but OK for this test prg */ - /* mwAutoCheck( 1 ); */ - - TRACE("Hello world!\n"); - - p = malloc(210); - free(p); - p = malloc(20); - p = malloc(200); /* causes unfreed error */ - p[-1] = 0; /* causes underflow error */ - free(p); - - p = malloc(100); - p[ -(int)(sizeof(long)*8) ] = -1; /* try to damage MW's heap chain */ - free( p ); /* should cause relink */ - - mwSetAriFunc( mwAriHandler ); - ASSERT(1==2); - - mwLimit(1000000); - mwNoMansLand( MW_NML_ALL ); - - /* These may cause a general protection fault (segmentation fault) */ - /* They're here to help test the no-mans-land protection */ - if( mwIsSafeAddr(p+50000,1) ) { - TRACE("Killing byte at %p\n", p+50000); - *(p+50000) = 0; - } - if( mwIsSafeAddr(p+30000,1) ) { - TRACE("Killing byte at %p\n", p+30000); - *(p+30000) = 0; - } - if( mwIsSafeAddr(p+1000,1) ) { - TRACE("Killing byte at %p\n", p+1000); - *(p+1000) = 0; - } - if( mwIsSafeAddr(p-100,1) ) { - TRACE("Killing byte at %p\n", p-100); - *(p-100) = 0; - } - - /* This may cause a GP fault as well, since MW data buffers */ - /* have been damaged in the above killing spree */ - CHECK(); - - p = malloc(12000); - p[-5] = 1; - p[-10] = 2; - p[-15] = 3; - p[-20] = 4; - - /* This may cause a GP fault since MW's buffer list may have */ - /* been damaged by above killing, and it will try to repair it. */ - free(p); - - p = realloc(p,10); /* causes realloc: free'd from error */ - - /* May cause GP since MW will inspect the memory to see if it owns it. */ - free( (void*)main ); - - return 0; -} - -/* Comment out the following line to compile. */ -#error "Hey! Don't just compile this program, read the comments first!" diff --git a/thirdparty/zlib-1.2.13.tar.gz b/thirdparty/zlib-1.2.13.tar.gz new file mode 100644 index 0000000..ba7c5a2 --- /dev/null +++ b/thirdparty/zlib-1.2.13.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30 +size 1497445 diff --git a/tools/prebuild.sh b/tools/prebuild.sh index aa79ca6..a84993a 100755 --- a/tools/prebuild.sh +++ b/tools/prebuild.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash -e # # JoeyDev @@ -23,34 +23,108 @@ ROOT=$1 +INSTALLED=${ROOT}/thirdparty-installed +THIRDPARTY=${ROOT}/thirdparty pushd "${ROOT}" || exit &> /dev/null - pushd thirdparty || exit &> /dev/null + mkdir -p ${INSTALLED}/include - if [[ ! -f scintilla/bin/scintilla.a ]]; then + pushd ${INSTALLED} || exit &> /dev/null + + if [[ ! -f ${INSTALLED}/memwatch/memwatch.c ]]; then + echo Unpacking Dependency: memwatch... + tar xjf ${THIRDPARTY}/memwatch.tar.bz2 + cp -f ${INSTALLED}/memwatch/memwatch.h ${INSTALLED}/include/. + fi + + if [[ ! -f ${INSTALLED}/include/stb_ds.h ]]; then + echo Installing Dependency: stb_ds... + cp -f ${THIRDPARTY}/stb_ds.h ${INSTALLED}/include/. + fi + + if [[ ! -f ${INSTALLED}/include/stb_image.h ]]; then + echo Installing Dependency: stb_image... + cp -f ${THIRDPARTY}/stb_image.h ${INSTALLED}/include/. + fi + + if [[ ! -f ${INSTALLED}/lib/libz.a ]]; then + echo Building Dependency: libz... + tar xzf ${THIRDPARTY}/zlib-1.2.13.tar.gz + pushd zlib-1.2.13 || exit &> /dev/null + ./configure \ + --static \ + --prefix=${INSTALLED} + make + make install + popd || true &> /dev/null + fi + + if [[ ! -f ${INSTALLED}/lib/libgpg-error.a ]]; then + echo Building Dependency: libgpg-error... + tar xjf ${THIRDPARTY}/libgpg-error-1.46.tar.bz2 + pushd libgpg-error-1.46 || exit &> /dev/null + ./configure \ + --enable-static \ + --disable-shared \ + --disable-doc \ + --disable-tests \ + --disable-languages \ + --prefix=${INSTALLED} + make + make install + popd || true &> /dev/null + fi + + if [[ ! -f ${INSTALLED}/lib/libgcrypt.a ]]; then + echo Building Dependency: libgcrypt... + tar xjf ${THIRDPARTY}/libgcrypt-1.10.1.tar.bz2 + pushd libgcrypt-1.10.1 || exit &> /dev/null + ./configure \ + --enable-static \ + --disable-shared \ + --disable-doc \ + --with-libgpg-error-prefix=${INSTALLED} \ + --prefix=${INSTALLED} + make + make install + popd || true &> /dev/null + fi + + if [[ ! -f ${INSTALLED}/lib/libssh2.a ]]; then + echo Building Dependency: libssh2... + tar xzf ${THIRDPARTY}/libssh2-1.10.0.tar.gz + pushd libssh2-1.10.0 || exit &> /dev/null + ./configure \ + --enable-static \ + --disable-shared \ + --with-crypto=libgcrypt \ + --with-libz-prefix=${INSTALLED} \ + --with-libgcrypt-prefix=${INSTALLED} \ + --prefix=${INSTALLED} + make + make install + popd || true &> /dev/null + fi + + if [[ ! -f ${INSTALLED}/lib/scintilla.a ]]; then echo Building Dependency: Scintilla... - tar xzf scintilla531.tgz + tar xzf ${THIRDPARTY}/scintilla531.tgz pushd scintilla/gtk || exit &> /dev/null GTK3=1 make + cp -f ../bin/scintilla.a ${INSTALLED}/lib/. + cp -f ../include/* ${INSTALLED}/include/. popd || true &> /dev/null fi - if [[ ! -f lexilla/bin/liblexilla.a ]]; then + if [[ ! -f ${INSTALLED}/lib/liblexilla.a ]]; then echo Building Dependency: Lexilla... - tar xzf lexilla520.tgz + tar xzf ${THIRDPARTY}/lexilla520.tgz pushd lexilla/src || exit &> /dev/null make - popd || true &> /dev/null - fi - - if [[ ! -f libssh2-1.10.0/src/libssh2.a ]]; then - echo Building Dependency: libssh2... - tar xzf libssh2-1.10.0.tar.gz - pushd libssh2-1.10.0 || exit &> /dev/null - cmake -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -DENABLE_ZLIB_COMPRESSION=ON -G Ninja -S . -B . - ninja + cp -f ../bin/liblexilla.a ${INSTALLED}/lib/. + cp -f ../include/* ${INSTALLED}/include/. popd || true &> /dev/null fi