public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
From: tika <tikabass@yahoo.fr>
To: libstdc++@gcc.gnu.org
Subject: Questions about std::string::operator=(char)
Date: Sat, 27 Mar 2021 03:25:56 +0100	[thread overview]
Message-ID: <7eeb24bf-58cc-5316-807e-64434ecf4b83@yahoo.fr> (raw)
In-Reply-To: <7eeb24bf-58cc-5316-807e-64434ecf4b83.ref@yahoo.fr>


Synopsys:?? assigning a char to a std::string makes a string 1 char long, 
but what happens if that char is zero??? And showing how easily can this 
UB pass undetected through unit testing...

The story:?? I created a stupid bug, that my unit testing did not 
catch....?? And ended up spending more more time debugging the test than 
fixing my bug.

The bug itself is kind of boring...?? Using the return value of int 
snd_get_name(int, char*) C function from the alsa library, and putting 
an int into a string. That's what I think could be a rather common mistake.

Here's my piece of code, the various tests that could be applied (and 
most fail to detect the bug in my code).?? It turns out that assigning a 
null character to a std::string breaks a lot iof invariants we usually 
depend on.?? All of gcc 10.2.1 (with libstdc++-10.2.1-9), clang 11.0.1 
and icc 2021.1.2 fail to warn of the mistake with -Wall, for gcc at 
least, that is both both on my system (fedora) and on godbolt.?? MSVC 
does a lot better, with both warnings and different outcome, with str = 
0 (correctly ?) resulting in an empty string of length zero.

I know it is UB, but I'm pretty sure the fact that this can go 
undetected so easily by the most common unit testing methods makes it an 
interseting one.?? Is it a feature? Is it something that is part of the 
standard's private UB collection? What does the standard say about 
expected invariants such as s == s.c_str() ? And about the contract of 
std::basic_string::operator(Char) ?

So, here's some code that show the issue and how stcky it is... You can 
also find it here: https://godbolt.org/z/cTWGWohv3 
<https://godbolt.org/z/cTWGWohv3>

#include<string>
#include<cstring>
#include<iostream>

// -------------------------------------------------------------------------
// simulating what is the C driver FYI, it's the alsa sound driver,
// but that's not much relevant

char*some_text =nullptr;

voidinit_text()
{
 ?????? some_text =strdup("some text");
}

intget_card_name(int,char** x)
{
*x =some_text;
return0;
}

// end 'driver' code
// -------------------------------------------------------------------------

intmain()
{
 ?????? init_text();

 ?????? inti =0;
char*name;
 ?????? std::string s;

// my original bug... &"??! happens.
 ?????? s =get_card_name(i,&name);

// Should have read:
// if (!get_card_name(i, &name))
// s = name;

// simulating EXPECT_FALSE(s.empty());
 ?????? std::cout <<"s.empty() : "<<s.empty()<<'\n';

// simulating EXPECT_NE(s.length(), 0);
 ?????? std::cout <<"s.length() : "<<s.length()<<'\n';

// simulating EXPECT_NE(s, "");
 ?????? std::cout <<"(s == \"\") : "<<(s =="")<<'\n';

// simulating EXPECT_EQ(s, s.c_str());
 ?????? std::cout <<"(s == s.c_str()): "<<(s ==s.c_str())<<" <- bug 
detected!\n";

// checking for transmisssion by copy
 ?????? std::string t =s;
 ?????? std::cout <<"t == s : "<<(t ==s)<<" <- transmission of odd 
behaviour by copy\n";

// a trace to check contents:
 ?????? std::cout <<"s : \""<<s <<"\"\n";


if(!s.empty())
 ?????? std::cout <<"int(s.front()) : "<<(int)s.front()<<'\n';

 ?????? free(some_text);
returns.length();
}



       reply	other threads:[~2021-03-27  2:26 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <7eeb24bf-58cc-5316-807e-64434ecf4b83.ref@yahoo.fr>
2021-03-27  2:25 ` tika [this message]
2021-03-27 10:35   ` Jonathan Wakely
2021-03-27 10:37     ` Jonathan Wakely
2021-03-27 14:58     ` tika
2021-03-27 15:32       ` Jonathan Wakely

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7eeb24bf-58cc-5316-807e-64434ecf4b83@yahoo.fr \
    --to=tikabass@yahoo.fr \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).