Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -349,11 +349,11 @@
/*
** Zero, unlock, and free the saved database encryption key now.
*/
db_unsave_encryption_key();
#endif
-#if defined(_WIN32) || defined(__BIONIC__) && !defined(FOSSIL_HAVE_GETPASS)
+#if defined(_WIN32) || (defined(__BIONIC__) && !defined(FOSSIL_HAVE_GETPASS))
/*
** Free the secure getpass() buffer now.
*/
freepass();
#endif
@@ -388,10 +388,17 @@
*/
if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){
if( g.interp ){
Th_DeleteInterp(g.interp); g.interp = 0;
}
+#if defined(TH_MEMDEBUG)
+ if( Th_GetOutstandingMalloc()!=0 ){
+ fossil_print("Th_GetOutstandingMalloc() => %d\n",
+ Th_GetOutstandingMalloc());
+ }
+ assert( Th_GetOutstandingMalloc()==0 );
+#endif
}
}
/*
** Convert all arguments from mbcs (or unicode) to UTF-8. Then
Index: src/makemake.tcl
==================================================================
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -1478,11 +1478,11 @@
OBJDIR = $(T)
OX = $(OBJDIR)
O = .obj
E = .exe
P = .pdb
-OPTLEVEL= /Os
+DBGOPTS = /Od
INSTALLDIR = .
!ifdef DESTDIR
INSTALLDIR = $(DESTDIR)\$(INSTALLDIR)
!endif
@@ -1501,10 +1501,15 @@
# Perl is only necessary if OpenSSL support is enabled and it is built from
# source code. The PERLDIR environment variable, if it exists, should point
# to the directory containing the main Perl executable specified here (i.e.
# "perl.exe").
PERL = perl.exe
+
+# Enable use of available compiler optimizations?
+!ifndef OPTIMIZATIONS
+OPTIMIZATIONS = 2
+!endif
# Enable debugging symbols?
!ifndef DEBUG
DEBUG = 0
!endif
@@ -1673,16 +1678,28 @@
CRTFLAGS = /MTd
!else
CRTFLAGS = /MT
!endif
!endif
+
+!if $(OPTIMIZATIONS)>3
+RELOPTS = /Os
+!elseif $(OPTIMIZATIONS)>2
+RELOPTS = /Ox
+!elseif $(OPTIMIZATIONS)>1
+RELOPTS = /O2
+!elseif $(OPTIMIZATIONS)>0
+RELOPTS = /O1
+!else
+RELOPTS =
+!endif
!if $(DEBUG)!=0
-CFLAGS = $(CFLAGS) /Zi $(CRTFLAGS) /Od /DFOSSIL_DEBUG
+CFLAGS = $(CFLAGS) /Zi $(CRTFLAGS) $(DBGOPTS) /DFOSSIL_DEBUG /DTH_MEMDEBUG
LDFLAGS = $(LDFLAGS) /DEBUG
!else
-CFLAGS = $(CFLAGS) $(CRTFLAGS) $(OPTLEVEL)
+CFLAGS = $(CFLAGS) $(CRTFLAGS) $(RELOPTS)
!endif
BCC = $(CC) $(CFLAGS)
TCC = $(CC) /c $(CFLAGS) $(MSCDEF) $(INCL)
RCC = $(RC) /D_WIN32 /D_MSC_VER $(MSCDEF) $(INCL)
Index: src/printf.c
==================================================================
--- src/printf.c
+++ src/printf.c
@@ -1100,11 +1100,11 @@
/*
** Avoid calling into the JSON support subsystem if it
** has not yet been initialized, e.g. early SQLite log
** messages, etc.
*/
- assert(json_is_bootstrapped_early());
+ if( !json_is_bootstrapped_early() ) json_bootstrap_early();
json_err( 0, z, 1 );
if( g.isHTTP && !g.json.preserveRc ){
rc = 0 /* avoid HTTP 500 */;
}
if( g.cgiOutput==1 ){
@@ -1230,11 +1230,11 @@
/*
** Avoid calling into the JSON support subsystem if it
** has not yet been initialized, e.g. early SQLite log
** messages, etc.
*/
- assert(json_is_bootstrapped_early());
+ if( !json_is_bootstrapped_early() ) json_bootstrap_early();
json_warn( FSL_JSON_W_UNKNOWN, "%s", z );
}else
#endif
{
if( g.cgiOutput==1 ){
Index: src/th.c
==================================================================
--- src/th.c
+++ src/th.c
@@ -222,11 +222,20 @@
Buffer *pBuffer,
const char *zAdd,
int nAdd
){
int nNew = (pBuffer->nBuf+nAdd)*2+32;
+#if defined(TH_MEMDEBUG)
+ char *zNew = (char *)Th_Malloc(interp, nNew);
+ th_memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf);
+ Th_Free(interp, pBuffer->zBuf);
+ pBuffer->zBuf = zNew;
+#else
+ int nOld = pBuffer->nBufAlloc;
pBuffer->zBuf = Th_Realloc(interp, pBuffer->zBuf, nNew);
+ memset(pBuffer->zBuf+nOld, 0, nNew-nOld);
+#endif
pBuffer->nBufAlloc = nNew;
th_memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd);
pBuffer->nBuf += nAdd;
}
static void thBufferWriteFast(
@@ -1535,10 +1544,37 @@
}else{
return (char *)Th_Malloc(pInterp, 1);
}
}
+#if defined(TH_MEMDEBUG)
+/*
+** Wrappers around the supplied malloc() and free()
+*/
+void *Th_DbgMalloc(Th_Interp *pInterp, int nByte){
+ void *p;
+ Th_Vtab *pVtab = pInterp->pVtab;
+ if( pVtab ){
+ p = pVtab->xMalloc(nByte);
+ if( p ) memset(p, 0, nByte);
+ }else{
+ p = Th_SysMalloc(pInterp, nByte);
+ }
+ return p;
+}
+void Th_DbgFree(Th_Interp *pInterp, void *z){
+ if( z ){
+ Th_Vtab *pVtab = pInterp->pVtab;
+ if( pVtab ){
+ pVtab->xFree(z);
+ }else{
+ Th_SysFree(pInterp, z);
+ }
+ }
+}
+#endif
+
/*
** Install a new th1 command.
**
** If a command of the same name already exists, it is deleted automatically.
*/
@@ -1821,16 +1857,24 @@
}
/*
** Create a new interpreter.
*/
-Th_Interp * Th_CreateInterp(void){
+Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){
+ int nByte = sizeof(Th_Interp) + sizeof(Th_Frame);
Th_Interp *p;
/* Allocate and initialise the interpreter and the global frame */
- p = Th_Malloc(0, sizeof(Th_Interp) + sizeof(Th_Frame));
- memset(p, 0, sizeof(Th_Interp));
+#if defined(TH_MEMDEBUG)
+ if( pVtab ){
+ p = pVtab->xMalloc(nByte);
+ memset(p, 0, nByte);
+ p->pVtab = pVtab;
+ }else
+#endif
+ p = Th_SysMalloc(0, nByte);
+
p->paCmd = Th_HashNew(p);
thPushFrame(p, (Th_Frame *)&p[1]);
thInitialize(p);
return p;
Index: src/th.h
==================================================================
--- src/th.h
+++ src/th.h
@@ -21,11 +21,11 @@
typedef struct Th_Interp Th_Interp;
/*
** Create and delete interpreters.
*/
-Th_Interp * Th_CreateInterp(void);
+Th_Interp * Th_CreateInterp(Th_Vtab *);
void Th_DeleteInterp(Th_Interp *);
/*
** Evaluate an TH program in the stack frame identified by parameter
** iFrame, according to the following rules:
@@ -121,16 +121,31 @@
/*
** Access the memory management functions associated with the specified
** interpreter.
*/
+#if defined(TH_MEMDEBUG)
+void *Th_DbgMalloc(Th_Interp *, int);
+void Th_DbgFree(Th_Interp *, void *);
+#endif
+
void *fossil_malloc_zero(size_t);
-void *fossil_realloc(void*,size_t);
-void fossil_free(void*);
-#define Th_Malloc(I,N) fossil_malloc_zero(N)
-#define Th_Realloc(I,P,N) fossil_realloc(P,N)
-#define Th_Free(I,P) fossil_free(P)
+void *fossil_realloc(void *, size_t);
+void fossil_free(void *);
+
+#define Th_SysMalloc(I,N) fossil_malloc_zero((N))
+#define Th_SysRealloc(I,P,N) fossil_realloc((P),(N))
+#define Th_SysFree(I,P) fossil_free((P))
+
+#if defined(TH_MEMDEBUG)
+# define Th_Malloc(I,N) Th_DbgMalloc((I),(N))
+# define Th_Free(I,P) Th_DbgFree((I),(P))
+#else
+# define Th_Malloc(I,N) Th_SysMalloc((I),(N))
+# define Th_Realloc(I,P,N) Th_SysRealloc((I),(P),(N))
+# define Th_Free(I,P) Th_SysFree((I),(P))
+#endif
/*
** Functions for handling TH lists.
*/
int Th_ListAppend(Th_Interp *, char **, int *, const char *, int);
Index: src/th_main.c
==================================================================
--- src/th_main.c
+++ src/th_main.c
@@ -68,10 +68,46 @@
** configuration ("user") database are currently open.
*/
#define Th_IsRepositoryOpen() (g.repositoryOpen)
#define Th_IsConfigOpen() (g.zConfigDbName!=0)
+/*
+** When memory debugging is enabled, use our custom memory allocator.
+*/
+#if defined(TH_MEMDEBUG)
+/*
+** Global variable counting the number of outstanding calls to malloc()
+** made by the th1 implementation. This is used to catch memory leaks
+** in the interpreter. Obviously, it also means th1 is not threadsafe.
+*/
+static int nOutstandingMalloc = 0;
+
+/*
+** Implementations of malloc() and free() to pass to the interpreter.
+*/
+static void *xMalloc(unsigned int n){
+ void *p = fossil_malloc(n);
+ if( p ){
+ nOutstandingMalloc++;
+ }
+ return p;
+}
+static void xFree(void *p){
+ if( p ){
+ nOutstandingMalloc--;
+ }
+ free(p);
+}
+static Th_Vtab vtab = { xMalloc, xFree };
+
+/*
+** Returns the number of outstanding TH1 memory allocations.
+*/
+int Th_GetOutstandingMalloc(){
+ return nOutstandingMalloc;
+}
+#endif
/*
** Generate a TH1 trace message if debugging is enabled.
*/
void Th_Trace(const char *zFormat, ...){
@@ -350,11 +386,11 @@
if(0==pOut && pThOut!=0){
pOut = pThOut;
}
if(TH_INIT_NO_ENCODE & g.th1Flags){
encode = 0;
- }
+ }
if( enableOutput && n ){
if( n<0 ) n = strlen(z);
if( encode ){
z = htmlize(z, n);
n = strlen(z);
@@ -627,10 +663,11 @@
blob_zero(&title); blob_zero(&body);
markdown_to_html(&src, &title, &body);
Th_ListAppend(interp, &zValue, &nValue, blob_str(&title), blob_size(&title));
Th_ListAppend(interp, &zValue, &nValue, blob_str(&body), blob_size(&body));
Th_SetResult(interp, zValue, nValue);
+ Th_Free(interp, zValue);
return TH_OK;
}
/*
** TH1 command: decorate STRING
@@ -810,15 +847,15 @@
}else if( azCap[i][0]=='*' ){
rc = 1;
}else{
rc = login_has_capability(azCap[i], anCap[i], 0);
}
- break;
+ break;
}
Th_Free(interp, azCap);
Th_SetResultInt(interp, rc);
- return TH_OK;
+ return TH_OK;
}
/*
** TH1 command: searchable STRING...
@@ -2356,11 +2393,20 @@
}
if( forceReset || forceTcl || g.interp==0 ){
int created = 0;
int i;
if( g.interp==0 ){
- g.interp = Th_CreateInterp();
+ Th_Vtab *pVtab = 0;
+#if defined(TH_MEMDEBUG)
+ if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){
+ pVtab = &vtab;
+ if( g.thTrace ){
+ Th_Trace("th1-init MEMDEBUG ENABLED
\n");
+ }
+ }
+#endif
+ g.interp = Th_CreateInterp(pVtab);
created = 1;
}
if( forceReset || created ){
th_register_language(g.interp); /* Basic scripting commands. */
}
Index: src/user.c
==================================================================
--- src/user.c
+++ src/user.c
@@ -38,11 +38,11 @@
if( z[i]>0 && z[i]<' ' ) z[i] = ' ';
}
blob_append(pBlob, z, -1);
}
-#if defined(_WIN32) || defined(__BIONIC__) && !defined(FOSSIL_HAVE_GETPASS)
+#if defined(_WIN32) || (defined(__BIONIC__) && !defined(FOSSIL_HAVE_GETPASS))
#ifdef _WIN32
#include
#endif
/*
Index: win/Makefile.msc
==================================================================
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -14,11 +14,11 @@
OBJDIR = $(T)
OX = $(OBJDIR)
O = .obj
E = .exe
P = .pdb
-OPTLEVEL= /Os
+DBGOPTS = /Od
INSTALLDIR = .
!ifdef DESTDIR
INSTALLDIR = $(DESTDIR)\$(INSTALLDIR)
!endif
@@ -37,10 +37,15 @@
# Perl is only necessary if OpenSSL support is enabled and it is built from
# source code. The PERLDIR environment variable, if it exists, should point
# to the directory containing the main Perl executable specified here (i.e.
# "perl.exe").
PERL = perl.exe
+
+# Enable use of available compiler optimizations?
+!ifndef OPTIMIZATIONS
+OPTIMIZATIONS = 2
+!endif
# Enable debugging symbols?
!ifndef DEBUG
DEBUG = 0
!endif
@@ -209,16 +214,28 @@
CRTFLAGS = /MTd
!else
CRTFLAGS = /MT
!endif
!endif
+
+!if $(OPTIMIZATIONS)>3
+RELOPTS = /Os
+!elseif $(OPTIMIZATIONS)>2
+RELOPTS = /Ox
+!elseif $(OPTIMIZATIONS)>1
+RELOPTS = /O2
+!elseif $(OPTIMIZATIONS)>0
+RELOPTS = /O1
+!else
+RELOPTS =
+!endif
!if $(DEBUG)!=0
-CFLAGS = $(CFLAGS) /Zi $(CRTFLAGS) /Od /DFOSSIL_DEBUG
+CFLAGS = $(CFLAGS) /Zi $(CRTFLAGS) $(DBGOPTS) /DFOSSIL_DEBUG /DTH_MEMDEBUG
LDFLAGS = $(LDFLAGS) /DEBUG
!else
-CFLAGS = $(CFLAGS) $(CRTFLAGS) $(OPTLEVEL)
+CFLAGS = $(CFLAGS) $(CRTFLAGS) $(RELOPTS)
!endif
BCC = $(CC) $(CFLAGS)
TCC = $(CC) /c $(CFLAGS) $(MSCDEF) $(INCL)
RCC = $(RC) /D_WIN32 /D_MSC_VER $(MSCDEF) $(INCL)