C++ exception handling is defective

M

Marcus Kwok

Zorro said:
The simplicity of stack unraveling of C++ is not without defective
consequences. The following article points to C++ examples showing the
defects. An engineer aware of defects can avoid hard-to-find bugs.

http://distributed-software.blogspot.com/2007/01/c-exception-handling-is-defective.html

It seems you have confused C++ exceptions with "structured exception
handling" (SEH). SEH is provided as a Microsoft extension (you said you
were using VC++ 6.0), and Microsoft specifically says that SEH is not
specifically designed for, nor is it recommended, for C++, and that
regular C++ exception handling should be used in a C++ program.

If you use SEH, you must instead use the non-standard __try/__finally
construct.

See the following links for more information. Incidentally, one of the
examples demonstrates it with a divide-by-zero error:

http://msdn.microsoft.com/library/d...html/_core_exception_handling_differences.asp

http://msdn.microsoft.com/library/d...structured_exception_handling_with_c.2b2b.asp
 
I

Ian Collins

Zorro said:
OK. This is a direct answer, and I appreciate it. Let us be more
specific.
Please follow the advice I posted on quoting and using signatures, it
will make your posts easier to follow.
"Catching exceptions that were not thrown is not part of standard C++".
Such a beast does not exist. Something that isn't created with a throw
simply isn't an exception!
 
Z

Zorro

Marcus said:
It seems you have confused C++ exceptions with "structured exception
handling" (SEH). SEH is provided as a Microsoft extension (you said you
were using VC++ 6.0), and Microsoft specifically says that SEH is not
specifically designed for, nor is it recommended, for C++, and that
regular C++ exception handling should be used in a C++ program.

If you use SEH, you must instead use the non-standard __try/__finally
construct.

See the following links for more information. Incidentally, one of the
examples demonstrates it with a divide-by-zero error:

http://msdn.microsoft.com/library/d...html/_core_exception_handling_differences.asp

http://msdn.microsoft.com/library/d...structured_exception_handling_with_c.2b2b.asp

Thanks for the links Marcus. They make it clear that, if you do use
throw the destructors will be called with much less overhead. But if
you miss on some possible exception that may occur, then the jump to
the catch section will occur but the clean up may not be done as needed
(In MS context). Thus, it is the engineer that must remember every
little detail.

I was not talking about how to catch other kinds of exceptions (given
that I remember them in a complex program), but the comments went in
that direction. Also, I am saying this behavior is not unique to VC++.
If that were the case, this would end the discussion.

Whether or not a raised exception is "thrown", the control from the try
block makes a jump to the catch() section. That is what I meant by
"catching none-thrown exceptions".

Thanks again.

Regards,
(e-mail address removed)
http://www.zhmicro.com
http://distributed-software.blogspot.com
http://groups-beta.google.com/group/computerlangZ?lnk=la&hl=en
 
Z

Zorro

Simon said:
No. An exception that isn't thrown doesn't even exist. For an
exception to exist, it must be thrown. The throwing of an exception is
the creation of that exception.

Again, things that may be regarded as exceptions /outside/ of C++ /are
not/ C++ exceptions. A processor exception /is not an exception in
C++./ An exception thrown by an operating system /is not an exception
in C++./ The /only/ exceptions in C++ are exceptions thrown /within/ C++.

So, in a sense, yes: 'exceptions' that are not thrown /within/ C++
should not be caught /within/ C++. Except, of course, when it's a case
of undefined behaviour (such as with division by zero), in which case
anything's allowed to happen (including catching exceptions that weren't
thrown). That's what "undefined" means.

I will try to bring together your comments as a reply to Simon. My
apologies should I misinterpret your comments.

Replying to Simon.

You are very specific about not catching exceptions that were not
thrown within a program, because they do not even exist. This settles
the main aspect of the issue, assuming that is how the standard
stipulates this matter.
Then, you add, other events such as "file not found", "read
error" and "div by 0" put the program in an undefined state in
which it may behave in an undefined manner. I am asking if the standard
uses the term "undefined" in this context. Here is what Pete says.

"It means that the standard does not address it. Again: if your
implementation does this, you need to ask your compiler vendor for
details and, perhaps, for an explanation of how to use it".

