Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

/Og and exception handling in VC++7

4 views
Skip to first unread message

Jaap Havinga

unread,
Mar 4, 2003, 4:05:21 AM3/4/03
to
Hello,
The /Og (global optimization) switch of the VC++7
compiler seems to result in an incorrect compilation of
exception handling. My question is if anyone knows this
problem and how to resolve it.
The foo function (see below) is throwing a CError
exception that should be catched in the Work function.
Without the /Og switch set, the CError object is catched
at the expected location. However, when the /Og switch is
set, the thrown object is not recognized as CError, and
can only be catched by the ellipsis catch(...) (or without
a ellipsis catch an 'unhandled exception' runtime error).
Other switches like /Ob1, /Oy, /Ot can be set without
problem.
This problem now occurs since the program exe image grew
from 1.6 to 2.5 MB

Thanks
Jaap Havinga

void foo()
{
// a throw in a if statement will sometimes cause
problems...
if (condition)
throw CError(arg1, arg2);
...
//a throw on last line, will cause problems: (the throw
is 'reachable')
throw CError (arg1, arg2);
}

void Work()
{
try
{
...
foo();
...
}
catch (CError &e)
{
//correct catch here when /Og switch not set
}
catch (...)
{
// incorrect catch here when /Og switch set
}
}


David Lowndes

unread,
Mar 4, 2003, 5:12:47 AM3/4/03
to
>The /Og (global optimization) switch of the VC++7
>compiler seems to result in an incorrect compilation of
>exception handling.

Do you have a short console application example that would allow
someone to reproduce the problem?

Dave
--
MVP VC++ FAQ: http://www.mvps.org/vcfaq

Jaap Havinga

unread,
Mar 4, 2003, 11:16:27 AM3/4/03
to
I don't have such an application (yet). I also get
unexplained warnings about unreachable code (C4702) at
(for example)lines 855, 857, 858 of <list> (std library):
These are lines of a _CATCH_ALL block of the _Buynode()
function. May be this triggers a suggestion?

Jaap Havinga

>.
>

David Lowndes

unread,
Mar 4, 2003, 12:11:52 PM3/4/03
to
>I don't have such an application (yet). I also get
>unexplained warnings about unreachable code (C4702) at
>(for example)lines 855, 857, 858 of <list> (std library):
>These are lines of a _CATCH_ALL block of the _Buynode()
>function. May be this triggers a suggestion?

I also get those unreachable warnings from the STL in the release
build of a project I'm currently working on - I don't know why.

I don't believe they are an indication of any particular problem,
though I can't swear that they're not!

Brandon Bray [MSFT]

unread,
Mar 4, 2003, 12:27:04 PM3/4/03
to
Jaap Havinga wrote:
> The /Og (global optimization) switch of the VC++7
> compiler seems to result in an incorrect compilation of
> exception handling. My question is if anyone knows this
> problem and how to resolve it.

Just to be sure, are you setting at least the /EHs switch in addition to
/Og? (You can also use /EHa instead of /EHs.)

If you don't set either of these switches, the optimizer basically ignores
exception handling.

--
Brandon Bray Visual C++ Compiler
This posting is provided AS IS with no warranties, and confers no rights.


Brandon Bray [MSFT]

unread,
Mar 4, 2003, 12:29:39 PM3/4/03
to
Jaap Havinga wrote:
> Other switches like /Ob1, /Oy, /Ot can be set without
> problem.

Of course, these switches don't mean anything if /Og isn't set. Actually,
setting these switches is really not useful at all. That's what /O1 and /O2
are good for.

/01 == /Ogb2ys /GF /Gy
/O2 == /Ogb2yit /GF /Gy

Jaap Havinga

unread,
Mar 4, 2003, 2:39:27 PM3/4/03
to
The problem was solved by setting the /EHa switch instead
of the default /EHsc switch I used before. The /EHs switch
did not solve the problem. Also, the stl warnings
disappeared. So thanks for that. I still would like to
know why the e.g. stl code is left out by the optimizer
when the /EHs(c) switch is set? Is this because there is
no explicit throw statement in the try block?
Thanks
Jaap Havinga

>.
>

Jeff Kohn

unread,
Mar 4, 2003, 6:56:07 PM3/4/03
to

"Jaap Havinga" <j.ha...@planet.nl> wrote in message
news:062c01c2e285$c46905a0$3301...@phx.gbl...

