Plz explain me the following code

D

Dik T. Winter

> >
> > This one is well-defined and requires no explanation.
>
> Whether a text line requires a terminating new-line is
> implementation defined. There can be practical consequences
> to leaving it off. [e.g. on old line printers.]

I think somewhere a backslash has been lost.
 
J

James Kuyper

Processor-Dev1l said:
It is not correct, it is compiler dependent, that is the
difference :).

Phrases like "compiler dependent" sound like they are meant to be an
informal equivalent of what the standard refers to as "unspecified
behavior", a term which it defines as "use of an unspecified value, or
other behavior where this International Standard provides two or more
possibilities and imposes no further requirements on which is chosen in
any instance."

Unspecified behavior is relatively benign. There's very few, if any,
real world programs that don't involve any unspecified behavior. When
the set of possibilities is finite, portable code can be written to cope
with all of them. Even when the set of possibilities is infinite, if
they at least all share some common features, portable code can be
written which relies only upon those common features.

When (as is the case when using #pragma for pragmas that do not start
with "STDC"), the set of possibilities is completely unconstrained, it
might seem that unspecified behavior is indistinguishable from undefined
behavior - however, whenever this is the case, the behavior is not
merely unspecified, but implementation-defined. Such constructs should
never be used in portable code, but may be used in non-portable code
(possibly controlled by appropriate use if the #if family), with
complete confidence about their behavior. All that is needed is to the
implementation's standard-mandated documentation.

This code, on the other hand, has undefined behavior. That means that
the standard imposes no constraints on what the code can do. There is no
finite list of permissible behaviors. There is no common features shared
by all of the members of the infinite list of permitted behaviors. There
is no way to write portable code which copes with all of the possible
consequences, and no requirement that the implementation document what
it can do.

In the future, if only to avoid misunderstandings, please avoid using
"compiler dependent" to refer to undefined behavior; it carries
incorrectly benign connotations about the consequences of writing such code.
 
P

Processor-Dev1l

Phrases like "compiler dependent" sound like they are meant to be an
informal equivalent of what the standard refers to as "unspecified
behavior", a term which it defines as "use of an unspecified value, or
other behavior where this International Standard provides two or more
possibilities and imposes no further requirements on which is chosen in
any instance."

Unspecified behavior is relatively benign. There's very few, if any,
real world programs that don't involve any unspecified behavior. When
the set of possibilities is finite, portable code can be written to cope
with all of them. Even when the set of possibilities is infinite, if
they at least all share some common features, portable code can be
written which relies only upon those common features.

When (as is the case when using #pragma for pragmas that do not start
with "STDC"), the set of possibilities is completely unconstrained, it
might seem that unspecified behavior is indistinguishable from undefined
behavior - however, whenever this is the case, the behavior is not
merely unspecified, but implementation-defined. Such constructs should
never be used in portable code, but may be used in non-portable code
(possibly controlled by appropriate use if the #if family), with
complete confidence about their behavior. All that is needed is to the
implementation's standard-mandated documentation.

This code, on the other hand, has undefined behavior. That means that
the standard imposes no constraints on what the code can do. There is no
finite list of permissible behaviors. There is no common features shared
by all of the members of the infinite list of permitted behaviors. There
is no way to write portable code which copes with all of the possible
consequences, and no requirement that the implementation document what
it can do.

In the future, if only to avoid misunderstandings, please avoid using
"compiler dependent" to refer to undefined behavior; it carries
incorrectly benign connotations about the consequences of writing such code.

Ok, sorry for the "compiler dependent" phrase, I have heard a lot of
it on last meeting and it somehow came into my mind :)
 
N

Nick Keighley

Why? Because it works on USS cc modified compiler

You are missing the point. It DOES NOT work on a whatever-it-is.
This is because there is no behaviour specified for this construct.
Therefore an implementation can do whatever it likes. Therefore
whatever it does it isn't wrong (I wouldn't argue that it is right
though). The main reason the standard does this is to allow lee-way
(flexibility) to compiler implementors. Because of this it is
*very* likely that changes to optimisation or small changes
to the program can cause large chnages in behaviour.
Don't test stuff like this. Just don't write stuff like this.
and because I was trained to code this way :).

ask for your money back and get some proper training