So, does "undefined" mean that the standard does not address it, or
does it mean that the standard specifically mentions, "undefined
behavior"?

Erik says "It means that if you have code with a catch-block that
gets executed even though no exception has been thrown it is not
standard compliant behavior, I would even go as far as saying that it
is in direct violation of the standard".

A very specific and clear statement. But again, Erik immediately brings
up undefined behavior.

Is "undefined behavior", in this context, mentioned in the
standard? It will be nice someone familiar with standard to kindly
tells us where this is stated.

My opinion is what it was some 20 years ago with regard to the
implementation in the experimental compiler.

"If your design requires the use of throw in order to behave
logically, then it must remain oblivious with regard to an exception
not raised by a throw".

Please note that what this means is the following "For any exception
not thrown in a try block, the control must not jump to the catch
section".

Finally, considering the difficulty of implementation, it is fine to
make the jump (i.e. catch any exception as it comes), without having a
corresponding name for it. Just label them as "Unknown Exception",
but do the clean up so the program does not behave unpredictably.

The best way to resolve this is an answer like this. Standard item
number such and such states that .... Or, standard does not address
this issue for now.

Please note the following, which seems to get lost in your replies.

"When the majority (if not all) compilers do the same thing, one
takes the behavior for granted very much like an implicit standard.
Specifically, for exceptions not thrown by an application, they make
the jump to the catch section (the exceptions are caught anyway)".

You are addressing this issue by pointing to a particular example that
I have presented as "undefined". So, are you saying any none-thrown
exception is "undefined"? If not, can you give an example (and your
choice of compiler) that "does not catch a none-thrown exception"?

Regards,
(e-mail address removed)
http://www.zhmicro.com
http://distributed-software.blogspot.com
http://groups-beta.google.com/group/computerlangZ?lnk=la&hl=en
 
S

Simon G Best

Zorro said:
Whether or not a raised exception is "thrown", the control from the try
block makes a jump to the catch() section. That is what I meant by
"catching none-thrown exceptions".

Exceptions are raised *by throwing them.* In C++, that's what raising
an exception is. You can't have a raised exception that isn't thrown,
because you can't have a /thrown/ exception that isn't thrown.
 
I

Ian Collins

Zorro wrote:

*PLEASE* follow my advice on regarding signatures!
Please note the following, which seems to get lost in your replies.

"When the majority (if not all) compilers do the same thing, one
takes the behavior for granted very much like an implicit standard.
Specifically, for exceptions not thrown by an application, they make
the jump to the catch section (the exceptions are caught anyway)".
The only platform I know that does this in windows, so there isn't any
de facto standard here.
You are addressing this issue by pointing to a particular example that
I have presented as "undefined". So, are you saying any none-thrown
exception is "undefined"? If not, can you give an example (and your
choice of compiler) that "does not catch a none-thrown exception"?
It's beyond undefined, it's outside of the scope of the C++ standard and
squarely in the scope of the operating environment.

If the operating environment chooses to abort an application in the
event of a asynchronous event, there is nothing the C++ compiler can do
to circumvent this behaviour.
 
Z

Zorro

Zorro said:
I will try to bring together your comments as a reply to Simon. My
apologies should I misinterpret your comments.

Replying to Simon.

You are very specific about not catching exceptions that were not
thrown within a program, because they do not even exist. This settles
the main aspect of the issue, assuming that is how the standard
stipulates this matter.
Then, you add, other events such as "file not found", "read
error" and "div by 0" put the program in an undefined state in
which it may behave in an undefined manner. I am asking if the standard
uses the term "undefined" in this context. Here is what Pete says.

"It means that the standard does not address it. Again: if your
implementation does this, you need to ask your compiler vendor for
details and, perhaps, for an explanation of how to use it".

So, does "undefined" mean that the standard does not address it, or
does it mean that the standard specifically mentions, "undefined
behavior"?

Erik says "It means that if you have code with a catch-block that
gets executed even though no exception has been thrown it is not
standard compliant behavior, I would even go as far as saying that it
is in direct violation of the standard".

A very specific and clear statement. But again, Erik immediately brings
up undefined behavior.

Is "undefined behavior", in this context, mentioned in the
standard? It will be nice someone familiar with standard to kindly
tells us where this is stated.

