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

How is it that this code seems to work?

155 views
Skip to first unread message

bobl...@gmail.com

unread,
Dec 10, 2013, 4:34:25 PM12/10/13
to
A student submitted this code:

bool isPalindrome(string word)
{
string::iterator forwardIt = word.begin();
string::reverse_iterator reverseIt = word.rbegin();

while (forwardIt != word.end())
{
if (*forwardIt != *reverseIt)
{
return false;
}
else
{
++forwardIt;
++reverseIt;
}
}
}

The function seems to work, even though I don't believe it should.

Specifically, I believe the code should be instead:

bool isPalindrome(string word)
{
string::iterator forwardIt = word.begin();
string::reverse_iterator reverseIt = word.rbegin();

while (forwardIt != word.end())
{
if (*forwardIt != *reverseIt)
{
return false;
}
else
{
++forwardIt;
++reverseIt;
}
}

return true; // THE CHANGE I MADE
}

The if statement that invokes this function appears to work correctly:

if (isPalindrome(substring))

Does anyone have a clue as to how this works despite the missing return statement?

Thanks in advance.

Mr Flibble

unread,
Dec 10, 2013, 4:53:48 PM12/10/13
to
Exiting a function without a return statement is undefined behaviour
(UB). Undefined behaviour can silently "work" (which might be the case
here) but is nevertheless a bug. It is impossible in the general case
for a compiler to emit a diagnostic for missing return statements which
is why it is undefined behaviour instead.

/Leigh

Juha Nieminen

unread,
Dec 12, 2013, 5:11:18 AM12/12/13
to
Mr Flibble <fli...@i42.co.uk> wrote:
> It is impossible in the general case
> for a compiler to emit a diagnostic for missing return statements which
> is why it is undefined behaviour instead.

Do you understand that compilers *have to* generate the equivalent of
a "return" statement in asm for each subroutine? They can't just leave
it out because else the execution of the program would just continue
after the last opcode of the subroutine to whatever comes after it,
making the program malfunction? Therefore they can see if there is
an equivalent "return" statement in the source code.

What you probably meant was that it's in general impossible to prove
that the execution of a subroutine will ever reach its last 'return'
statement (if it contains previous such statements inside conditionals),
and for legacy reasons (coming from the earliest history of C) it has
been decided to not force each function to explicitly end with a
'return' statement if the execution never reaches it. This allows
things like this to be legal:

bool foo(int i)
{
if(i < 0) return true;
else return false;
}

(Note how there's no ending "return" statement to the function.
Technically speaking this is "wrong", but in practice it causes no
malfunction because the ending of the function is never reached.
In this particular case it's trivial even for a compiler to see,
and most compilers will probably optimize that "implicit return"
at the end of the function away. However, it's easy to write
conditionals that are much harder, even impossible, to prove that
they will always execute a mid-function return.)

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Victor Bazarov

unread,
Dec 12, 2013, 7:44:41 AM12/12/13
to
On 12/12/2013 5:11 AM, Juha Nieminen wrote:
> Mr Flibble <fli...@i42.co.uk> wrote:
>> It is impossible in the general case
>> for a compiler to emit a diagnostic for missing return statements which
>> is why it is undefined behaviour instead.
>
> Do you understand that compilers *have to* generate the equivalent of
> a "return" statement in asm for each subroutine?

That's not true for an inlined function, is it?

> They can't just leave
> it out because else the execution of the program would just continue
> after the last opcode of the subroutine to whatever comes after it,

Which should be just fine for inlined code, shouldn't it?

> making the program malfunction? Therefore they can see if there is
> an equivalent "return" statement in the source code.
> [..]

Just trying to understand...

V
--
I do not respond to top-posted replies, please don't ask

Alf P. Steinbach

unread,
Dec 12, 2013, 8:28:07 AM12/12/13
to
On 12.12.2013 11:11, Juha Nieminen wrote:
> Mr Flibble <fli...@i42.co.uk> a.k.a. Leigh Johnson wrote:
>> It is impossible in the general case
>> for a compiler to emit a diagnostic for missing return statements which
>> is why it is undefined behaviour instead.
>
[snip]
>
> What you probably meant was that it's in general impossible to prove
> that the execution of a subroutine will ever reach its last 'return'
> statement (if it contains previous such statements inside conditionals)