I would do the test myself, but I have no access to common linux
kernel now.

if you want to waste your own time, fine. But why waste someone elses?
 
K

Keith Thompson

Processor-Dev1l said:
On Sep 22, 10:41 am, Barry Schwarz <[email protected]> wrote:

[big snip]
Congratz, yours was first acceptable answer :).

Several people had already said that the behavior is undefined; some
even quoted the section of the C standard that says the behavior
is undefined. How were those perfectly correct answers unacceptable?
Pitty is this style can be found even in some "ansi" C oriented books.
It's really a pitty because what is written should be right...

Really? What C books show code like that (other than as a deliberate
demonstration of undefined behavior)?

[...]
 
P

Processor-Dev1l

Processor-Dev1l said:
I just did a test on mainframe....
$ cat ctest.c
#include <stdio.h>
int main(void)
{
  int x;
  int y;
  x = 20;
  y = 35;
  x = y++ + x++;
  y = ++y + ++x;
  printf("x = %d, y = %d\n", x, y);
  return 0;} [...]
$ ./a.out
x = 57, y = 94
$
Everything what I want is someone with linux to try it with gcc
compiler, that is
all.
why? It is Undefined Behaviour. Even changing the compiler
optimisation
level may change the result
Why? Because it works on USS cc modified compiler

"Gives the output I thought I wanted" is one of the possible outcomes of
undefined behavior.

I ran it on my DS3K, and it reformatted the hard drive.  Now I have to
reinstall everything.  Fortunately, the hardware itself is still intact..
and because I was
trained to code this way :).

Trained to depend on how one particular release, of one particular compiler,
using one particular set of compilation settings, happens to behave?  I hope
you never have to patch or upgrade your compiler, or even make changes to
any of your source code, as doing so can change the behavior of your code..
I would do the test myself, but I have no access to common linux
kernel now...

Unless you are investigating what "undefined behavior" means, or have a
morbid need to inflict damage into others' computers, I see no need to do
any testing on the above code.

It "formatted your hard drive"?
Well, I don't see any way how this code can format hard drive.
Yes, there is possible memory leak, but it shouldn't affect harddisk
devices... Except one concrete case when leak would set registers and
called interrupt for work with pure data on disk...
I am sorry you haven't set up buffer overflow protection...

The reason why code work on mainframe can be that the whole USS is
just a managed subsystem of z/OS...
 
K

Keith Thompson

Processor-Dev1l said:
Processor-Dev1l wrote: [...]
Why? Because it works on USS cc modified compiler

"Gives the output I thought I wanted" is one of the possible outcomes of
undefined behavior.

I ran it on my DS3K, and it reformatted the hard drive.  Now I have to
reinstall everything.  Fortunately, the hardware itself is still intact.
and because I was
trained to code this way :).

Trained to depend on how one particular release, of one particular compiler,
using one particular set of compilation settings, happens to behave?  I hope
you never have to patch or upgrade your compiler, or even make changes to
any of your source code, as doing so can change the behavior of your code.
I would do the test myself, but I have no access to common linux
kernel now...

Unless you are investigating what "undefined behavior" means, or have a
morbid need to inflict damage into others' computers, I see no need to do
any testing on the above code.

It "formatted your hard drive"?
Well, I don't see any way how this code can format hard drive.
Yes, there is possible memory leak, but it shouldn't affect harddisk
devices... Except one concrete case when leak would set registers and
called interrupt for work with pure data on disk...
I am sorry you haven't set up buffer overflow protection...

The reason why code work on mainframe can be that the whole USS is
just a managed subsystem of z/OS...

The DS3K (originally the DS9K, or DeathStation 9000) is a mythical
machine with a C implementation that fully conforms to the letter
of the C standard, but on which undefined behavior generally results
in the worst possible outcome. For example, evaluating ``i = i++''
might erase your hard drive, and dividing by zero might launch
an ICBM.

There's also a standing joke that one of the possible results of
undefined behavior is making demons fly out of your nose ("nasal
demons").

It's all an exaggerated attempt to help people understand what
"undefined behavior" really means.

Here's what the C standard says about it:

3.4.3
1 undefined behavior
behavior, upon use of a nonportable or erroneous program construct
or of erroneous data, for which this International Standard
imposes no requirements

2 NOTE Possible undefined behavior ranges from ignoring the
situation completely with unpredictable results, to behaving
during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance
of a diagnostic message), to terminating a translation or
execution (with the issuance of a diagnostic message).