My opinion is what it was some 20 years ago with regard to the
implementation in the experimental compiler.

"If your design requires the use of throw in order to behave
logically, then it must remain oblivious with regard to an exception
not raised by a throw".

Please note that what this means is the following "For any exception
not thrown in a try block, the control must not jump to the catch
section".

Finally, considering the difficulty of implementation, it is fine to
make the jump (i.e. catch any exception as it comes), without having a
corresponding name for it. Just label them as "Unknown Exception",
but do the clean up so the program does not behave unpredictably.

The best way to resolve this is an answer like this. Standard item
number such and such states that .... Or, standard does not address
this issue for now.

Please note the following, which seems to get lost in your replies.

"When the majority (if not all) compilers do the same thing, one
takes the behavior for granted very much like an implicit standard.
Specifically, for exceptions not thrown by an application, they make
the jump to the catch section (the exceptions are caught anyway)".

You are addressing this issue by pointing to a particular example that
I have presented as "undefined". So, are you saying any none-thrown
exception is "undefined"? If not, can you give an example (and your
choice of compiler) that "does not catch a none-thrown exception"?

Regards,
(e-mail address removed)
http://www.zhmicro.com
http://distributed-software.blogspot.com
http://groups-beta.google.com/group/computerlangZ?lnk=la&hl=en

In response to several comments after this posting:

Let us be fair. Do not reply to a paragraph, somewhat out ot context. I
am asking a couple of specific questions. If someone is familiar with
the standard, please point out where should we look in the standard.
Please, kindly show an example, and your choice of compiler, as I have
requested. Some of the comments simply say "Only MS VC++ does that".
Well, can you create an example using another compiler that does not?
Playing with words can go on forever, such as "An exception that is not
thrown is not an exception".
Please show an example that does not do what I am saying is happening.
Do not simply say that it is not happening. Show us how it is not
happening.

Please read the whole comment and kindly provide an answer to the
questions asked, not to individual phrases.

Thank you very much for all your input, so far.

Regards.
 
?

=?windows-1252?Q?Erik_Wikstr=F6m?=

Simon G Best wrote:

Erik says "It means that if you have code with a catch-block that
gets executed even though no exception has been thrown it is not
standard compliant behavior, I would even go as far as saying that it
is in direct violation of the standard".

A very specific and clear statement. But again, Erik immediately brings
up undefined behavior.

Sorry if that was unclear, what I meant to say was that while I can't
cite any specific part of the standard I'm quite sure that it specifies
that all exceptions have to be throw. As no such things happens in your
example I claim that there is no exception.
Is "undefined behavior", in this context, mentioned in the
standard? It will be nice someone familiar with standard to kindly
tells us where this is stated.
[snip]

The best way to resolve this is an answer like this. Standard item
number such and such states that .... Or, standard does not address
this issue for now.

I don't own a copy of the standard but I've got a copy of a draft for
the next standard, which I hope will suffice.

1.3.13 undefined behavior [defns.undefined]

behavior, such as might arise upon use of an erroneous program construct
or erroneous data, for which this International Standard mposes no
requirements. Undefined behavior may also be expected when this
International Standard omits the description of any explicit definition
of behavior. [ Note: permissible 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). Many erroneous program constructs do not
engender undefined behavior; they are required to be diagnosed. —end note ]

The following might also be of interest:

5.6 Multiplicative operators [expr.mul]

4th paragraph

The binary / operator yields the quotient, and the binary % operator
yields the remainder from the division of the first expression by the
second. If the second operand of / or % is zero the behavior is
undefined; otherwise (a/b)*b + a%b is equal to a. If both operands are
nonnegative then the remainder is nonnegative; if not, the sign of the
remainder is implementation-defined).

Hope that helps.
 
I

Ian Collins

Zorro said:
In response to several comments after this posting:

Let us be fair. Do not reply to a paragraph, somewhat out ot context. I
am asking a couple of specific questions. If someone is familiar with
the standard, please point out where should we look in the standard.

