DZone
Performance Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Performance Zone > Undefined Behavior Due to the Absence of a Return

Undefined Behavior Due to the Absence of a Return

A true story of when code breaks bad.

Andrey Karpov user avatar by
Andrey Karpov
·
Feb. 12, 22 · Performance Zone · Tutorial
Like (3)
Save
Tweet
3.59K Views

Join the DZone community and get the full member experience.

Join For Free

This article contains a very interesting example. The absence of the return statement in a value-returning function leads to undefined behavior. It's a perfect example of how wrong code can crash one day, even though it could work for many years. 

We inspect an error pattern that the SEI CERT C++ coding standard describes as MSC52-CPP. Value-returning functions must return a value from all exit paths.

The C++ Standard, [stmt.return], paragraph 2 [ISO/IEC 14882-2014], states the following: 

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.

A simple example of code with an error: 

C++
 
int foo(T a, T b)
{
  if (a < b)
    return -1;
  else if (a > b)
    return 1;
}

The developer forgot to write return 0 if two values are equal. Not all execution branches return the value, and this leads to undefined behavior.

I think everything's clear here. It's a well-known error pattern. We often find this error with the V591 diagnostic in various open-source projects. You can see the examples here.

Well, if everything's clear and errors are found, why did I write this article? Here comes the fun part!

The problem is that developers often interpret undefined behavior a bit different than it really is. Undefined behavior with the forgotten return statement is often interpreted like this: the function returns a random value. Moreover, the developer's previous experience may confirm this.

Wrong. Undefined behavior means we cannot predict what's going to happen. Code that worked correctly may suddenly start working in a different way.

To demonstrate this, I'll show you a slightly edited discussion (RU) from the RSDN website.

A Funny Crash

Linux, libc-2.33, GCC 11.1.0, optimization -O2, the following code fragment crashes with SIGSEGV:

C++
 
#include <string>
#include <iostream>

bool foobar(const std::string &s)
{
    std::string sx = s;
    std::cout << sx << std::endl;
}

int main(int argc, char **argv)
{
    foobar(argv[0]);
    return 0;
}
C++
 
    /home/user/test$ g++ -O2 -std=c++11 ./test.cpp -o ./test && ./test
    ./test.cpp: In function 'bool foobar(const string&)':
    ./test.cpp:8:1: warning: no return statement in function returning non-void [-Wreturn-type]
    8 | }
    | ^
    ./test
    Segmentation fault (core dumped)

If we change bool foobar to void foobar or add return false, the code doesn't crash.

It also doesn't crash if we use GCC 7.5.0.

By the way, std::string, as it turned out, doesn't affect the situation. The analog of this code on C, compiled by g++, also crashes.

C++
 
#include <stdio.h>

bool foobar(const char *s)
{
    printf("foobar(%s)\n", s);
}

int main(int argc, char **argv)
{
    foobar(argv[0]);
    return 0;
}
C++
 
    /home/user/test$ g++ -O2 ./test.c -o ./test && ./test
    ./test.c: In function 'int foobar(const char*)':
    ./test.c:6:1: warning: no return statement in function returning non-void [-Wreturn-type]
    6 | }
    | ^
    foobar(./test)
    Segmentation fault (core dumped)

If we write this: gcc -O2 ./test.c -o ./test && ./test, everything's fine.

The compiler just won't generate instructions for returning from the function (ret)!

C
 
0000000000001150 <_Z6foobarPKc>:
 1150:  48 89 fe              mov   rsi,rdi
 1153:  48 83 ec 08           sub   rsp,0x8
 1157:  48 8d 3d a6 0e 00 00  lea   rdi,[rip+0xea6]  # 2004 <_IO_stdin_used+0x4>
 115e:  31 c0                 xor   eax,eax
 1160:  e8 cb fe ff ff        call  1030 <printf@plt>
 1165:  66 2e 0f 1f 84 00 00 00 00 00   cs nop WORD PTR [rax+rax*1+0x0]
 116f:  90                    nop

0000000000001170 <__libc_csu_init>:
 1170:  f3 0f 1e fa           endbr64 
 1174:  41 57                 push  r15

Thanks to the ononim user from the RSDN website for a very entertaining example.

A very unusual example of undefined behavior.

What conclusions can be drawn from this? In my opinion, there are two of them:

  • Don't try to guess where undefined behavior will lead you to. If you think that you, for example, know what the signed integer overflow will lead to, then this is self-deception. There may be a very unexpected result.
  • Code that causes undefined behavior may stop working at any time. Use compiler warnings and static code analysis tools (for example, PVS-Studio) to find and fix such dangerous code fragments.

Additional links:

  • Undefined behavior.
  • Undefined Behavior Is Really Undefined.
  • Null pointer dereferencing causes undefined behavior.
  • Undefined behavior is closer than you think.
  • Undefined behavior, carried through the years.

Published at DZone with permission of Andrey Karpov. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Building HIPAA Compliant APIs
  • AWS IAM Security Best Practices
  • Build a Data Pipeline on AWS With Kafka, Kafka Connect, and DynamoDB
  • Streaming ETL with Apache Kafka in the Healthcare Industry

Comments

Performance Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo