diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2022-10-28 09:23:51 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2022-10-28 21:21:45 +0300 |
commit | d4c81638d9087f5c344b0e86de6b2b3827c84f58 (patch) | |
tree | 5a18846c33701c8346d98fcd4066916f92876f66 | |
parent | a37cdaa3b7a0c1ac4acc9213bb0a5fa4b4f852e9 (diff) | |
download | bdwgc-d4c81638d9087f5c344b0e86de6b2b3827c84f58.tar.gz |
Define public GC_[p]valloc() and redirect to them in leak_detector.h
Issue #495 (bdwgc).
* doc/README.macros (GC_NO_VALLOC): Document.
* doc/leak.md: Mention GNU valloc and pvalloc functions.
* include/gc/gc.h (GC_memalign): Remove comment that it is not tested;
add comment describing the functionality and a note.
* include/gc/gc.h [!GC_NO_VALLOC] (GC_valloc, GC_pvalloc): Declare
new API function.
* include/gc/leak_detector.h [!GC_NO_VALLOC] (valloc, pvalloc):
Redefine to the corresponding GC_ function.
* include/private/gc_priv.h (GC_page_size): Add comment.
* include/private/gc_priv.h (GC_real_page_size): Declare new variable
(or as a macro).
* include/private/gcconfig.h [NACL] (GETPAGESIZE): Add TODO item.
* mallocx.c (GC_memalign): Likewise.
* tests/gctest.c (run_one_test): Likewise.
* include/private/gcconfig.h [CYGWIN32 && (MPROTECT_VDB || USE_MUNMAP)
|| !MSWIN32 && !MSWINCE && !CYGWIN32 && (GC_DISABLE_INCREMENTAL
|| DEFAULT_VDB) && !USE_MMAP] (ALT_PAGESIZE_USED): Define macro.
* include/private/gcconfig.h [CYGWIN32 && (MPROTECT_VDB || USE_MUNMAP)
|| !MSWIN32 && !MSWINCE && !CYGWIN32 && (GC_DISABLE_INCREMENTAL
|| DEFAULT_VDB) && !USE_MMAP && !GC_NO_VALLOC] (REAL_PAGESIZE_NEEDED):
Likewise.
* mallocx.c (GC_strdup): Reformat comment.
* mallocx.c [!GC_NO_VALLOC] (GC_valloc, GC_pvalloc): Implement.
* os_dep.c [REAL_PAGESIZE_NEEDED] (GC_real_page_size): Define variable.
* os_dep.c [MSWIN32 || MSWINCE || CYGWIN32] (GC_setpagesize): Replace
CYGWIN32&&(MPROTECT_VDB||USE_MUNMAP) to ALT_PAGESIZE_USED; remove
comment that a separate variable could be added; reformat comment;
assert about GC_pagesize only if REAL_PAGESIZE_NEEDED.
* os_dep.c [ALT_PAGESIZE_USED && REAL_PAGESIZE_NEEDED]
(GC_setpagesize): Set GC_real_page_size.
* os_dep.c [!MSWIN32 && !MSWINCE && !CYGWIN32] (GC_setpagesize):
Replace MPROTECT_VDB||PROC_VDB||SOFT_VDB||USE_MMAP to
!ALT_PAGESIZE_USED.
* tests/gctest.c [!GC_NO_VALLOC] (run_one_test): Call GC_valloc() and
GC_pvalloc().
-rw-r--r-- | doc/README.macros | 3 | ||||
-rw-r--r-- | doc/leak.md | 10 | ||||
-rw-r--r-- | include/gc/gc.h | 10 | ||||
-rw-r--r-- | include/gc/leak_detector.h | 7 | ||||
-rw-r--r-- | include/private/gc_priv.h | 7 | ||||
-rw-r--r-- | include/private/gcconfig.h | 16 | ||||
-rw-r--r-- | mallocx.c | 22 | ||||
-rw-r--r-- | os_dep.c | 37 | ||||
-rw-r--r-- | tests/gctest.c | 14 |
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) @@ -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; @@ -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)) |