summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/README.macros3
-rw-r--r--doc/leak.md10
-rw-r--r--include/gc/gc.h10
-rw-r--r--include/gc/leak_detector.h7
-rw-r--r--include/private/gc_priv.h7
-rw-r--r--include/private/gcconfig.h16
-rw-r--r--mallocx.c22
-rw-r--r--os_dep.c37
-rw-r--r--tests/gctest.c14
9 files changed, 102 insertions, 24 deletions
diff --git a/doc/README.macros b/doc/README.macros
index 8582f9ae..ed257208 100644
--- a/doc/README.macros
+++ b/doc/README.macros
@@ -98,6 +98,9 @@ GC_REQUIRE_WCSDUP Force GC to export GC_wcsdup() (the Unicode version
of GC_strdup); could be useful in the leak-finding mode. Clients should
define it before including gc.h if the function is needed.
+GC_NO_VALLOC Do not provide GC_valloc() and GC_pvalloc(), and do not
+ redirect the corresponding glibc functions in leak_detector.h.
+
FIND_LEAK Causes GC_find_leak to be initially set. This causes the
collector to assume that all inaccessible objects should have been
explicitly deallocated, and reports exceptions. Finalization and the test
diff --git a/doc/leak.md b/doc/leak.md
index 6381d9f0..3948d704 100644
--- a/doc/leak.md
+++ b/doc/leak.md
@@ -36,11 +36,11 @@ To use the collector as a leak detector, do the following steps:
The second step can usually be accomplished with the
`-DREDIRECT_MALLOC=GC_malloc` option when the collector is built, or by
defining `malloc`, `calloc`, `realloc`, `free` (as well as `strdup`,
-`strndup`, `wcsdup`, `memalign`, `posix_memalign`) to call the corresponding
-garbage collector functions. But this, by itself, will not yield very
-informative diagnostics, since the collector does not keep track of the
-information about how objects were allocated. The error reports will include
-only object addresses.
+`strndup`, `wcsdup`, `posix_memalign`, BSD `memalign`, GNU `valloc`, GNU
+`pvalloc`) to call the corresponding garbage collector functions. But this,
+by itself, will not yield very informative diagnostics, since the collector
+does not keep track of the information about how objects were allocated. The
+error reports will include only object addresses.
For more precise error reports, as much of the program as possible should use
the all uppercase variants of these functions, after defining `GC_DEBUG`, and
diff --git a/include/gc/gc.h b/include/gc/gc.h
index fec9402f..4ecc504d 100644
--- a/include/gc/gc.h
+++ b/include/gc/gc.h
@@ -551,11 +551,19 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
GC_malloc_uncollectable(size_t /* size_in_bytes */);
GC_API GC_ATTR_DEPRECATED void * GC_CALL GC_malloc_stubborn(size_t);
-/* GC_memalign() is not well tested. */
+/* The routines that guarantee the requested alignment of the allocated */
+/* memory object. Note that GC_base() and GC_size() might return the */
+/* value which is not the expected one (due to the alignment). */
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(2) void * GC_CALL
GC_memalign(size_t /* align */, size_t /* lb */);
GC_API int GC_CALL GC_posix_memalign(void ** /* memptr */, size_t /* align */,
size_t /* lb */) GC_ATTR_NONNULL(1);
+#ifndef GC_NO_VALLOC
+ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_valloc(size_t /* lb */);
+ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_pvalloc(size_t /* lb */);
+#endif /* !GC_NO_VALLOC */
/* Explicitly deallocate an object. Dangerous if used incorrectly. */
/* Requires a pointer to the base of an object. */
diff --git a/include/gc/leak_detector.h b/include/gc/leak_detector.h
index 5ee5b9ba..852b8e34 100644
--- a/include/gc/leak_detector.h
+++ b/include/gc/leak_detector.h
@@ -57,6 +57,13 @@
#undef posix_memalign
#define posix_memalign(p,a,n) GC_posix_memalign(p,a,n)
+#ifndef GC_NO_VALLOC
+# undef valloc
+# define valloc(n) GC_valloc(n)
+# undef pvalloc
+# define pvalloc(n) GC_pvalloc(n) /* obsolete */
+#endif /* !GC_NO_VALLOC */
+
#ifndef CHECK_LEAKS
# define CHECK_LEAKS() GC_gcollect()
/* Note 1: CHECK_LEAKS does not have GC prefix (preserved for */
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index ec8adcff..9d63c2de 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -1772,6 +1772,13 @@ GC_EXTERN struct obj_kind {
GC_EXTERN unsigned GC_n_kinds;
GC_EXTERN size_t GC_page_size;
+ /* May mean the allocation granularity size, not page size. */
+
+#ifdef REAL_PAGESIZE_NEEDED
+ GC_EXTERN size_t GC_real_page_size;
+#else
+# define GC_real_page_size GC_page_size
+#endif
/* Round up allocation size to a multiple of a page size. */
/* GC_setpagesize() is assumed to be already invoked. */
diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h
index 3a26bc9a..c5cfd01c 100644
--- a/include/private/gcconfig.h
+++ b/include/private/gcconfig.h
@@ -1182,7 +1182,7 @@ EXTERN_C_BEGIN
# define HEURISTIC1
# define NO_PTHREAD_GETATTR_NP
# define USE_MMAP_ANON
-# define GETPAGESIZE() 65536
+# define GETPAGESIZE() 65536 /* FIXME: Not real page size */
# define MAX_NACL_GC_THREADS 1024
# endif
@@ -2836,6 +2836,20 @@ EXTERN_C_BEGIN
# error Invalid config: GWW_VDB requires USE_WINALLOC
#endif
+/* Whether GC_page_size is to be set to a value other than page size. */
+#if defined(CYGWIN32) && (defined(MPROTECT_VDB) || defined(USE_MUNMAP)) \
+ || (!defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) \
+ && (defined(GC_DISABLE_INCREMENTAL) || defined(DEFAULT_VDB)) \
+ && !defined(USE_MMAP))
+ /* Cygwin: use the allocation granularity instead. */
+ /* Other than Windows: use HBLKSIZE instead (unless mmap() is used). */
+# define ALT_PAGESIZE_USED
+# ifndef GC_NO_VALLOC
+ /* Nonetheless, we need the real page size is some extra functions. */
+# define REAL_PAGESIZE_NEEDED
+# endif
+#endif
+
#if defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS) \
&& !defined(GC_WIN32_THREADS) && !defined(PLATFORM_STOP_WORLD) \
&& !defined(SN_TARGET_PSP2)
diff --git a/mallocx.c b/mallocx.c
index cb6dec07..aa441d2b 100644
--- a/mallocx.c
+++ b/mallocx.c
@@ -513,6 +513,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_memalign(size_t align, size_t lb)
}
/* We could also try to make sure that the real rounded-up object size */
/* is a multiple of align. That would be correct up to HBLKSIZE. */
+ /* TODO: Not space efficient for big align values. */
new_lb = SIZET_SAT_ADD(lb, align - 1);
result = (ptr_t)GC_malloc(new_lb);
/* It is OK not to check result for NULL as in that case */
@@ -554,8 +555,25 @@ GC_API int GC_CALL GC_posix_memalign(void **memptr, size_t align, size_t lb)
return 0;
}
-/* provide a version of strdup() that uses the collector to allocate the
- copy of the string */
+#ifndef GC_NO_VALLOC
+ GC_API GC_ATTR_MALLOC void * GC_CALL GC_valloc(size_t lb)
+ {
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
+ GC_ASSERT(GC_real_page_size != 0);
+ return GC_memalign(GC_real_page_size, lb);
+ }
+
+ GC_API GC_ATTR_MALLOC void * GC_CALL GC_pvalloc(size_t lb)
+ {
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
+ GC_ASSERT(GC_real_page_size != 0);
+ lb = SIZET_SAT_ADD(lb, GC_real_page_size - 1) & ~(GC_real_page_size - 1);
+ return GC_memalign(GC_real_page_size, lb);
+ }
+#endif /* !GC_NO_VALLOC */
+
+/* Provide a version of strdup() that uses the collector to allocate */
+/* the copy of the string. */
GC_API GC_ATTR_MALLOC char * GC_CALL GC_strdup(const char *s)
{
char *copy;
diff --git a/os_dep.c b/os_dep.c
index 2f105934..b56d9531 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -698,8 +698,11 @@ struct o32_obj {
# endif /* OS/2 */
-/* Find the page size */
+/* Find the page size. */
GC_INNER size_t GC_page_size = 0;
+#ifdef REAL_PAGESIZE_NEEDED
+ GC_INNER size_t GC_real_page_size = 0;
+#endif
#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
# ifndef VER_PLATFORM_WIN32_CE
@@ -715,17 +718,19 @@ GC_INNER size_t GC_page_size = 0;
GC_INNER void GC_setpagesize(void)
{
GetSystemInfo(&GC_sysinfo);
-# if defined(CYGWIN32) && (defined(MPROTECT_VDB) || defined(USE_MUNMAP))
+# ifdef ALT_PAGESIZE_USED
/* Allocations made with mmap() are aligned to the allocation */
- /* granularity, which (at least on Win64) is not the */
- /* same as the page size. Probably a separate variable could */
- /* be added to distinguish the allocation granularity from the */
- /* actual page size, but in practice there is no good reason to */
- /* make allocations smaller than dwAllocationGranularity, so we */
- /* just use it instead of the actual page size here (as Cygwin */
- /* itself does in many cases). */
+ /* granularity, which (at least on Win64) is not the same as the */
+ /* page size. Probably we could distinguish the allocation */
+ /* granularity from the actual page size, but in practice there */
+ /* is no good reason to make allocations smaller than */
+ /* dwAllocationGranularity, so we just use it instead of the */
+ /* actual page size here (as Cygwin itself does in many cases). */
GC_page_size = (size_t)GC_sysinfo.dwAllocationGranularity;
- GC_ASSERT(GC_page_size >= (size_t)GC_sysinfo.dwPageSize);
+# ifdef REAL_PAGESIZE_NEEDED
+ GC_real_page_size = (size_t)GC_sysinfo.dwPageSize;
+ GC_ASSERT(GC_page_size >= GC_real_page_size);
+# endif
# else
GC_page_size = (size_t)GC_sysinfo.dwPageSize;
# endif
@@ -816,16 +821,18 @@ GC_INNER size_t GC_page_size = 0;
#else /* !MSWIN32 */
GC_INNER void GC_setpagesize(void)
{
-# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(SOFT_VDB) \
- || defined(USE_MMAP)
+# ifdef ALT_PAGESIZE_USED
+# ifdef REAL_PAGESIZE_NEEDED
+ GC_real_page_size = (size_t)GETPAGESIZE();
+# endif
+ /* It's acceptable to fake it. */
+ GC_page_size = HBLKSIZE;
+# else
GC_page_size = (size_t)GETPAGESIZE();
# if !defined(CPPCHECK)
if (0 == GC_page_size)
ABORT("getpagesize failed");
# endif
-# else
- /* It's acceptable to fake it. */
- GC_page_size = HBLKSIZE;
# endif
}
#endif /* !MSWIN32 */
diff --git a/tests/gctest.c b/tests/gctest.c
index aefbaf93..86b448fe 100644
--- a/tests/gctest.c
+++ b/tests/gctest.c
@@ -1542,11 +1542,25 @@ void run_one_test(void)
(void)GC_malloc(17);
AO_fetch_and_add1(&collectable_count);
+ /* TODO: GC_memalign and friends are not tested well. */
for (i = sizeof(GC_word); i < 512; i *= 2) {
GC_word result = (GC_word) GC_memalign(i, 17);
if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL;
}
}
+# ifndef GC_NO_VALLOC
+ {
+ void *p = GC_valloc(78);
+
+ if (NULL == p || ((GC_word)p & 0x1ff /* at least */) != 0
+ || *(int *)p != 0)
+ FAIL;
+ p = GC_pvalloc(123);
+ /* Note: cannot check GC_size() result. */
+ if (NULL == p || ((GC_word)p & 0x1ff) != 0 || *(int *)p != 0)
+ FAIL;
+ }
+# endif
# ifndef ALL_INTERIOR_POINTERS
# if defined(POWERPC)
if (!TEST_FAIL_COUNT(1))