This is out of the scope of the standard!
Please, kindly show an example, and your choice of compiler, as I have
requested. Some of the comments simply say "Only MS VC++ does that".
Well, can you create an example using another compiler that does not?
Playing with words can go on forever, such as "An exception that is not
thrown is not an exception".
Please show an example that does not do what I am saying is happening.
Do not simply say that it is not happening. Show us how it is not
happening.
This is becoming tedious.

Your own example:

#include <iostream>

struct simple
{
int s;
simple() { s = 5;}
~simple(void) {std::cout << "Destructor ..." << std::endl;}
};

int main(){
int i = 1, j = 0;
try {
simple spl;
int k = i/j;
}
catch(...) {
std::cout << "Caught it" << std::endl;
}
std::cout << "Finishing" << std::endl;
return 0;
}

compiled with gcc on Solaris or Linux aborts.

../a.out
Arithmetic Exception (core dumped)
 
S

Simon G Best

Just to clarify...

Ian said:
./a.out
Arithmetic Exception (core dumped)

That "Arithmetic Exception", I bet, is *not* a C++ exception, but some
other kind of exception beyond C++. (Just thought I'd better clarify
that, just in case Zorro mistakes it for a C++ exception.)
 
?

=?windows-1252?Q?Erik_Wikstr=F6m?=

Sorry if that was unclear, what I meant to say was that while I can't
cite any specific part of the standard I'm quite sure that it specifies
that all exceptions have to be throw. As no such things happens in your
example I claim that there is no exception.

Sorry, no, that is not what I meant. My only excuse is that it's quite
late. What I really meant was that I'm quite sure that the standard
specifies that the code in a catch-block may only be executed if an
exception is thrown in the preceding try-block. So executing the catch-
block when no exception has been thrown is in violation of the standard.
 
?

=?windows-1252?Q?Erik_Wikstr=F6m?=

In response to several comments after this posting:

Let us be fair. Do not reply to a paragraph, somewhat out ot context. I
am asking a couple of specific questions. If someone is familiar with
the standard, please point out where should we look in the standard.
Please, kindly show an example, and your choice of compiler, as I have
requested. Some of the comments simply say "Only MS VC++ does that".
Well, can you create an example using another compiler that does not?
Playing with words can go on forever, such as "An exception that is not
thrown is not an exception".

It's not, chapter 15, first paragraph states:

Exception handling provides a way of transferring control and
information from a point in the execution of a program to an exception
handler associated with a point previously passed by the execution. A
handler will be invoked only by a throw-expression invoked in code
executed in the handler’s try block or in functions called from the
handler’s try block.

The handler here is the catch-block.
 
Z

Zorro

Erik said:
Simon G Best wrote:

Erik says "It means that if you have code with a catch-block that
gets executed even though no exception has been thrown it is not
standard compliant behavior, I would even go as far as saying that it
is in direct violation of the standard".

A very specific and clear statement. But again, Erik immediately brings
up undefined behavior.

Sorry if that was unclear, what I meant to say was that while I can't
cite any specific part of the standard I'm quite sure that it specifies
that all exceptions have to be throw. As no such things happens in your
example I claim that there is no exception.
Is "undefined behavior", in this context, mentioned in the
standard? It will be nice someone familiar with standard to kindly
tells us where this is stated.
[snip]

The best way to resolve this is an answer like this. Standard item
number such and such states that .... Or, standard does not address
this issue for now.

I don't own a copy of the standard but I've got a copy of a draft for
the next standard, which I hope will suffice.

1.3.13 undefined behavior [defns.undefined]

behavior, such as might arise upon use of an erroneous program construct
or erroneous data, for which this International Standard mposes no
requirements. Undefined behavior may also be expected when this
International Standard omits the description of any explicit definition
of behavior. [ Note: permissible 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). Many erroneous program constructs do not
engender undefined behavior; they are required to be diagnosed. -end note ]

The following might also be of interest:

5.6 Multiplicative operators [expr.mul]

4th paragraph

The binary / operator yields the quotient, and the binary % operator
yields the remainder from the division of the first expression by the
second. If the second operand of / or % is zero the behavior is
undefined; otherwise (a/b)*b + a%b is equal to a. If both operands are
nonnegative then the remainder is nonnegative; if not, the sign of the
remainder is implementation-defined).

Hope that helps.

Yes Erik, it helps me completely. Thanks. I actually needed this info
for improving on the article. Good night.

