pointer equality

I

Ike Naar

In K&R "The C++ programming language (2nd ANSI C edition), the reference
manual states (paragraphs 7.9 and 7.10) that pointer comparison is
undefined for pointers that do not point to the same object.

So if we have

const char * foo = "foo" , * bar = "bar" ;
int foobar = ( foo == bar ) ;

would it mean that foobar is undefined?

I knew that relational operators (<,<=,>=,>) cannot be used on pointers
to different objects, but how about equality operators ==,!= ?

Regards,
Ike

mail to ike at iae dot nl
 
C

Christian Bau

Ike Naar said:
In K&R "The C++ programming language (2nd ANSI C edition), the reference
manual states (paragraphs 7.9 and 7.10) that pointer comparison is
undefined for pointers that do not point to the same object.

So if we have

const char * foo = "foo" , * bar = "bar" ;
int foobar = ( foo == bar ) ;

would it mean that foobar is undefined?
I knew that relational operators (<,<=,>=,>) cannot be used on pointers
to different objects, but how about equality operators ==,!= ?

< <= > >= cannot be legally used on pointers to different objects; ==
and != can. So either the book you mentioned is wrong, or you missed
something when you read it. You might want to re-read it and see if it
mentions "relational operators" and "equality operators". If you are
sure you don't misunderstand anything, you should probably post a bit
more literally from that book.
 
L

Leor Zolman

In K&R "The C++ programming language (2nd ANSI C edition), the reference
manual states (paragraphs 7.9 and 7.10) that pointer comparison is
undefined for pointers that do not point to the same object.

So if we have

const char * foo = "foo" , * bar = "bar" ;
int foobar = ( foo == bar ) ;

would it mean that foobar is undefined?

How are you reading that? I'm seeing:

"Pointers to objects of the same type (ignoring any qualifiers)
may be compared"
I knew that relational operators (<,<=,>=,>) cannot be used on pointers
to different objects

Why not?
int a[10];
int *p1 = &a[3];
int *p2 = &a[4];
if (p2 > p1)
...

Perfectly legal.


, but how about equality operators ==,!= ?

Of course, to test if the pointers point to the same object or not...
-leor
 
I

Ike Naar

:> In K&R "The C++ programming language (2nd ANSI C edition), the reference
:> manual states (paragraphs 7.9 and 7.10) that pointer comparison is
:> undefined for pointers that do not point to the same object.

: < <= > >= cannot be legally used on pointers to different objects; ==
: and != can. So either the book you mentioned is wrong, or you missed
: something when you read it. You might want to re-read it and see if it
: mentions "relational operators" and "equality operators".

Thanks for your response.

Paragraph 7.9 describes relational operators and explains how these
operators can only be used on pointers pointing to the same object.

Paragraph 7.10 describes equality operators, and describes them as
analogous to relational operators, except that equality operators can
also be used to compare a pointer to an object and the null pointer.

: If you are
: sure you don't misunderstand anything, you should probably post a bit
: more literally from that book.

I don't have the book at hand now, but I can quote the paragraphs when
I get back to work in the morning.
 
I

Ike Naar

:>In K&R "The C++ programming language (2nd ANSI C edition), the reference
:>manual states (paragraphs 7.9 and 7.10) that pointer comparison is
:>undefined for pointers that do not point to the same object.

: How are you reading that? I'm seeing:
: "Pointers to objects of the same type (ignoring any qualifiers)
: may be compared"

The rest of that sentence mentions that the pointers should point
to the same object, and that the comparison is otherwise undefined.

: int a[10];
: int *p1 = &a[3];
: int *p2 = &a[4];
: if (p2 > p1)
: Perfectly legal.

That's what everybody would expect, but not what K&R seem to say.
 
J

Jeremy Yallop

Ike said:
:>In K&R "The C++ programming language (2nd ANSI C edition), the reference
:>manual states (paragraphs 7.9 and 7.10) that pointer comparison is
:>undefined for pointers that do not point to the same object.

: How are you reading that? I'm seeing:
: "Pointers to objects of the same type (ignoring any qualifiers)
: may be compared"

The rest of that sentence mentions that the pointers should point
to the same object, and that the comparison is otherwise undefined.