Rather, I think Leigh referred to the case where a non-void function
exits by execution reaching the end of the function body, so that the
return value is dynamically unspecified, which is Undefined Behavior.

The general case includes such code as

auto f()
-> Foo
{ if( fermatsLastTheoremIsTrue() ) { return Foo( 42 ); } }

which a compiler might find difficult to reason about.

The main problem -- for me, who is all I can speak for -- is that in
some cases the compiler *can* prove that execution will never reach a
return statement at the end. Then first without that statement it might
complain that a non-void function, like e.g. throw_exception (I just
call it "fail"), doesn't have a return statement, and then after such a
statement is added the compiler, too smart for the programmer's own
good, complains that the return statement will never be reached...

That's what C++11 "noreturn" attribute is about.

However, as I understand it and vaguely remember it, Visual C++ will
never get C++11 attribute support, but it does have a non-standard
extension (called "declspec") for declaring the same.

I just wrap this, and some other such features, in macros, like
CPPX_NORETURN, defined by a header file that's included via different
include paths for different compilers.


Cheers,

- Alf


Mr Flibble

unread,
Dec 12, 2013, 4:12:12 PM12/12/13
to
On 12/12/2013 10:11, Juha Nieminen wrote:
> Mr Flibble <fli...@i42.co.uk> wrote:
>> It is impossible in the general case
>> for a compiler to emit a diagnostic for missing return statements which
>> is why it is undefined behaviour instead.
>
> Do you understand that compilers *have to* generate the equivalent of
> a "return" statement in asm for each subroutine? They can't just leave
> it out because else the execution of the program would just continue
> after the last opcode of the subroutine to whatever comes after it,
> making the program malfunction? Therefore they can see if there is
> an equivalent "return" statement in the source code.
>
> What you probably meant was that it's in general impossible to prove
> that the execution of a subroutine will ever reach its last 'return'
> statement (if it contains previous such statements inside conditionals),
> and for legacy reasons (coming from the earliest history of C) it has
> been decided to not force each function to explicitly end with a
> 'return' statement if the execution never reaches it. This allows
> things like this to be legal:

What I meant was that it is undefined behaviour to flow off the end of a
value returning function without using a return statement.

The compiler cannot raise a diagnostic about missing return statements
in the general case as it doesn't always know how a function may be
exited, e.g.:

bool foo()
{
if (bar())
return baz();
wibble();
}

if wibble() always throws an exception then that code is perfectly legal
however the compiler may not be able to determine that wibble() always
throws an exception hence why there is no diagnostic for missing return
statements and flowing off the end is undefined behaviour.

/Flibble

Juha Nieminen

unread,
Dec 13, 2013, 4:04:04 AM12/13/13
to
Victor Bazarov <v.ba...@comcast.invalid> wrote:
>> Do you understand that compilers *have to* generate the equivalent of
>> a "return" statement in asm for each subroutine?
>
> That's not true for an inlined function, is it?

There exists no function you can write that can only be inlined,
from which the compiler does not have to make an actual subroutine
if needed.

Victor Bazarov

unread,
Dec 13, 2013, 7:39:26 AM12/13/13
to
On 12/13/2013 4:04 AM, Juha Nieminen wrote:
> Victor Bazarov <v.ba...@comcast.invalid> wrote:
>>> Do you understand that compilers *have to* generate the equivalent of
>>> a "return" statement in asm for each subroutine?
>>
>> That's not true for an inlined function, is it?
>
> There exists no function you can write that can only be inlined,
> from which the compiler does not have to make an actual subroutine
> if needed.