> The problem was solved by setting the /EHa switch instead
> of the default /EHsc switch I used before. The /EHs switch
> did not solve the problem. Also, the stl warnings
> disappeared. So thanks for that. I still would like to
> know why the e.g. stl code is left out by the optimizer
> when the /EHs(c) switch is set? Is this because there is
> no explicit throw statement in the try block?
> Thanks
> Jaap Havinga

This workaround concerns me though. Isn't there a huge penalty hit for
asynchronous exception handling, and doesn't that also mean you end up
catching win32 structured exceptions? Might be better to just not use /Og if
this is indeed an optimizer bug.

Jeff


Jaap Havinga

unread,
Mar 5, 2003, 6:17:56 AM3/5/03
to
It bothers me too, since I don't have an explanation...
I measured the effect on different settings on a job to be
performed by the application:
switch .exe size(kB) time (s)
/Og /Ot /EHsc 2016 212 // but with error *)
/Og /Ot /EHa 2140 220 // no error
/Ot /EHsc 2528 279 // no error
/Os /EHsc 2380 292 // no error
*) as long as no exception occurs I can still run the
program

As you can see, the penalty on /EHa is not so big. Leaving
out /Og is a bigger penalty. Also it appears that /Ot
and /Os switches do have effect, even if /Og is not set
(This is consistent with the documentation)

Jaap Havinga


>This workaround concerns me though. Isn't there a huge
penalty hit for
>asynchronous exception handling, and doesn't that also
mean you end up
>catching win32 structured exceptions? Might be better to
just not use /Og if
>this is indeed an optimizer bug.
>
>Jeff
>
>

>.
>

Craig Powers

unread,
Mar 5, 2003, 10:17:11 AM3/5/03
to
Jeff Kohn wrote:
>
> "Jaap Havinga" <j.ha...@planet.nl> wrote in message
> news:062c01c2e285$c46905a0$3301...@phx.gbl...
> > The problem was solved by setting the /EHa switch instead
> > of the default /EHsc switch I used before. The /EHs switch
> > did not solve the problem. Also, the stl warnings
> > disappeared. So thanks for that. I still would like to
> > know why the e.g. stl code is left out by the optimizer
> > when the /EHs(c) switch is set? Is this because there is
> > no explicit throw statement in the try block?
> > Thanks
> > Jaap Havinga
>
> This workaround concerns me though. Isn't there a huge penalty hit for
> asynchronous exception handling

I don't think there would be. The main effect of /EHa, as I understand
it, is to tell the compiler that it has to assume that an exception can
originate anywhere and not just from a throw statement. And, as I
understand it, that just means that it's precluded from optimizing away
exception handling machinery in places where it otherwise would do so.

> and doesn't that also mean you end up
> catching win32 structured exceptions?

IIRC (don't have it available to test), VC7 did not change the behavior
of VC6 with respect to catching structured exceptions. They'll always
get caught by catch(...) handlers, but without /EHa the behavior may
not be correct. And, they will only get caught be a catch(...)
handler unless _set_se_translator is used.

--
Craig Powers
MVP - Visual C++

Jeff Kohn

unread,
Mar 5, 2003, 7:08:07 PM3/5/03
to

"Jaap Havinga" <j.ha...@planet.nl> wrote in message
news:052401c2e308$df14c8c0$a401...@phx.gbl...

> It bothers me too, since I don't have an explanation...
> I measured the effect on different settings on a job to be
> performed by the application:
> switch .exe size(kB) time (s)
> /Og /Ot /EHsc 2016 212 // but with error *)
> /Og /Ot /EHa 2140 220 // no error
> /Ot /EHsc 2528 279 // no error
> /Os /EHsc 2380 292 // no error
> *) as long as no exception occurs I can still run the
> program
>
> As you can see, the penalty on /EHa is not so big. Leaving
> out /Og is a bigger penalty. Also it appears that /Ot
> and /Os switches do have effect, even if /Og is not set
> (This is consistent with the documentation)
>
Jaap,

I'd be interested to see how the /EHc switch affects things. Do you still
get the bug if you use /EHs instead of /EHsc? What about /EHac?

Thanks,

Jeff


Jeff Kohn

unread,
Mar 5, 2003, 7:12:40 PM3/5/03
to

"Craig Powers" <eni...@hal-pc.org> wrote in message
news:3E6614F7...@hal-pc.org...

> >
> > This workaround concerns me though. Isn't there a huge penalty hit for
> > asynchronous exception handling
>
> I don't think there would be. The main effect of /EHa, as I understand
> it, is to tell the compiler that it has to assume that an exception can
> originate anywhere and not just from a throw statement. And, as I
> understand it, that just means that it's precluded from optimizing away
> exception handling machinery in places where it otherwise would do so.