3 EXAMPLE An example of undefined behavior is the behavior on
integer overflow.

The key phrase is "imposes no requirements". If your implementation,
when your program evaluates ``i = i++'', caused time to start flowing
backwards, it might violate the laws of physics, but it wouldn't
violate the requirements of the C standard.

Formatting your hard drive is a more realistic consequence. You might
be confident that it can't possibly happen, because your program
doesn't run with enough privileges that it can even attempt to format
your hard drive. But in fact undefined behavior (particularly buffer
overflows) can have almost arbitrarily bad consequences. As I
understand it, viruses and other malware often take advantage of this
kind of thing.

Furthermore, for something like
int i = 42;
i = i++;

you might think that the only possible results are setting i to 42
or setting i to 43. But in fact an optimizing compiler is allowed
to *assume* that no undefined behavior occurs, and to rearrange
and rewrite the generated code based on that assumption. If the
assumption is violated, again, arbitrarily bad things can happen.

Your code, which exhibits undefined behavior, doesn't "work".
It might happen to behave in the way you expect, but there is
simply no basis in the C standard for any expectation of how it
should behave. The answer is not to figure out what the code
does; the answer is to fix the code so its behavior is defined
(and, for bonus points, correct).
 
P

Phil Carmody

Keith Thompson said:
Processor-Dev1l said:
On Sep 22, 10:41 am, Barry Schwarz <[email protected]> wrote:

[big snip]
Congratz, yours was first acceptable answer :).

Several people had already said that the behavior is undefined; some
even quoted the section of the C standard that says the behavior
is undefined. How were those perfectly correct answers unacceptable?

If anything, they were better answers. Attempting to explain possible
ways that UB may behave is counterproductive, IMHO.
Really? What C books show code like that (other than as a deliberate
demonstration of undefined behavior)?

Please not the 'S' word...

Phil
 
J

jameskuyper

Processor-Dev1l said:
Processor-Dev1l said:
On Sep 22, 10:13 am, Nick Keighley <[email protected]>
wrote:
I just did a test on mainframe....
$ cat ctest.c
#include <stdio.h>
int main(void)
{
int x;
int y;
x = 20;
y = 35;
x = y++ + x++;
y = ++y + ++x;
printf("x = %d, y = %d\n", x, y);
return 0;} [...]
$ ./a.out
x = 57, y = 94
$
Everything what I want is someone with linux to try it with gcc
compiler, that is
all.
why? It is Undefined Behaviour. Even changing the compiler
optimisation
level may change the result
Why? Because it works on USS cc modified compiler

"Gives the output I thought I wanted" is one of the possible outcomes of
undefined behavior.

I ran it on my DS3K, and it reformatted the hard drive. Now I have to
reinstall everything. Fortunately, the hardware itself is still intact.
....
It "formatted your hard drive"?
Well, I don't see any way how this code can format hard drive.

If you don't see how that can happen, that implies that you haven't
fully appreciated the significance of the part of the C standard which
says that when the behavior is undefined, "this International Standard
imposes no requirements". None. Nada. Zilch. Drill that into your
head. In some cases, something other than the ISO C standard may
impose relevant requirements (such as POSIX), in which case it may be
acceptable to write such code, so long as you only want to port it to
machines where that "something other" applies. However, unless
something else does impose relevant requirements, you should avoid
undefined behavior completely.

Unless, that is, you don't care what your program does. However, in
that case, why bother writing it in the first place? Not writing it,
and therefore not running it, is a lot easier, uses up less disk space
and less CPU time, and may have precisely the same effect as writing
it and executing it - "imposes no requirements" means that one of the
permitted results is that your program does absolutely nothing.

You may think "the standard may not impose any requirements, but
reality does - there's only a few realistic possibilities", but that's
an example of so-called "realism" gone soft in the brain. One of the
key purposes served by making the behavior undefined under certain
circumstances is that it allows implementions to implement various
optimizations without having to worry about the fact that those
optimizations might have unexpected consequences when applied to such
code. That means that such code has a good change of producing
arbitrarily bad unexpected consequences, as a result of such
optimizations.

