Re: [Gc] C optimizer hazards in practice
Richard Brooksby <[email protected]> Wed, 16 Jul 2014 16:04:06 +0100
| Newsgroups | gmane.comp.programming.garbage-collection.boehmgc |
|---|---|
| Message-ID | <[email protected]> |
On 2014-07-16, at 09:00, Richard Brooksby <[email protected]> wrote: > 2. We believe we have a repro using pointer types. We're working on inducing a failure with it now. The attached program links with BDWGC 7.4.0 to cause an access violation by reading a prematurely recycled object due to the last reference being optimized away. This program uses pointers to structures as its object type, and is therefore not bending the rules of the C standard. It's about 100 lines. We registered a finalizer to force overwriting of recycled objects to demonstrate the problem. Compile with Microsoft C 16.00.40219.01 for x64 (comes with Visual Studio 2010) like this: cl /Zi /I\path\to\gc-7.4.0\include /O2 update.c \path\to\gc-7.4.0\gc64_dll.lib user32.lib I'd appreciate it if someone out there would check that they get a repro using this example. _______________________________________________ bdwgc mailing list [email protected] https://lists.opendylan.org/mailman/listinfo/bdwgc
update.c
(application/octet-stream, 2.2 KB)
/* update.c -- demonstrate update_tree underscanning with BDWGC
*
* See thread <https://lists.opendylan.org/pipermail/bdwgc/2014-July/005981.html>.
*
* $Id: //info.ravenbrook.com/user/dl/test/bugs/update-tree-underscanning/update.c#12 $
*/
#include <malloc.h>
#include <stdlib.h>
#include <memory.h>
#define BOEHM
#ifdef BOEHM
#include <gc.h>
#define malloc(x) doalloc(x)
void GC_CALLBACK trashobj(void *p, void *cd) {
size_t s = (char*)cd - (char*)0;
memset(p, 0xcc, s);
}
void *doalloc(size_t s) {
void *p = GC_MALLOC(s);
GC_REGISTER_FINALIZER(p, trashobj,(char*)0+s, NULL,NULL);
return p;
}
#endif
double pupdate = 1;
int width = 2;
unsigned depth = 10;
typedef struct info_s *info_t;
typedef struct obj_s obj_s, *obj_t;
struct obj_s {
info_t info;
int good;
obj_t v[1];
};
#define objNULL ((obj_t)0)
obj_t mkvector(info_t info, size_t n) {
obj_t p = malloc(sizeof(obj_s) + (n-1)*sizeof (obj_t));
int i;
p->info = info;
p->good = 0x900d;
for(i = 0; i < n; i++)
p->v[i] = 0;
return p;
}
static obj_t aref(obj_t obj, size_t i) {
return obj->v[i];
}
static void aset(obj_t obj, size_t i, obj_t val) {
obj->v[i] = val;
}
static obj_t mktree(info_t info, unsigned d, obj_t leaf) {
obj_t tree;
size_t i;
if (d <= 0) return leaf;
tree = mkvector(info, width);
for (i = 0; i < width; ++i) {
aset(tree, i, mktree(info, d - 1, leaf));
}
return tree;
}
static obj_t update_tree(info_t info, obj_t oldtree, unsigned d) {
obj_t tree;
size_t i;
#ifdef KEEP_ROOT
void * volatile root = oldtree;
#endif
if (oldtree == objNULL || d == 0) {
GC_gcollect_and_unmap();
return oldtree;
}
if (info) {
tree = mkvector(info, width);
for (i = 0; i < width; ++i) {
aset(tree, i, update_tree(info, aref(oldtree, i), d - 1));
}
} else {
tree = oldtree;
}
#ifdef KEEP_ROOT
/* The following line prevents root from being overwritten keeping a
* reference to oldtree alive. */
root = root;
#endif
return tree;
}
int main(void)
{
info_t info;
int i;
obj_t tree;
GC_INIT();
info = malloc(1);
tree = mktree(info, depth, objNULL);
tree = update_tree(info, tree, depth);
return tree == 0;
}