Third-party libraries reorganized to make adding more easier. Start of SSH/SFTP code. libgcrypt, libgpg-error, libz, added.

This commit is contained in:
Scott Duensing 2022-12-20 20:41:14 -06:00
parent c218812ef7
commit 0c9b9c1487
20 changed files with 510 additions and 4360 deletions

2
.gitattributes vendored
View file

@ -1,2 +1,4 @@
*.gz filter=lfs diff=lfs merge=lfs -text
*.tgz 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 *.png filter=lfs diff=lfs merge=lfs -text

5
.gitignore vendored
View file

@ -1,14 +1,11 @@
.idea/ .idea/
.flatpak-builder/ .flatpak-builder/
crapForLater/ crapForLater/
thirdparty/scintilla/ thirdparty-installed/
thirdparty/lexilla/
thirdparty/libssh2-1.10.0/
ui/generated/ ui/generated/
cmake-build-debug/ cmake-build-debug/
flatpak-build/ flatpak-build/
flatpak-repo/ flatpak-repo/
crapForLater/
*~ *~
joeydev.flatpak joeydev.flatpak

View file

@ -37,7 +37,7 @@ option(DEBUG_MODE "Enable debugging output and memory tracing?" ON)
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
set(SOURCE_FILES set(SOURCE_FILES
thirdparty/memwatch/memwatch.c thirdparty-installed/memwatch/memwatch.c
ui/generated/resources.c ui/generated/resources.c
src/main.c src/main.c
src/utils.c src/utils.c
@ -50,6 +50,7 @@ set(SOURCE_FILES
src/color.c src/color.c
src/palette.c src/palette.c
src/project.c src/project.c
src/ssh.c
) )
configure_file(include/config.h.in config.h) 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 add_custom_target(GENERATE_UI_HEADERS
COMMAND ${CMAKE_SOURCE_DIR}/tools/prebuild.sh "${CMAKE_SOURCE_DIR}" COMMAND ${CMAKE_SOURCE_DIR}/tools/prebuild.sh "${CMAKE_SOURCE_DIR}"
BYPRODUCTS BYPRODUCTS
${CMAKE_SOURCE_DIR}/thirdparty/scintilla/bin/scintilla.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/memwatch/memwatch.c
${CMAKE_SOURCE_DIR}/thirdparty/lexilla/bin/liblexilla.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/scintilla.a
${CMAKE_SOURCE_DIR}/thirdparty/libssh2-1.10.0/src/libssh2.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) add_dependencies(${CMAKE_PROJECT_NAME} GENERATE_UI_HEADERS)
@ -77,10 +82,7 @@ include_directories(
${PROJECT_BINARY_DIR} ${PROJECT_BINARY_DIR}
include include
ui/generated ui/generated
thirdparty/libssh2-1.10.0/include thirdparty-installed/include
thirdparty/scintilla/include
thirdparty/lexilla/include
thirdparty/memwatch
) )
add_definitions( add_definitions(
@ -98,16 +100,16 @@ target_link_directories(${CMAKE_PROJECT_NAME} PUBLIC
target_link_libraries(${CMAKE_PROJECT_NAME} target_link_libraries(${CMAKE_PROJECT_NAME}
-rdynamic -rdynamic
${CMAKE_SOURCE_DIR}/thirdparty/scintilla/bin/scintilla.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/scintilla.a
${CMAKE_SOURCE_DIR}/thirdparty/lexilla/bin/liblexilla.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/liblexilla.a
${CMAKE_SOURCE_DIR}/thirdparty/libssh2-1.10.0/src/libssh2.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} ${GTK3_LIBRARIES}
# -lgpg-error
# -lssl # -lssl
# -lcrypto -ldl
# -ldl -pthread
# -pthread
# -lz
-lm -lm
-lstdc++ -lstdc++
) )

View file

@ -36,27 +36,7 @@ modules:
dest: tools dest: tools
- type: dir - type: dir
path: thirdparty/memwatch path: thirdparty/
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
dest: thirdparty/ dest: thirdparty/
- type: file - type: file

55
include/ssh.h Normal file
View file

@ -0,0 +1,55 @@
/*
* JoeyDev
* Copyright (C) 2018-2023 Scott Duensing <scott@kangaroopunch.com>
*
* 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

320
src/ssh.c Normal file
View file

@ -0,0 +1,320 @@
/*
* JoeyDev
* Copyright (C) 2018-2023 Scott Duensing <scott@kangaroopunch.com>
*
* 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 <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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; i<arrlen(_activeSSHs); i++) {
s = _activeSSHs[i];
if (!s->finished) {
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;
}

BIN
thirdparty/libgcrypt-1.10.1.tar.bz2 (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
thirdparty/libgpg-error-1.46.tar.bz2 (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
thirdparty/memwatch.tar.bz2 (Stored with Git LFS) vendored Normal file

Binary file not shown.

View file

@ -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.

View file

@ -1,2 +0,0 @@
test:
$(CC) -DMEMWATCH -DMW_STDIO test.c memwatch.c

View file

@ -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

View file

@ -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.

View file

@ -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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 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.

File diff suppressed because it is too large Load diff

View file

@ -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 "FBI<counter>filename(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: <sequence-number> 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 <stdlib.h>
/*lint -restore */
/* strdup() */
#include <string.h>
#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 */

View file

@ -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

View file

@ -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 <stdio.h>
#include <signal.h>
#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!"

BIN
thirdparty/zlib-1.2.13.tar.gz (Stored with Git LFS) vendored Normal file

Binary file not shown.

View file

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash -e
# #
# JoeyDev # JoeyDev
@ -23,34 +23,108 @@
ROOT=$1 ROOT=$1
INSTALLED=${ROOT}/thirdparty-installed
THIRDPARTY=${ROOT}/thirdparty
pushd "${ROOT}" || exit &> /dev/null 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... echo Building Dependency: Scintilla...
tar xzf scintilla531.tgz tar xzf ${THIRDPARTY}/scintilla531.tgz
pushd scintilla/gtk || exit &> /dev/null pushd scintilla/gtk || exit &> /dev/null
GTK3=1 make GTK3=1 make
cp -f ../bin/scintilla.a ${INSTALLED}/lib/.
cp -f ../include/* ${INSTALLED}/include/.
popd || true &> /dev/null popd || true &> /dev/null
fi fi
if [[ ! -f lexilla/bin/liblexilla.a ]]; then if [[ ! -f ${INSTALLED}/lib/liblexilla.a ]]; then
echo Building Dependency: Lexilla... echo Building Dependency: Lexilla...
tar xzf lexilla520.tgz tar xzf ${THIRDPARTY}/lexilla520.tgz
pushd lexilla/src || exit &> /dev/null pushd lexilla/src || exit &> /dev/null
make make
popd || true &> /dev/null cp -f ../bin/liblexilla.a ${INSTALLED}/lib/.
fi cp -f ../include/* ${INSTALLED}/include/.
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
popd || true &> /dev/null popd || true &> /dev/null
fi fi