Would you care to bet that you're able to anticipate every possible
way a compiler might choose to optimize your code, and thereby predict
what the consequences of those optimizations might be? Unless you have
been the sole author of a bleeding-edge aggressively optimizing C
compiler, I wouldn't recommend making such a bet, regardless of the
odds. Even if you were, the odds would have have to be pretty good to
justify such a bet.

You're much better off making certain that you avoid writing any code
unless there is something, somewhere (it doesn't have to be the C
standard) which imposes some meaningful requirements on the behavior
of your code.
 
S

Seebs

Nice you are quoting my typo :).

I don't care about the typo.

I was objecting to the notion that testing shows anything about definition.
You can also take a look at my test where I compiled and ran that
code.

I did.
If all you can do is to quote wrong post and to say only Wrong, you
are just jerk :).

I did explain why it was wrong.

The test doesn't prove anything. Something is not "defined" because you
happened to get a particular result; it's "defined" if the language standard
defines it.
Another thing that makes me thinking you are jerk is that you are
posting into already answered topic (greatly answered by Barry).

This is poor reasoning. Usenet is an asynchronous medium, and often,
people don't see each others' posts for hours or even days after they
were posted. In general, there is no expectation that people will refrain
from answering something that someone else might have.

(I do not assert that I am not a jerk, merely that your argument for the
position is flawed.)
I know maybe you will not understand if you have ever tried just one
compiler or you are thinking that all C compilers are from God and all
are the same with same parsing, etc.

I use multiple compilers, on multiple architectures. As a result, it's
become important to me to distinguish between what the language specifies
and what individual compilers might do.
Counting I used is a common counting for High Level Languages, these
are capable to parse such operations, I also tested the code on
machine and the result supported my idea, but I still never said it is
a standard.

Someone claimed that it was undefined. You ran a test, and claimed that
you had tested whether or not it was defined. This test could not address
the question, though.
So let's summarize it:
Is it possible for the code to work as I said? Yes, it is possible,
but it depends on the compiler
Is it standard for the code to work as I said? No, it is not!

It's not required, but nor is it impermissible.

The key point is that testing it doesn't tell you anything about whether
or not it is defined.

-s
 
B

Barry Schwarz

On Tue, 22 Sep 2009 01:55:19 -0700 (PDT), Processor-Dev1l

snip
Congratz, yours was first acceptable answer :).

Actually, my attempt at an intuitive explanation (which by definition
is therefore not rigorously correct) was an attempt to convince you
that the previous responses citing undefined behavior were the ones
you should be learning from.
Pitty is this style can be found even in some "ansi" C oriented books.
It's really a pitty because what is written should be right...

The only differences between bad information on the Internet and bad
information in traditional publications are the cost and speed of
dissemination.
for manish:
It is always better to use x++ on a standalone line except "for" cycle.

So you would deny the traditional strcpy sample of

while (*tgt++ = *src++)
;

in favor of

while (*tgt = *src){
tgt++;
src++;
}

To each his own.
 
N

Nick Keighley

[...] [...]
Everything what I want is someone with linux to try it with gcc
compiler, that is all.
why? It is Undefined Behaviour. [...]
Why? Because it works on USS cc modified compiler
"Gives the output I thought I wanted" is one of the possible outcomes of
undefined behavior.
I ran it on my DS3K, and it reformatted the hard drive.  Now I have to
reinstall everything.  Fortunately, the hardware itself is still intact. [...]
I would do the test myself, but I have no access to common linux
kernel now...
Unless you are investigating what "undefined behavior" means,

I don't see how writing test programs tells you anything about UB
It "formatted your hard drive"?
Well, I don't see any way how this code can format hard drive.

I agree it's unlikely. But apparently someone did get the
"I'm about to reformat the C: drive do you want to continue?"
DOS dialog from some undefined behaviour, but not I believe
for i = i++
Yes, there is possible memory leak,

again, not particularly likely
but it shouldn't affect harddisk
devices... Except one concrete case when leak would set registers

I don't think you know whate a memory leak is.
and
called interrupt for work with pure data on disk...