My understanding is that it's much more efficient to implement synchronous
EH. Jaap's test's only show a 3% difference, but I would think it might be
dependent on the number of try blocks in your code or how your code is
structured as to how much difference it makes.

> > and doesn't that also mean you end up
> > catching win32 structured exceptions?
>
> IIRC (don't have it available to test), VC7 did not change the behavior
> of VC6 with respect to catching structured exceptions. They'll always
> get caught by catch(...) handlers, but without /EHa the behavior may
> not be correct. And, they will only get caught be a catch(...)
> handler unless _set_se_translator is used.

Well, the documented behavior in the help says that only async EH catches
structured exceptions:

-Use /EHs to specify the synchronous exception handling model (C++ exception
handling without structured exception handling exceptions). If you use /EHs,
do not rely on the compiler to catch asynchronous exceptions.

-Use /EHa to specify the asynchronous exception handling model (C++
exception handling with structured exception handling exceptions).

Now I haven't done any testing to confirm this, but it was my understanding
that catch(...) was safe with synchronous EH.

Jeff


Carl Daniel [VC++ MVP]

unread,
Mar 5, 2003, 7:23:03 PM3/5/03
to
Jeff Kohn wrote:
> Well, the documented behavior in the help says that only async EH
> catches structured exceptions:
>
> -Use /EHs to specify the synchronous exception handling model (C++
> exception handling without structured exception handling exceptions).
> If you use /EHs, do not rely on the compiler to catch asynchronous
> exceptions.
>
> -Use /EHa to specify the asynchronous exception handling model (C++
> exception handling with structured exception handling exceptions).
>
> Now I haven't done any testing to confirm this, but it was my
> understanding that catch(...) was safe with synchronous EH.

It's not. When compiled with /EHs, catch(...) will still catch structured
exceptions, unless the compiler optimizes the catch away, in which case it
won't. Worse, under /EHs, C++ objects on the stack may or may not have
their destructors called before the catch is entered (within a particular
code construct, they'll either be called or not - but it's not immediately
clear how to predict which objects' destructors won't be called).

Under /EHs, if there's a section of code that you expect (might) raise a
structured exception, you need to use __try/__except in that block to
reliably catch the SE. That block must not contain C++ objects with
destructors (on the stack) because their destructors may not be run.

Bottom line: if you expect to structured exceptions to be raised and your
code contains any catch(...) blocks, you must compile with /EHa, or do all
the SE handling yourself to get reliable operation.

-cd


Craig Powers

unread,
Mar 6, 2003, 10:01:10 AM3/6/03
to
Jeff Kohn wrote:
>
> "Craig Powers" <eni...@hal-pc.org> wrote in message
> news:3E6614F7...@hal-pc.org...
>
> > >
> > > This workaround concerns me though. Isn't there a huge penalty hit for
> > > asynchronous exception handling
> >
> > I don't think there would be. The main effect of /EHa, as I understand
> > it, is to tell the compiler that it has to assume that an exception can
> > originate anywhere and not just from a throw statement. And, as I
> > understand it, that just means that it's precluded from optimizing away
> > exception handling machinery in places where it otherwise would do so.
>
> My understanding is that it's much more efficient to implement synchronous
> EH. Jaap's test's only show a 3% difference, but I would think it might be
> dependent on the number of try blocks in your code or how your code is
> structured as to how much difference it makes.

I'm not aware of any differences between /EHa and /EHs exception
handling that would make the latter more efficient, except in the sense
that the former precludes optimizations because it tells the compiler
that any statement (not just an explicit throw) might generate an
exception. AFAIK, the actual exception handling implementation is
exactly the same for both switches.

Brandon Bray [MSFT]

unread,
Mar 6, 2003, 12:52:27 PM3/6/03
to
Craig Powers wrote:
>
> I'm not aware of any differences between /EHa and /EHs exception
> handling that would make the latter more efficient, except in the sense
> that the former precludes optimizations because it tells the compiler
> that any statement (not just an explicit throw) might generate an
> exception. AFAIK, the actual exception handling implementation is
> exactly the same for both switches.

As you say, EHa precludes optimizations because (1) try/catch blocks cannot
be optimized away, and (2) instruction reordering needs to preserve the
asynchronous exception semantics of the program. With EHs, performance can
improve because (1) try/catch blocks can be optimized away if the body of
the try block provably has no throw statements, and (2) instruction
reordering needs only preserve the synchronous exception handling semantics
which gives the optimizer much more freedom.

This also explains why the 'c' in EHac isn't interesting and why it is for
EHsc. Under EHa, no try/catch or __try/__except block is ever optimized
away, so there is no analysis needed of the try or __try blocks to see if
any exception could occur. With EHs, since there is analysis done, the
optimizer is limited to the information it has on hand (which is only what
is available in the translation unit). EHsc gives the optimizer more
freedom -- it allows it to assume that an extern "C" function does not have
a throw statement (or does not call any other function that has a throw
statement). This widens the possibility that the try/catch block is not
needed. (It is also worth noting that Link Time Code Generation via /GL can
improve this optimization, as the optimizer can search the call graph for
the entire program looking for throw statements.)

If a translation unit has any __try/__except blocks, it should be compiled
with EHa. If there are no __try/__except blocks in a translation unit, EHs
is appropriate (unless you're using _set_se_translator). Provided a
translation unit was compiled with either EHs or EHa, the correct stack
unwinding semantics will take place for at least the C++ EH model.

The fact that catch(...) will capture an ansyncronous exception (as long as
the associated try block was not optimized away) is a bug. We intend to fix
this for EHs in a future release. After this is fixed, there are two
programming errors that a developer can make:
- C++ EH (aka synchronous EH) can handle SEH in /EHa. There is a
_set_se_translator function that makes this sound. Forgetting to
call this function and having catch(...) in the code is a problem.
- SEH can handle C++ EH. The danger is when the C++ exception is
thrown by value - when SEH handles the exception, the C++ exception
object will not have its destructor called but its memory will be
freed. The recommended practice is of course to always throw a
pointer to a C++ exception object (of course, this can be tricky).

Hope that helps!

Brandon Bray [MSFT]

unread,
Mar 6, 2003, 12:59:13 PM3/6/03
to
Jaap Havinga wrote:
> I still would like to know why the e.g. stl code is left
> out by the optimizer when the /EHs(c) switch is set? Is
> this because there is no explicit throw statement in the
> try block?

Without seeing code, I cannot say anything for sure. If there is no throw
statement as you say, I would expect the optimizer to remove the try/catch
block under EHs.

According to the code you put in the original post, I would not expect
problems with /EHs as you did have throw statements. If that is
representative of your code, I'm a little concerned. Can you reproduce your
problem in an example that we can use to investigate?

Thanks!

Jeff Kohn

unread,
Mar 6, 2003, 4:04:13 PM3/6/03
to

"Brandon Bray [MSFT]" <bran...@online.microsoft.com> wrote in message
news:eR4CokA5...@TK2MSFTNGP10.phx.gbl...


> The fact that catch(...) will capture an ansyncronous exception (as long
as
> the associated try block was not optimized away) is a bug. We intend to
fix
> this for EHs in a future release.

So would I be correct in assuming that "future release" is not VC 7.1? If
not that's a shame, this seems like a pretty serious bug.

Let me explain my situation. I don't want to catch/handle Win32 SE's; if my
program performs an Access Violation or some such, I'm perfectly happy with
the default handling (ie terminate the program). That said, I do use
catch(...) on occasion. For instance, the COM interface methods in an ATL
COM server will be wrapped in try/catch blocks that use catch(...) as a last
resort because I want to be absolutely sure that no C++ exceptions escape my
component. So what can I do to safely use catch(...) in these situations
without having to worried about Win32 SE's silently getting caught? What I
would really like to do is use /EHsc and just not worry about Win32 SE's,
but it sounds like that's not an option due to the bug you mention. So is my
only real option to use /EHa and install an _se_translator_function to
handle Win32 SE's. Then again I'm not even sure if that's safe to do in a
COM component whose threading model is "neutral" or "both"

BTW, I have also noticed that /EHsc in combination with /OG produces C4702
warnings for system headers, such as <xtree> and <vector>. I don't know if
this is just something that can safely be ignored or an indicator of the
possible bug Jaap is reporting, but it does concern me somewhat because I
always try to compile cleanly at level 4 and I'd have to have to disable
this warning since it does have its uses.

Jeff


Jaap Havinga

unread,
Mar 8, 2003, 2:24:08 PM3/8/03
to
After playing around with different settings (each time
with a full rebuild), I noticed the size of the executable
differed from one I tried before with the same settings.
This triggered me to throw away the whole 'release'
directory and start all over again. Now the program works
fine in all /EH flavors... Apparently some files with e.g.
linker information are not cleared when a rebuild is
issued?? (I remember these kind of problems occured with
early versions of VC). So in the end it seems not to be a
compiler issue, at most some file maintenance problem.

Jaap Havinga

>.
>

0 new messages