Regards.
 
Z

Zorro

Ian said:
This is out of the scope of the standard!

This is becoming tedious.

Your own example:

#include <iostream>

struct simple
{
int s;
simple() { s = 5;}
~simple(void) {std::cout << "Destructor ..." << std::endl;}
};

int main(){
int i = 1, j = 0;
try {
simple spl;
int k = i/j;
}
catch(...) {
std::cout << "Caught it" << std::endl;
}
std::cout << "Finishing" << std::endl;
return 0;
}

compiled with gcc on Solaris or Linux aborts.

./a.out
Arithmetic Exception (core dumped)

Yes Ian. gcc gave me "Floating point Exception". The compilers from
Metrowerks, Borland and MS were on PC and it seemed sufficient to show
the problem, without trying a free compiler (and retyping the program).
That proved to be wrong.

Thanks.
Regards.
 
Z

Zorro

Simon said:
Just to clarify...



That "Arithmetic Exception", I bet, is *not* a C++ exception, but some
other kind of exception beyond C++. (Just thought I'd better clarify
that, just in case Zorro mistakes it for a C++ exception.)

No Simon, I do not mistake it. This exception is equivalent to a crash,
as one would expect to happen.

Regards.
 
G

Grizlyk

benben said:
C++ could have properly throw an exception when you try to divide an int
by zero. However, this will put up a significant performance penalty
that not everyone is comfortable with. Alternatively, you can simple
test the divident and throw your own exception:

if (j == 0)
throw divide_by_zero();

i /= j;

Can not, divide by zero can happen not only for zero, try divide 0xffff
to 0x02, test it in debug
write to file:"
r ax
ffff
r dx
2
a
div dl

r
t
q
"
write to command line:"
debug <file
"
But compiler easy can setup trap for the error and throw divide_by zero
exception.

It seems to me, that there is no std::divide_by zero exception, so it
is really interesting problem, thanks Zorro.

It looks like " We do not want to process the error, and will try to
find a cause of it, if we will not find any, we will not process the
error also. Abtreten! " :)

Speaking seriously, the ignoring the error as "undefined behaviour" may
be is not a best solution, because most CPUs can handle the error and
compilers must do good workaround (they do not do it itself), and if
CPU can not, the kind of C++ exception just will never appear.

I think, user can not effective manage the error, because can not jump
to hidden catch entry point directly, because trap can be executed in
other task(process) from which user can not throw, so user must do
unneccessary if-else after each divide operation, that is no good.
 
S

Simon G Best

Grizlyk said:
Can not, divide by zero can happen not only for zero, try divide 0xffff
to 0x02, test it in debug

Interesting. Is that because, on your architecture, 0xFFFF is -0? (I'm
just guessing.)
But compiler easy can setup trap for the error and throw divide_by zero
exception.

But we don't want the unnecessary overhead when there's no possibility
of divide-by-zero. C++ leaves it to the programmer to decide whether or
not checks are needed, rather than imposing such checks.
It looks like " We do not want to process the error, and will try to
find a cause of it, if we will not find any, we will not process the
error also. Abtreten! " :)

Sorry, I just didn't understand that. "try to find a cause of it"? "if
we will not find any, we will not process the error also"?
Speaking seriously, the ignoring the error as "undefined behaviour" may
be is not a best solution, because most CPUs can handle the error and
compilers must do good workaround (they do not do it itself), and if
CPU can not, the kind of C++ exception just will never appear.

I didn't understand the second half of that. But as for "may be is not
a best solution, because most CPUs can handle the error", the problem is
that (as I understand it) the operating system deals with such things.
Different operating systems deal with such things in different ways.
And, as I said above, such things are beyond the scope of the C++
specification.
I think, user can not effective manage the error, because can not jump
to hidden catch entry point directly, because trap can be executed in
other task(process) from which user can not throw, so user must do
unneccessary if-else after each divide operation, that is no good.

Such checking only needs to be done in those cases where undefined
behaviour would otherwise be possible, and would be unacceptable. Such
checks don't need to be done for those cases where such undefined
behaviour isn't able to occur anyway.