Yes, I understand the "if needed" portion. I am just trying to bring it
in concert with the statement that <<compilers *have to* generate the
equivalent of a "return" statement>>. They probably don't *have to* if
the body of the function is inlined, do they? Since the behavior of the
compiler is not mandated in any way (or is it?) the conclusion that they
"have to" is a speculation, yes? I am not trying to argue the point,
just trying to understand.

Stuart

unread,
Dec 13, 2013, 9:57:57 AM12/13/13
to
On 2013/12/12, Mr Flibble wrote:
> What I meant was that it is undefined behaviour to flow off the end of a
> value returning function without using a return statement.
>
> The compiler cannot raise a diagnostic about missing return statements
> in the general case as it doesn't always know how a function may be
> exited, e.g.:
>
> bool foo()
> {
> if (bar())
> return baz();
> wibble();
> }
>
> if wibble() always throws an exception then that code is perfectly legal
> however the compiler may not be able to determine that wibble() always
> throws an exception hence why there is no diagnostic for missing return
> statements and flowing off the end is undefined behaviour.
>
> /Flibble

I never thought that this day would come, but in this case I prefer
Java's behaviour. I'd rather be forced to add superfluous return
statements than hunting bugs that stem from forgotten return statements.

However, gcc actually does complain:
1: bool foo () {
2: }

yields

2: "Control reaches end of non-void function"

Regards,
Stuart

Mr Flibble

unread,
Dec 13, 2013, 11:20:18 AM12/13/13
to
I doubt gcc complains about my example if it doesn't have sight of the
definition of wibble(). Compilers are not required to complain in any
case so it is undefined behaviour instead.

/Flibble

Scott Lurndal

unread,
Dec 13, 2013, 12:50:05 PM12/13/13
to
$ cat /tmp/a.cpp
#include <stdlib.h>
#include <string.h>

bool bar(void) { return strcasecmp(getenv("FRED"), "joe") == 0; }
bool baz(void) { return strcasecmp(getenv("HOME"), "/home/fred")==0; }

void wibble(void) { throw "wibble threw"; }

bool foo(void) { if (bar()) return baz(); wibble(); }

$ g++ -Wall -c -o /tmp/a /tmp/a.cpp
/tmp/a.cpp: In function 'bool foo()':
/tmp/a.cpp:9:54: warning: control reaches end of non-void function [-Wreturn-type]

$ cat /tmp/a.cpp
#include <stdlib.h>
#include <string.h>

bool bar(void) { return strcasecmp(getenv("FRED"), "joe") == 0; }
bool baz(void) { return strcasecmp(getenv("HOME"), "/home/fred")==0; }

extern void wibble(void);

bool foo(void) { if (bar()) return baz(); wibble(); }
$ g++ -Wall -c -o /tmp/a /tmp/a.cpp
/tmp/a.cpp: In function 'bool foo()':
/tmp/a.cpp:9:54: warning: control reaches end of non-void function [-Wreturn-type]

Mr Flibble

unread,
Dec 13, 2013, 1:07:51 PM12/13/13
to

Mr Flibble

unread,
Dec 13, 2013, 1:09:32 PM12/13/13
to
On 13/12/2013 17:50, Scott Lurndal wrote:
Well that warning is clearly a bag of shite, what were they thinking?
The salient point here though is that it is only a warning and not an
error which has to be the case.

/Leigh

Scott Lurndal

unread,
Dec 13, 2013, 4:33:04 PM12/13/13
to
$ g++ -Wall -Werror -c -o /tmp/a /tmp/a.cpp
/tmp/a.cpp: In function 'bool foo()':
/tmp/a.cpp:9:54: error: control reaches end of non-void function [-Werror=return-type]
cc1plus: all warnings being treated as errors


Mr Flibble

unread,
Dec 13, 2013, 4:37:02 PM12/13/13
to
I thought you might do that as a joke. I do hope you are joking, the
alternative doesn't bear thinking about.

/Flibble

Paavo Helde

unread,
Dec 13, 2013, 4:49:46 PM12/13/13
to
Mr Flibble <flibbleRE...@i42.co.uk> wrote in
news:TZOdnbwzKujA0DbP...@giganews.com:
This cannot be a compile-time error. The standard clearly states:

"Flowing off the end of a function is equivalent to a return with no
value; this results in undefined behavior in a value-returning function."

So this is undefined behavior at run-time (not ill-formed code); there is
no way it could be undefined behavior at run-time if compilers refused to
compile the code in the first place. Ergo: a conforming compiler may not
refuse to compile the code, and the compiled code must actually run
normally as far as the "flowing off the end of a function" UB does not
actually happen.

Cheers
Paavo







Mr Flibble

unread,
Dec 13, 2013, 5:25:02 PM12/13/13
to
I said that already, did you misunderstand me? I said it has to be the
case that it cannot be an error.

/Flibble

Paavo Helde

unread,
Dec 13, 2013, 6:11:26 PM12/13/13
to
Mr Flibble <flibbleRE...@i42.co.uk> wrote in
news:wq-dnY52RO-iFDbP...@giganews.com:

> On 13/12/2013 21:49, Paavo Helde wrote:
>> Mr Flibble <flibbleRE...@i42.co.uk> wrote in
>> news:TZOdnbwzKujA0DbP...@giganews.com:

>>> Well that warning is clearly a bag of shite, what were they
>>> thinking? The salient point here though is that it is only a warning
>>> and not an error which has to be the case.
>>
>> This cannot be a compile-time error. The standard clearly states:
>
> I said that already, did you misunderstand me? I said it has to be the
> case that it cannot be an error.

On second reading, it might be indeed that your claim can be interpreted
also in the way where "which" applies to "salient point", not to "error".
However, in such interpretation it is unclear why do you think the warning
is "a big of "shite"".

Cheers
Paavo


Mr Flibble

unread,
Dec 13, 2013, 6:35:08 PM12/13/13
to
On 13/12/2013 23:11, Paavo Helde wrote:
> Mr Flibble <flibbleRE...@i42.co.uk> wrote in
> news:wq-dnY52RO-iFDbP...@giganews.com:
>
>> On 13/12/2013 21:49, Paavo Helde wrote:
>>> Mr Flibble <flibbleRE...@i42.co.uk> wrote in
>>> news:TZOdnbwzKujA0DbP...@giganews.com:
>
>>>> Well that warning is clearly a bag of shite, what were they
>>>> thinking? The salient point here though is that it is only a warning
>>>> and not an error which has to be the case.
>>>
>>> This cannot be a compile-time error. The standard clearly states:
>>
>> I said that already, did you misunderstand me? I said it has to be the
>> case that it cannot be an error.
>
> On second reading, it might be indeed that your claim can be interpreted
> also in the way where "which" applies to "salient point", not to "error".
> However, in such interpretation it is unclear why do you think the warning
> is "a big of "shite"".

It is a bag of shite as the warning will likely be a false positive
unless the compiler can determine that control will indeed always flow
off the end.

"Bag of shite" is a catchphrase of Paul Calf:
http://www.youtube.com/watch?v=F-kfeyEzAT8

/Leigh

woodb...@gmail.com

unread,
Dec 13, 2013, 10:54:36 PM12/13/13
to
On Friday, December 13, 2013 5:35:08 PM UTC-6, Mr Flibble wrote:

Please don't swear here.

Mr Flibble

unread,
Dec 14, 2013, 11:21:43 AM12/14/13
to
On 14/12/2013 03:54, woodb...@gmail.com wrote:
> On Friday, December 13, 2013 5:35:08 PM UTC-6, Mr Flibble wrote:
>
> Please don't swear here.

"Well that's a shit load of fucking bastard cunts" -- Paul Calf

http://www.youtube.com/watch?v=F-kfeyEzAT8



Juha Nieminen

unread,
Dec 16, 2013, 9:31:48 AM12/16/13
to
Victor Bazarov <v.ba...@comcast.invalid> wrote:
> Yes, I understand the "if needed" portion. I am just trying to bring it
> in concert with the statement that <<compilers *have to* generate the
> equivalent of a "return" statement>>.

Obviously I meant "have to be able to generate".
0 new messages