Reputation: 6561
Recently a developer at my company committed some code that looked something like this:
char buf[50];
string str;
str = sprintf(buf, "%s", "test");
//proceeds to use str
The thing is, it slipped through CI because the compiler raised no warnings despite -Wall
and -Werror
being set.
Shouldn't this be an obvious type mismatch? You can't assign an integer to an std::string
type without std::to_string
...
I took a look at the list of string assignments but I can't tell which one is being triggered in this case? Is it using one of these?
c-string (2) string& operator= (const char* s);
character (3) string& operator= (char c);
I'm guessing the latter, but that still seems like a compiler fail since sprintf clearly returns int
not char
.
Is there a warning we could have enabled that could have saved us in this case not covered by -Wall
?
Edit:
A related thread I found: https://stackoverflow.com/a/39285668/2516916
Upvotes: 3
Views: 593
Reputation: 348
I made some tests and here is all my results. Compiling this program:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str;
str = 1000;
cout << str << "\n";
return 0;
}
With the command:
g++ -o test test.cpp
you get the following warning:
teste.cpp: In function ‘int main()’:
teste.cpp:10:11: warning: overflow in implicit constant conversion [-Woverflow]
str = 1000;
if instead of 1000 you use a number from 0 to 255 then you do not get a warning. Apparently if the number is within the range of a char the compiler is trying to transform that number into a char and the string type accepts that.
But now if you do this:
#include <iostream>
#include <string>
using namespace std;
int number(){
return 100;
}
int main ()
{
int a = 100;
string str;
str = a;
cout << str << "\n";
str = number();
cout << str << "\n";
return 0;
}
You do not get any warning and as output you get:
d
d
If instead of 100 you use 10000 in my case i got only two blank lines as result.
So after that analysis i believe that what is happening is that even if what the variable str
is trying to receive is a int
The compiler is trying to make your life easier by converting everything to you, but unfortunatly in this case it made the exact opposite.
After some research here cpp-flags i finally found a combination that would have saved you:
g++ -o test test.cpp -Wconversion -Werror
with -Wconversion
you turn those implicit conversions made by the compiler into warnings and with -Werror
you turn every warning into an error.
and then in the program above you would get:
test.cpp: In function ‘int main()’:
test.cpp:13:11: error: conversion to ‘char’ from ‘int’ may alter its value [-
Werror=conversion]
str = a;
^
test.cpp:17:17: error: conversion to ‘char’ from ‘int’ may alter its value [-
Werror=conversion]
str = number();
Upvotes: 1
Reputation: 866
The return value of snprintf
is an int
which can be implicitely casted to a char
therefore str = sprintf(buf, "%s", "test");
calls the character (3) string& operator= (char c);
assignement operator.
The usual way of preventing that is to add the explicit
keyword, but in your case since std::string
is in the library you can't really do anything.
One way of detecting that is using UBSAN which has an option for implicit casts.
Hope that helps!
Upvotes: 3