: int a[10];
: int *p1 = &a[3];
: int *p2 = &a[4];
: if (p2 > p1)
: Perfectly legal.

That's what everybody would expect, but not what K&R seem to say.

K&R, in A7.9, says:

"Pointer comparison is defined only for parts of the same object:
[...] if the pointers refer to members of an array, the comparison
is equivalent to comparison of the corresponding subscripts."

which covers Leor's example above. The undefined case is when the
pointers are to entirely distinct objects:

int a, b;
&a == &b; /* okay */
&a > &b; /* undefined */

It's the behaviour that's undefined, not just the result, so the
comparison could cause your program to crash (in theory, at least).

Jeremy.
 
M

Martin Dickopp

Leor Zolman said:
I knew that relational operators (<,<=,>=,>) cannot be used on pointers
to different objects

Why not?
int a[10];
int *p1 = &a[3];
int *p2 = &a[4];
if (p2 > p1)
...

Perfectly legal.

Both pointers point to "sub-objects" contained in the same aggregate
object `a'. This is probably what the OP meant: there must be a single
object into which both pointers point.

For example, this code causes UB:

int i, j, p1 = &i, p2 = &j;
p2 > p1;

Martin
 
I

Ike Naar

: K&R, in A7.9, says:
: "Pointer comparison is defined only for parts of the same object:
: [...] if the pointers refer to members of an array, the comparison
: is equivalent to comparison of the corresponding subscripts."
: [...]. The undefined case is when the
: pointers are to entirely distinct objects:
: int a, b;
: &a == &b; /* okay */

How could this be OK, if &a and &b are pointing to distinct objects?

: &a > &b; /* undefined */

: It's the behaviour that's undefined, not just the result, so the
: comparison could cause your program to crash (in theory, at least).

: Jeremy.
 
P

pete

Ike said:
: K&R, in A7.9, says:
: "Pointer comparison is defined only for parts of the same object:
: [...] if the pointers refer to members of an array, the comparison
: is equivalent to comparison of the corresponding subscripts."
: [...]. The undefined case is when the
: pointers are to entirely distinct objects:
: int a, b;
: &a == &b; /* okay */

How could this be OK, if &a and &b are pointing to distinct objects?

If &a and &b are pointing to distinct objects, then the value of
(&a == &b) is zero, and that's OK.

If &a and &b are pointing to distinct objects, then the value of
(&a > &b) is undefined, and that's bad.
 
R

Régis Troadec

"Ike Naar" <[email protected]> a écrit dans le message de

Hi,
: K&R, in A7.9, says:
: "Pointer comparison is defined only for parts of the same object:
: [...] if the pointers refer to members of an array, the comparison
: is equivalent to comparison of the corresponding subscripts."
: [...]. The undefined case is when the
: pointers are to entirely distinct objects:
: int a, b;
: &a == &b; /* okay */

How could this be OK, if &a and &b are pointing to distinct objects?

It's OK in the sense it's not a UB. &a == &b evaluates to false here.
Equality operators are much more reliable than relational operators in
relation to UB and don't lead specially to an UB if they are applied on
distinct objects (therefore, it often evaluates to false).
A case I know for witch an UB can occur for equality operators is when the
pointers you're going to compare (with equality ops) are invalid, like
accessing outside the bounds of arrays.

exple of (possible) UB :
....
int tab[10];
....
int *p = &tab[21];
int *q = &tab[32];
....
if (p != q) ...
{
}

Regis
 
K

Keith Thompson

Ike Naar said:
In K&R "The C++ programming language (2nd ANSI C edition), the reference
manual states (paragraphs 7.9 and 7.10) that pointer comparison is
undefined for pointers that do not point to the same object.

So if we have

const char * foo = "foo" , * bar = "bar" ;
int foobar = ( foo == bar ) ;

would it mean that foobar is undefined?

I knew that relational operators (<,<=,>=,>) cannot be used on pointers
to different objects, but how about equality operators ==,!= ?

I think you've found an error in K&R2. (BTW, it's "The C Programming
Language", not C++.) It's not mentioned in the errata at
<http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html> either.

Section A7.9, "Relational Operators", discusses the "<", ">", "<=",
and ">=" operators. It says, in part:

Pointers comparison is defined only for parts of the same object:
[...] Otherwise, pointer comparison is undefined.

Section A7.10, "Equality Operators", discusses the "==" and "!="
operators. It says, in part:

The equality operators follow the same rules as the relational
operators, but permit additional possibilities: a pointer may be
compared to a constant integral expression with value 0, or to a
pointer to void. See section A6.6.

(Section A6.6 doesn't address the issue of comparing pointers to
distinct objects for equality.)

The corresponding sections in the C90 and C99 standard say that
relational operators on pointers to distinct objects cause undefined
behavior (except perhaps in some obscure circumstances involving
objects that happen to be adjacent in memory), but doesn't make a
similar statement about equality operators, implying that equality
comparison of pointers to distinct objects is well-defined (and yields
the value 0).

I hesitate to suggest that the creators of the language got something
like this wrong; it can happen, but I'm hardly immune to making
mistakes myself. I encourage other readers to check my interpretation
and point out whether I've missed something or K&R have.
 
E

E. Robert Tisdale

Ike said:
In K&R "The C++ programming language (2nd ANSI C edition), the reference
manual states (paragraphs 7.9 and 7.10) that pointer comparison is
undefined for pointers that do not point to the same object.

So if we have

const char * foo = "foo" , * bar = "bar" ;
int foobar = ( foo == bar ) ;

would it mean that foobar is undefined?

I knew that relational operators (<,<=,>=,>)
cannot be used on pointers to different objects,
but how about equality operators ==,!= ?

> cat main.c
#include <stdio.h>
#include <stdlib.h>

int onStack(void* p) {
return (p > (void*)&p);
}

int main(int argc, char* argv[]) {
char c;
char* p = &c;
//char* p = (char*)malloc(sizeof(char));
if (onStack(p)) {
fprintf(stdout,"p probably points to a character "
"in automatic storage.\n");
}
else {
fprintf(stdout, "p probably points to static data "
"or free storage.\n");
}
return 0;
}
> gcc -Wall -std=c99 -pedantic -o main main.c
> ./main
p probably points to a character in automatic storage.

I also tested with Greg Comeau's C99 compiler:

http://www.comeaucomputing.com/pcgi-bin/compiler.cgi

Your Comeau C/C++ test results are as follows:

Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
Copyright 1988-2003 Comeau Computing. All rights reserved.
MODE:strict errors C99


In strict mode, with -tused, Compile succeeded
(but remember, the Comeau online compiler does not link).
 
I

Ike Naar

: I think you've found an error in K&R2. (BTW, it's "The C Programming
: Language", not C++.) It's not mentioned in the errata at
: <http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html> either.

I think you found an error in my article ;-)
Of course it should be "The C Programming Language".

: Section A7.9, "Relational Operators", discusses the "<", ">", "<=",
: and ">=" operators. It says, in part:
: Pointers comparison is defined only for parts of the same object:
: [...] Otherwise, pointer comparison is undefined.
: Section A7.10, "Equality Operators", discusses the "==" and "!="
: operators. It says, in part:
: The equality operators follow the same rules as the relational
: operators, but permit additional possibilities: a pointer may be
: compared to a constant integral expression with value 0, or to a
: pointer to void. See section A6.6.
: (Section A6.6 doesn't address the issue of comparing pointers to
: distinct objects for equality.)
: The corresponding sections in the C90 and C99 standard say that
: relational operators on pointers to distinct objects cause undefined
: behavior (except perhaps in some obscure circumstances involving
: objects that happen to be adjacent in memory), but doesn't make a
: similar statement about equality operators, implying that equality
: comparison of pointers to distinct objects is well-defined (and yields
: the value 0).
: I hesitate to suggest that the creators of the language got something
: like this wrong; it can happen, but I'm hardly immune to making
: mistakes myself. I encourage other readers to check my interpretation
: and point out whether I've missed something or K&R have.

I also found it hard to believe that equality comparison on valid
pointers to distinct objects would be UB, but K&R seemed to lead to
no other conclusion. That's why I asked the group.

Thank you for your response, anyway.

: --
: Keith Thompson (The_Other_Keith) (e-mail address removed) <http://www.ghoti.net/~kst>
: San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
: Schroedinger does Shakespeare: "To be *and* not to be"
 
K

Keith Thompson

E. Robert Tisdale said:
Ike Naar wrote: [...]
I knew that relational operators (<,<=,>=,>) cannot be used on
pointers to different objects,
but how about equality operators ==,!= ?
[sample code and output snipped; see parent article if you're curious.]

The behavior of the sample program proves nothing. The question is
whether comparison of pointers to different objects invokes undefined
behavior. Since undefined behavior can do anything, including
whatever you might expect it to do, and since compilers are not
required to diagnose undefined behavior, the behavior of doesn't say
anything one way or the other.

It's clear from the C90 standard, the C99 standard, and K&R2 that
applying a relational operator to pointers to distinct objects results
in undefined behavior (K&R2 says "Otherwise, pointer comparison is
undefined."; the pre-standard K&R1 merely says it isn't portable.)
You've demonstrated that one particular instance of undefined
behavior, in one particular case, results in the program printing
"p probably points to a character in automatic storage.", which is
neither surprising nor illuminating.

(I'm assuming here that "cannot be used" is short for "cannot be used
without invoking undefined behavior". Obviously it can be used if you
don't mind undefined behavior.)

The real question is whether equality comparison of pointers to
distinct objects results in undefined behavior. The C90 and C99
standards both imply that it doesn't; K&R2 implies that it does,
unless I've misunderstood it. I presume that wasn't the intent; it
seems obvious that P1==P2 should simply yield 0 if P1 and P2 point to
distinct objects. Do you have anything useful to add to that part of
the discussion?
 
A

Arthur J. O'Dwyer

I think you've found an error in K&R2. (BTW, it's "The C Programming
Language", not C++.) It's not mentioned in the errata at
<http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html> either.

I don't see any error in what you've posted, except for a probable
typo.
Section A7.9, "Relational Operators", discusses the "<", ">", "<=",
and ">=" operators. It says, in part:

Pointers comparison is defined only for parts of the same object:
[...] Otherwise, pointer comparison is undefined.

Shouldn't that read "Pointer comparison is..."? Did you make any
more serious typos? (It matters. ;-)
Anyway, that excerpt states explicitly that the behavior of the
following code is well-defined:

int bar[3];
(&bar[1] >= bar+2);

because '&bar[1]' and 'bar+2' point to parts of the same object. That
is, they both point to parts of the object 'bar', which is an array[3]
of int.
Section A7.10, "Equality Operators", discusses the "==" and "!="
operators. It says, in part:

The equality operators follow the same rules as the relational
operators, but permit additional possibilities: a pointer may be
compared to a constant integral expression with value 0, or to a
pointer to void. See section A6.6.

Looks good to me.
(Section A6.6 doesn't address the issue of comparing pointers to
distinct objects for equality.)

The corresponding sections in the C90 and C99 standard say that
relational operators on pointers to distinct objects cause undefined
behavior (except perhaps in some obscure circumstances involving
objects that happen to be adjacent in memory),

Nothing obscure about that circumstance! :) IIRC, the Standard
explicitly allows

int i;
int j;
printf("%d\n", &i+1 == &j)

to print "1", if j follows i in memory, even though &i+1 and &j point
to parts of different objects (&i points to the end of the object i,
and &j points to the object j). I don't recall any similar language
about relational operators, since the case

(&i < &j)

is explicitly covered by "undefined behavior" anyway, and can print 1,
or 0, or 42, or whatever it likes.
but doesn't make a
similar statement about equality operators, implying that equality
comparison of pointers to distinct objects is well-defined (and yields
the value 0).

Except in the circumstances above. I think you're right.
I hesitate to suggest that the creators of the language got something
like this wrong; it can happen, but I'm hardly immune to making
mistakes myself. I encourage other readers to check my interpretation
and point out whether I've missed something or K&R have.

So, what do you think K&R missed? It all looks there to me.

-Arthur
 
C

Christian Bau

Ike Naar said:
:> In K&R "The C++ programming language (2nd ANSI C edition), the reference
:> manual states (paragraphs 7.9 and 7.10) that pointer comparison is
:> undefined for pointers that do not point to the same object.

: < <= > >= cannot be legally used on pointers to different objects; ==
: and != can. So either the book you mentioned is wrong, or you missed
: something when you read it. You might want to re-read it and see if it
: mentions "relational operators" and "equality operators".

Thanks for your response.

Paragraph 7.9 describes relational operators and explains how these
operators can only be used on pointers pointing to the same object.

Then it is exactly as the C Standard says. Relational operators must
_not_ be used to compare pointers to different objects or compare any
pointer to a NULL pointer, equality operators are perfectly legal to
compare pointers to different objects and NULL pointers.

So (&foo == &bar) is legal, (&foo == NULL) is legal, (&foo >= &bar) is
not legal, (&foo >= NULL) is not legal, and even (NULL >= NULL) is not
legal, even though NULL == NULL and if x == y then you would expect x >=
y to be true.
 
C

Christian Bau

Ike Naar said:
: K&R, in A7.9, says:
: "Pointer comparison is defined only for parts of the same object:
: [...] if the pointers refer to members of an array, the comparison
: is equivalent to comparison of the corresponding subscripts."
: [...]. The undefined case is when the
: pointers are to entirely distinct objects:
: int a, b;
: &a == &b; /* okay */

How could this be OK, if &a and &b are pointing to distinct objects?

It is an equality operator, not a relational operator. The rules are
different for equality operators and relational operators.
 
K

Keith Thompson

Arthur J. O'Dwyer said:
I think you've found an error in K&R2. (BTW, it's "The C Programming
Language", not C++.) It's not mentioned in the errata at
<http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html> either.

I don't see any error in what you've posted, except for a probable
typo.
Section A7.9, "Relational Operators", discusses the "<", ">", "<=",
and ">=" operators. It says, in part:

Pointers comparison is defined only for parts of the same object:
[...] Otherwise, pointer comparison is undefined.

Shouldn't that read "Pointer comparison is..."? Did you make any
more serious typos? (It matters. ;-)

At the moment, I'm at home and my copy of K&R2 is at the office.
Since you can't cut-and-paste dead trees (well, I suppose you can if
you take it literally), I'll have to do this from memory. Yes, I'm
sure I meant "Pointer comparison is..."; I'll go back and proofread
the rest when I get a chance.
Anyway, that excerpt states explicitly that the behavior of the
following code is well-defined:

int bar[3];
(&bar[1] >= bar+2);

because '&bar[1]' and 'bar+2' point to parts of the same object. That
is, they both point to parts of the object 'bar', which is an array[3]
of int.
Agreed.
Section A7.10, "Equality Operators", discusses the "==" and "!="
operators. It says, in part:

The equality operators follow the same rules as the relational
operators, but permit additional possibilities: a pointer may be
compared to a constant integral expression with value 0, or to a
pointer to void. See section A6.6.

Looks good to me.

Almost; see below.
Nothing obscure about that circumstance! :) IIRC, the Standard
explicitly allows

int i;
int j;
printf("%d\n", &i+1 == &j)

to print "1", if j follows i in memory, even though &i+1 and &j point
to parts of different objects (&i points to the end of the object i,
and &j points to the object j). I don't recall any similar language
about relational operators, since the case

(&i < &j)

is explicitly covered by "undefined behavior" anyway, and can print 1,
or 0, or 42, or whatever it likes.

One might assume that if &i+1 == &j is true, then &i+1 <= &j and
&i+1 >= &j are also true, and &i+1 < &j and &i+1 > &j are false, but
yes, since the standard doesn't say so I suppose it's covered by
"undefined behavior". But this is not the main point.
but doesn't make a
similar statement about equality operators, implying that equality
comparison of pointers to distinct objects is well-defined (and yields
the value 0).

Except in the circumstances above. I think you're right. [...]
So, what do you think K&R missed? It all looks there to me.

But here's the problem. Suppose x and y are distinct objects of the
same type that do not happen to be adjacent. It's clear from the C90
and C99 standards and from K&R2 that the expression &x < &y invokes
undefined behavior (K&R1 merely says it's not portable). In the C90
and C99 standards, the statement about undefined behavior occurs in
the description of relational operators, but not in the description of
equality operators, so the expression &x == &y is well-defined (and
yields 0). In K&R2, the section on relational operators says that
&x < &y is undefined, but the section on equality operators refers
to the section on relational operators:

The equality operators follow the same rules as the relational
operators, but permit additional possibilities: a pointer may be
compared to a constant integral expression with value 0, or to a
pointer to void. See section A6.6.

implying that &x == &y is undefined, just as &x < &y is.
 
D

Dan Pop

In said:
I think you've found an error in K&R2. (BTW, it's "The C Programming

Not really. But the text really needs to be improved.
Language", not C++.) It's not mentioned in the errata at
<http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html> either.

Section A7.9, "Relational Operators", discusses the "<", ">", "<=",
and ">=" operators. It says, in part:

Pointers comparison is defined only for parts of the same object:
[...] Otherwise, pointer comparison is undefined.

Section A7.10, "Equality Operators", discusses the "==" and "!="
operators. It says, in part:

The equality operators follow the same rules as the relational
operators, but permit additional possibilities: a pointer may be
compared to a constant integral expression with value 0, or to a
pointer to void. See section A6.6.

(Section A6.6 doesn't address the issue of comparing pointers to
distinct objects for equality.)

The corresponding sections in the C90 and C99 standard say that
relational operators on pointers to distinct objects cause undefined
behavior (except perhaps in some obscure circumstances involving
objects that happen to be adjacent in memory), but doesn't make a
similar statement about equality operators, implying that equality
comparison of pointers to distinct objects is well-defined (and yields
the value 0).

I hesitate to suggest that the creators of the language got something
like this wrong; it can happen, but I'm hardly immune to making
mistakes myself. I encourage other readers to check my interpretation
and point out whether I've missed something or K&R have.

The key is in the "or to a pointer to void" words in A7.10. It means
you can compare a pointer to an object and a pointer to non-object for
equality, so the restriction that both pointers must point inside the
same object no longer applies. It's still not immediately obvious that
you can compare for equality object pointers that point to different
objects, but, since p == (void *)q is allowed regardless of where q
points (the text under discussion doesn't impose restrictions on the void
pointer operand), it follows that p == q should be valid, too (assuming
that the types of p and q allow direct comparison for equality).

As I said at the beginning, the text is far from optimal (or even
"clear enough", in the C committee lingo) and my interpretation was
heavily influenced by the fact that I already knew the right answer.

Dan
 
K

Keith Thompson

Arthur J. O'Dwyer said:
Section A7.9, "Relational Operators", discusses the "<", ">", "<=",
and ">=" operators. It says, in part:

Pointers comparison is defined only for parts of the same object:
[...] Otherwise, pointer comparison is undefined.

Shouldn't that read "Pointer comparison is..."? Did you make any
more serious typos? (It matters. ;-)

I just re-checked what I posted previously against my copy of K&R2.
I believe that typing "Pointers comparison" rather than "Pointer
comparison" is the only transcription error I made.

I have the first printing, with "Based on Draft-Proposed ANSI C"
on the cover. The text in question is not relevantly affected
by the on-line errata, though there is one change in a part of
that section that I didn't quote:

On p. 206, A7.9, about relational operators: ``Pointers to objects
of the same type may be compared...'' is changed to ``Pointers to
object of the same type >(ignoring any qualifiers)< may be
compared...''.
Anyway, that excerpt states explicitly that the behavior of the
following code is well-defined:

int bar[3];
(&bar[1] >= bar+2);

because '&bar[1]' and 'bar+2' point to parts of the same object. That
is, they both point to parts of the object 'bar', which is an array[3]
of int.
Section A7.10, "Equality Operators", discusses the "==" and "!="
operators. It says, in part:

The equality operators follow the same rules as the relational
operators, but permit additional possibilities: a pointer may be
compared to a constant integral expression with value 0, or to a
pointer to void. See section A6.6.

Looks good to me.
(Section A6.6 doesn't address the issue of comparing pointers to
distinct objects for equality.)

The corresponding sections in the C90 and C99 standard say that
relational operators on pointers to distinct objects cause undefined
behavior (except perhaps in some obscure circumstances involving
objects that happen to be adjacent in memory),
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top