Boehm GC - undefined reference to `GC_malloc'

J

Jack Trades

I've been having some problems using the Boehm Garbage Collector.
Initially I tried...
#include "gc.h"

which failed with a "No such file or directory". After a bit of
playing around I got it to work with...

#include "/usr/include/gc/gc.h"

While GC_INIT() works now but I get the following error when I try to
use GC_MALLOC or GC_malloc...

/tmp/cc9TT8nq.o: In function `alloc_object':
lispy.c:(.text+0xe): undefined reference to `GC_malloc'
....

I'm using Ubuntu 10.04 and libgc (however it also happens when I
compile the source from http://www.hpl.hp.com/personal/Hans_Boehm/gc/)

Thanks
Jack Trades
 
K

Keith Thompson

Jack Trades said:
I've been having some problems using the Boehm Garbage Collector.
Initially I tried...
#include "gc.h"

which failed with a "No such file or directory". After a bit of
playing around I got it to work with...

#include "/usr/include/gc/gc.h"

While GC_INIT() works now but I get the following error when I try to
use GC_MALLOC or GC_malloc...

/tmp/cc9TT8nq.o: In function `alloc_object':
lispy.c:(.text+0xe): undefined reference to `GC_malloc'
...

I'm using Ubuntu 10.04 and libgc (however it also happens when I
compile the source from http://www.hpl.hp.com/personal/Hans_Boehm/gc/)

The #include directive just tells the compiler where to find the
header that tells it what declarations are available. It doesn't
tell the linker where to find the code that actually implements
the functionality. (So why isn't this a problem for most of the
language-defined library? Because the files containing the code that
implements the standard C library are typically loaded by default.)

The documentation for Boehm GC should tell you how to do this.
On my system, "man GC_malloc" includes a good synopsis at the top
of the page:

SYNOPSIS
#include <gc.h>
void * GC_malloc(size_t size);
void GC_free(void *ptr);
void * GC_realloc(void *ptr, size_t size);

+ cc ... -I/usr/include/gc -lgc

The details might vary depending on your system.
 
A

August Karlstrom

I've been having some problems using the Boehm Garbage Collector.
Initially I tried...
#include "gc.h"

which failed with a "No such file or directory". After a bit of
playing around I got it to work with...

#include "/usr/include/gc/gc.h"

You only need

#include <gc/gc.h>

as /usr/include is in the default include path.
While GC_INIT() works now but I get the following error when I try to
use GC_MALLOC or GC_malloc...

/tmp/cc9TT8nq.o: In function `alloc_object':
lispy.c:(.text+0xe): undefined reference to `GC_malloc'
...

You need to link with the garbage collector by adding -lgc to the gcc
command, e.g.

gcc test.c -lgc


/August
 
J

Jack Trades

Thanks for the quick responses, that solved my problem of loading the
library (I think). However now I'm getting a segfault when I try to
use the function below 'alloc_object'.

I don't have the time right now to put together a minimal case to
reproduce the error, and won't until at least Monday. However is
there an inherent problem in using GC_MALLOC with this type of
struct? It works fine with malloc and I was under the impression that
GC_MALLOC was more-or-less a drop in replacement.

This is the first time I've used a debugger and it seemed to crash on
this line in alloc_object:
obj = GC_MALLOC(sizeof(object));


typedef struct object {
object_type type;
int refcount;
union {
long int fixnum;
double flonum;
char boolean;
char character;
char *string;
char *symbol;
struct {
struct object *car;
struct object *cdr;
} pair;
struct {
long int length;
struct object **vec;
} vector;
struct {
struct object *(*fn) (struct object *arguments);
} primitive_procedure;
struct {
struct object *parameters;
struct object *body;
struct object *env;
struct object *docstring;
} compound_procedure;
struct {
struct object *transformer;
} macro;
} data;
} object;


object *alloc_object(void) {
object *obj;

obj = GC_MALLOC(sizeof(object));
if (obj == NULL) {
error("Out of memory\n");
}
return obj;
}


Thanks for the help,
Jack Trades
 
B

BartC

Jack Trades said:
Thanks for the quick responses, that solved my problem of loading the
library (I think). However now I'm getting a segfault when I try to
use the function below 'alloc_object'.

I don't have the time right now to put together a minimal case to
reproduce the error, and won't until at least Monday. However is
there an inherent problem in using GC_MALLOC with this type of
struct? It works fine with malloc and I was under the impression that
GC_MALLOC was more-or-less a drop in replacement.

This is the first time I've used a debugger and it seemed to crash on
this line in alloc_object:
obj = GC_MALLOC(sizeof(object));

It's unlikely that it is actually crashing inside GC_MALLOC (unless things
have already gone badly wrong; assuming sizeof(object) is fairly sensible,
eg. 24 bytes).
typedef struct object {
object_type type;
int refcount;

Possibly you no longer need refcount if using GC. I would guess any code
that does things with refcount would need to be suppressed in case it
interferes. What have you done with the free() calls?
union {
long int fixnum;
double flonum;
char boolean;
char character;
char *string;
char *symbol;

These pointers of course will all start with garbage values, but that's also
the case under malloc() (unless you're relying perhaps on chance zero fields
from malloc that is no longer the case with GC_MALLOC).
object *alloc_object(void) {
object *obj;

obj = GC_MALLOC(sizeof(object));
if (obj == NULL) {
error("Out of memory\n");
}
return obj;
}

Is this actual code that is failing? I would check that GC_MALLOC() has
actually been properly linked in then, and the correct prototype has been
compiled. But this can be tested without involving 'object': eg.
GC_MALLOC(24).
 
J

Jack Trades

It's unlikely that it is actually crashing inside GC_MALLOC (unless things
have already gone badly wrong; assuming sizeof(object) is fairly sensible,
eg. 24 bytes).

That's exactly what it was.

Possibly you no longer need refcount if using GC. I would guess any code
that does things with refcount would need to be suppressed in case it
interferes. What have you done with the free() calls?

Actually refcount is never used. As for the free() calls, there are
none. This is my first project with C and only the 3rd interpreter
I've ever written so I wanted to keep it simple and did no memory
management.
These pointers of course will all start with garbage values, but that's also
the case under malloc() (unless you're relying perhaps on chance zero fields
from malloc that is no longer the case with GC_MALLOC).

I'm not sure exactly what you mean here. It was my understanding that
union meant "only one of these". Here's an example of the fixnum
constructor that is used in the code...

object *make_fixnum(long value) {
object *obj;

obj = alloc_object();
obj->type = FIXNUM;
obj->data.fixnum = value;
return obj;
}

So I don't think I'm relying on any zero fields. Though, honestly, I
don't have enough experience with C to know.
Is this actual code that is failing? I would check that GC_MALLOC() has
actually been properly linked in then, and the correct prototype has been
compiled. But this can be tested without involving 'object': eg.
GC_MALLOC(24).

From my run of the debugger I believe that it is the code that is
failing. I have successfully run the following test code...

#include <stdio.h>
#include <stdlib.h>
#include <gc/gc.h>

int main() {
char *a = GC_MALLOC(sizeof(char)*3);
a[0] = 'h';
a[1] = 'i';
a[2] = '\0';
printf("%s\n", a);
return 0;
}

Compiled with: gcc -lgc -o test test.c

This code works just fine and I have both #include <gc/gc.h> in the
source and -lgc in the gcc command. I have also tried to put...

void * GC_malloc(size_t size);
void GC_free(void *ptr);
void * GC_realloc(void *ptr, size_t size);

in the source and...

+ cc ... -I/usr/include/gc -lgc

in the gcc command.

My code is heavily based on Bootstrap Scheme by Peter Michaux. I
tried to use GC_MALLOC with his v0.1 code (which is relatively
simplistic) and it also produced a segfault. Code for that can be
found below.

http://github.com/petermichaux/bootstrap-scheme/tree/v0.1

I made sure to add the appropriate #include and -lgc options.

Thanks
Jack Trades
 
B

Ben Bacarisse

Jack Trades said:
That's exactly what it was.

Let me draw your attention to BartC's remark in parentheses: "unless
things have already gone badly wrong". The code you show where you
think the crash happens is very simple. It is overwhelmingly likely
that the error is somewhere else entirely. A write through some
indeterminate pointer or an out-of-bounds access or any of the other
pitfalls of C could result in a subsequent allocation failing in the way
you report.

Unless there is a likely candidate (i.e. some code you already have
doubts about) showing selected part of the program probably won't help.
I'd suggest two ways forward:

(a) Use a memory access checker like valgrind. I don't know how well it
works with GC_MALLOC but you can always arrange for GC_MALLOC to be a
macro that expands to plain malloc. I can't praise this program highly
enough.

(b) Start to cut down the program until you have a minimal example.
This may be hard because there are cases where it is a sequence of
actions following the original error that provokes the crash. Removing
any one of them can "fix" the problem but that does not mean the error
is in code you have just cut. The purpose is only to get the smallest
thing you can so the task of finding the error becomes simpler.

From my run of the debugger I believe that it is the code that is
failing.

It's possible but far more likely that something has gone wrong before
this and the problem only shows up when an allocation is made.

<snip>
 
J

Jack Trades

Thanks for the replies. I'm leaving for vacation soon so I'll work on
getting a minimal example this weekend.

Thanks again for the help,
Jack Trades
 
J

Jack Trades

Thanks again for all the help. I put together a minimal example and
found that renaming my 'read' procedure stopped the segfaults.
Apparently it was a namespace issue, but I can't find 'read' defined
in the gc source anywhere.

I'm still getting used to the single namespace of C. Is there any
utility that will print all the identifiers both defined and imported
in a particular C program?

Thanks
Jack Trades
 
B

Barry Schwarz

Thanks again for all the help. I put together a minimal example and
found that renaming my 'read' procedure stopped the segfaults.
Apparently it was a namespace issue, but I can't find 'read' defined
in the gc source anywhere.

I'm still getting used to the single namespace of C. Is there any

The get unused to it. There are at least four distinct name spaces in
C. See 6.2.3 for the details.
 
K

Keith Thompson

Jack Trades said:
Thanks again for all the help. I put together a minimal example and
found that renaming my 'read' procedure stopped the segfaults.
Apparently it was a namespace issue, but I can't find 'read' defined
in the gc source anywhere.

read() is a POSIX-defined input function. On Unix-like systems, it's
typically part of the standard library that's loaded by default.

The consequences of defining your own function with the same name
are likely to vary depending on which headers you include and/or
which compiler/linker options you use. A trivial example I just
tried worked (I named a function "read" and was able to call it),
but I can easily imagine that there might be circumstances where
what appears to be a call to your own read() function instead calls
the system-defined function, or vice versa.

If you specify C standard conforming mode it shouldn't be an issue,
but then you might not be able to use gc.

[...]
 
A

August Karlstrom

read() is a POSIX-defined input function. On Unix-like systems, it's
typically part of the standard library that's loaded by default.

The consequences of defining your own function with the same name
are likely to vary depending on which headers you include and/or
which compiler/linker options you use. A trivial example I just
tried worked (I named a function "read" and was able to call it),
but I can easily imagine that there might be circumstances where
what appears to be a call to your own read() function instead calls
the system-defined function, or vice versa.

If you specify C standard conforming mode it shouldn't be an issue,
but then you might not be able to use gc.

I noticed some strange behaviour too with the following test:

$ cat test.c
#include <stdio.h>
#include <gc/gc.h>


void read(void)
{
char *s;

puts("read()");
s = GC_malloc(32);
}


int main(void)
{
read();

return 0;
}
$ gcc -Wall -Wextra -ansi -pedantic -O3 test.c -lgc
$ ./a.out
read()
read()

The program outputs `read()' twice and doesn't terminate. What is happening?