I suspect even if that were translated into english it would make
no sense
I am sorry you haven't set up buffer overflow protection...

The reason why code work on mainframe can be that the whole USS is
just a managed subsystem of z/OS

are you terminally thick? Which bit of "it doesn't work" didn't you
understand?
 
P

Processor-Dev1l

[...]> > >>>   x = y++ + x++;

[...]




Everything what I want is someone with linux to try it with gcc
compiler, that is all.
why? It is Undefined Behaviour. [...]
Why? Because it works on USS cc modified compiler
"Gives the output I thought I wanted" is one of the possible outcomes of
undefined behavior.
I ran it on my DS3K, and it reformatted the hard drive.  Now I have to
reinstall everything.  Fortunately, the hardware itself is still intact. [...]
I would do the test myself, but I have no access to common linux
kernel now...
Unless you are investigating what "undefined behavior" means,

I don't see how writing test programs tells you anything about UB
It "formatted your hard drive"?
Well, I don't see any way how this code can format hard drive.

I agree it's unlikely. But apparently someone did get the
"I'm about to reformat the C: drive do you want to continue?"
DOS dialog from some undefined behaviour, but not I believe
for i = i++
Yes, there is possible memory leak,

again, not particularly likely
but it shouldn't affect harddisk
devices... Except one concrete case when leak would set registers

I don't think you know whate a memory leak is.
Well, maybe I used incorrect definition...
I meant case when (thx to buffer overflow), something gets out of
memory allocated for the application and rewrite next part of memory.
The most horrible thing then would be when it would make instruction
for CPU to change data on HDD.
-Windows overwrites this function for data not to be directly
accessible in its pure form.
I suspect even if that were translated into english it would make
 no sense
interrupt = int
int 0x21 calls some basic functions (x86)
which function is used depends on settings of processor registers.
Register AX is commonly used to define number of function to be called
(its higher bits) and lower bits are used as a argument in x86
architecture.
are you terminally thick? Which bit of "it doesn't work" didn't you
understand?
Ok, repair:
Code printed result decided by me on mainframe because USS (Unix
System Services) is a managed subsystem with managed memory and code
execution.
 
P

Processor-Dev1l

On Tue, 22 Sep 2009 01:55:19 -0700 (PDT), Processor-Dev1l


snip


Actually, my attempt at an intuitive explanation (which by definition
is therefore not rigorously correct) was an attempt to convince you
that the previous responses citing undefined behavior were the ones
you should be learning from.
Well, it wasn't about me, I just wanted to help somehow the original
poster.
In the end it was great for me, because I learned something new (heard
of undefined behaviour for the first time)
The only differences between bad information on the Internet and bad
information in traditional publications are the cost and speed of
dissemination.
Yeah, maybe you are right, both printed and internet publications are
written by ppl so human failure is possible.
So you would deny the traditional strcpy sample of

    while (*tgt++ = *src++)
        ;

in favor of

    while (*tgt = *src){
        tgt++;
        src++;
        }

To each his own.
Well, I am not sure about security of this strcpy sample, I am not
really sure in this case, but this code can lead to the buffer
overflow if *src is bigger than *tgt.
 
P

Processor-Dev1l

I don't care about the typo.

I was objecting to the notion that testing shows anything about definition.


I did.


I did explain why it was wrong.

The test doesn't prove anything.  Something is not "defined" because you
happened to get a particular result; it's "defined" if the language standard
defines it.


This is poor reasoning.  Usenet is an asynchronous medium, and often,
people don't see each others' posts for hours or even days after they
were posted.  In general, there is no expectation that people will refrain
from answering something that someone else might have.
Sorry, I hadn't known which kind of notice you are using.
(I do not assert that I am not a jerk, merely that your argument for the
position is flawed.)


I use multiple compilers, on multiple architectures.  As a result, it's
become important to me to distinguish between what the language specifies
and what individual compilers might do.


Someone claimed that it was undefined.  You ran a test, and claimed that
you had tested whether or not it was defined.  This test could not address
the question, though.
I didn't wanted to claim the definition, I wanted just to prove my
calculation. When tested compiler had shown me "my result" I wanted to
know what gcc compiler would do with the same code. I am sorry it was
tested with other machine and other compiler and it caused such
damage.
It's not required, but nor is it impermissible.