For example, let's suppose that a program is going to be reading in some
data from somewhere. Let's also suppose that it's possible for that
data to be 'incorrect' in some way (even though it's obviously not
supposed to be incorrect, it still might be). And let's also suppose
that we need that program to behave well even when 'incorrect' data is
given to it. And finally, let's suppose it's possible for that data to
be 'incorrect' in such a way that normal processing of that data could
involve division by zero.

In order to have that program behave well when given such 'incorrect'
data, we're going to have to check the data somehow, and take
appropriate action when that data's 'incorrect'. That's the sort of
thing we can use exceptions for. (And we may well have that data
checking some way before it even gets close to any of the relevant
divisions, so we might not even have to specifically check for division
by zero.)

In contrast, if part of a program can't ever end up trying to do
something like division by zero, then there's no need to check for such
things as division by zero. No need to add the extra overhead of
checking for such cases when such cases can't arise anyway. For example:-

int foo (int x) {
for (int i(1); i <= 10; ++i) // i can't ever be zero, so
x /= i; // no check is ever needed.
return x;
}

As usual, C++ does not impose safety on the programmer; instead, it
provides tools to help the programmer write safe code.

:)
 
Z

Zorro

Simon said:
As usual, C++ does not impose safety on the programmer; instead, it
provides tools to help the programmer write safe code.

:)

Thanks to all comments, and in particular yours (to my blogger) I
realized I had made a slieght error because multiple compilers gave me
the same result (on Windows). My apologies. However ...

I have redone the blogger, and the article to show the disadvantages of
C++ exception model, and a better way of doing things. Looking at your
comment (above) I do not see what you are really trying to say. What do
you mean by "C++ does not impose safety on the programmer". So, how
come you cannot call a private method? It is the purpose of a modern
language to help with the safety.

Then you say "C++ provides tools ....". Does C not do that already? So
why use C++?

Now, reread the article, without prejudice. I love C++ and I have known
it from the time before it was called C++. My argument is that,
someone's weak implementation techniques were forced into standard, and
your generation simply takes that as a religion.

Regards.
 
D

David W

Zorro said:
Thanks to all comments, and in particular yours (to my blogger) I
realized I had made a slieght error because multiple compilers gave me
the same result (on Windows). My apologies. However ...

I have redone the blogger, and the article to show the disadvantages of
C++ exception model, and a better way of doing things. Looking at your
comment (above) I do not see what you are really trying to say. What do
you mean by "C++ does not impose safety on the programmer". So, how
come you cannot call a private method?

Different kind of safety. Calling a private function wouldn't necessarily be
unsafe, at least not _because_ the function is private. OTOH, you can happily
dereference uninitialized pointers and other unsafe things.
It is the purpose of a modern
language to help with the safety.

Different languages have different goals. One of C++'s is to have minimal
overhead. If C++ doesn't suit your purpose, then choose another language.
Then you say "C++ provides tools ....". Does C not do that already? So
why use C++?

What do tools have to do with whether to use C or C++, given the vast array of
differences between the two languages?

DW
 
Z

Zorro

David said:
What do tools have to do with whether to use C or C++, given the vast array of
differences between the two languages?

At least I thought the term tool (in context) meant linguistic
constructs, not tools external to the language itself. Sorry about
that. The vast array of differences were intended to ease development,
and for the most part they do.
Different languages have different goals. One of C++'s is to have minimal
overhead. If C++ doesn't suit your purpose, then choose another language.

I believe, in this one case, we are simply talking about the usefulness
of the C++ exception model. Is it really due to the significant
efficiency that C++ provides, that there is no resumption, for
instance. Or perhaps it has something to do with a form of
implementation that has been accepted as standard?
Different kind of safety. Calling a private function wouldn't necessarily be
unsafe, at least not _because_ the function is private. OTOH, you can happily
dereference uninitialized pointers and other unsafe things.

No language can ever be completely safe. The intent is to move towards
a safer language, just as the introduction of "class" made a better C.
So now, all I am saying about C++ exception is that, it was not
well-thought. There is no need to change to a different language. The
standard can take a closer look and re-evaluate the benefits of the
current model. At least we can point out to other ideas by citing other
languages. One can close his ears to any argument by continually
bringing up "overhead". So be it.

Thanks for your comments.

Regards.
 

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,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top