/August
 
K

Keith Thompson

August Karlstrom said:
I noticed some strange behaviour too with the following test:

$ cat test.c
#include <stdio.h>
#include <gc/gc.h>


void read(void)
{
char *s;

puts("read()");
s = GC_malloc(32);
}


int main(void)
{
read();

return 0;
}
$ gcc -Wall -Wextra -ansi -pedantic -O3 test.c -lgc
$ ./a.out
read()
read()

The program outputs `read()' twice and doesn't terminate. What is happening?

Your read() calls GC_malloc(), which calls (via several intermediate
functions) GC_get_nprocs(), which attempts to call the POSIX read().
Apparently, since you've defined your own read() function, it calls that
instead. (I found this out by running your program under gdb and
getting a stack trace.)

More generally, even if you compile your own code in
standard-compliant mode, that doesn't affect any library code
your program uses. If your program includes a library that calls
read(), one possibly consequence is that it will call your own
read() function.
 
A

August Karlstrom

More generally, even if you compile your own code in
standard-compliant mode, that doesn't affect any library code
your program uses. If your program includes a library that calls
read(), one possibly consequence is that it will call your own
read() function.

Is this caused by the library (libgc in this case) not providing a
prototype for the POSIX function `read'? If it did, a conflict would be
detected by the linker, right?