The key point is that testing it doesn't tell you anything about whether
or not it is defined.
Sorry for misunderstanding, I really didn't want to prove that
definition of undefined behaviour is right or not.
 
J

James Kuyper

Processor-Dev1l said:
On Sep 23, 9:43�am, Nick Keighley <[email protected]>
wrote: ....
Well, maybe I used incorrect definition...
I meant case when (thx to buffer overflow), something gets out of
memory allocated for the application and rewrite next part of memory.

He's correct. You don't know what a memory leak is. A memory leak is
when a program allocates memory using malloc(), calloc(), or realloc(),
and fails to free it; some people would restrict the term "leak" to
those cases where the failure to free the memory was unintentional.

Memory leaks are mostly innocuous, except insofar as they make it more
likely that some future call to malloc(), calloc() or realloc() will fail.

I'm not sure there's any single standard term for what you describe, but
the consequence of what you're talking about can be referred to as
memory corruption.
The most horrible thing then would be when it would make instruction
for CPU to change data on HDD.

On systems without adequate memory protection, memory corruption could,
in principle, cause your program to do just about anything the operating
system has given it permission to do. Depending upon what those
permissions are, and depending upon what hardware that computer is
connected to, it might be able to do things MUCH worse than changing
data on the hard drive. Imagine the possibilities if, for instance, a
computer is able to control, directly or indirectly, a weapons system, a
nuclear power plant, the navigation system of an airplane, or (for
security reasons) a self-destruct mechanism, and your program has
permission to exercise that control.
 
J

James Kuyper

Processor-Dev1l said:
I didn't wanted to claim the definition, I wanted just to prove my
calculation.

I don't know what you mean by "prove my calculation"; but your test
program doesn't prove ANYTHING useful about your code. It doesn't prove
that the results of your calculation are correct. It doesn't prove that
the behavior of your code is defined. It doesn't even prove what the
behavior of your code is when compiled by your compiler and run on your
machine. Since the behavior is undefined, a compiler has permission to
generate code that will produce different results every time the program
runs. Or every tenth time it is run. Or every time the program runs at
the same time that another user is performing a directory listing.

While the test doesn't prove anything useful about your code, it does
prove something important about you. It proves that you still don't
understand why the test is meaningless.
... When tested compiler had shown me "my result" I wanted to
know what gcc compiler would do with the same code.

The fact that you wanted to know that proves that you still don't
understand just how meaningless the result you got is.
 
T

Tom St Denis

Well, it wasn't about me, I just wanted to help somehow the original
poster.
In the end it was great for me, because I learned something new (heard
of undefined behaviour for the first time)

If you're a C developer of any sort and are just learning about
undefined behaviour you need to put away your C compiler and read the
standard from start to finish. Really that's kinda bad.
Yeah, maybe you are right, both printed and internet publications are
written by ppl so human failure is possible.

The standard correctly identifies this as undefined behaviour, all of
the posts I've seen in this thread correctly identify it as such.
Your refusal to take them at their word notwithstanding, it's been
well covered here.
Well, I am not sure about security of this strcpy sample, I am not
really sure in this case, but this code can lead to the buffer
overflow if *src is bigger than *tgt.

Standard strcpy is not safe. But that's not the point. He wasn't
showing strncpy, he was showing strcpy as a real-life example of where
"putting the ++ expr on it's own line causes problems."

Tom
 
T

Tom St Denis

In

Tom St Denis wrote:



Er, yes it is - if used correctly. Any function can be used
incorrectly. Some functions cannot be used safely, but strcpy is not
one of them.

Safe being a relative term I suppose... Generally as part of safe
development practices I just avoid it and always use strncpy with
proper limits (and/or I enforce the length of the source by reporting
errors if it's too long).

Tom
 
W

Willem

Tom St Denis wrote:
) Safe being a relative term I suppose... Generally as part of safe
) development practices I just avoid it and always use strncpy with
) proper limits (and/or I enforce the length of the source by reporting
) errors if it's too long).

Are you kidding ? strncpy is less safe than strcpy, not to mention slower.
It was never meant to be 'strcpy-with-limits'.

They should put something like BSD's strlcpy in the standard, that would
actually be useful.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 

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,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top