/August
 
B

BartC

The documentation for Boehm GC should tell you how to do this.
On my system, "man GC_malloc" includes a good synopsis at the top
of the page:

SYNOPSIS
#include <gc.h>
void * GC_malloc(size_t size);
void GC_free(void *ptr);
void * GC_realloc(void *ptr, size_t size);

+ cc ... -I/usr/include/gc -lgc

The details might vary depending on your system.

If this GC supposed to be a standard part of gcc?

On my Mingw gcc 4.5 (which I've just upgraded from 3.4.5 because it didn't
have _make_), there's no trace of it. Yet some other Windows C compilers
seem to have it.
 
B

Ben Bacarisse

[Is] this GC supposed to be a standard part of gcc?

No, though there is no reason why some packaging of gcc might not
include it. It is entirely separate on my Linux system.

<snip>
 
L

lawrence.jones

August Karlstrom said:
Is this caused by the library (libgc in this case) not providing a
prototype for the POSIX function `read'? If it did, a conflict would be
detected by the linker, right?

No, it's caused by the POSIX read() function being in a library.
Library files are only included to resolve missing symbols -- since you
already provided a definition for read(), it's not a missing symbol so
the library definition doesn't get included and thus there's no
conflict. (Just the "wrong" definition.)
 
K

Keith Thompson

August Karlstrom said:
Is this caused by the library (libgc in this case) not providing a
prototype for the POSIX function `read'? If it did, a conflict would be
detected by the linker, right?

Prototypes are visible to the compiler, not to the linker. The linker
just sees symbols. The details are *extremely* system-specific.

A POSIX-conforming implementation does provide a prototype for read (in
<unistd.h>).
 
A

August Karlstrom

A POSIX-conforming implementation does provide a prototype for read (in
<unistd.h>).

OK, so if libgc did include the prototype for `read' in unistd.h I would
get a compilation error with my example.


/August
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top