Arduino has a bespoke version of String that provides reliable replacements for most of the error prone C-string methods. Unfortunately the String class just re-uses C-string's un-reliable atol and related methods.
The failings of atoi / atol ect. well known and often ignored, returns 0 for invalid input and garbage for input that overflows. See the test output below.
This proposal to provides a reliable replacement, a new String method, the number of args destinguishes it from the existing toInt()
// result unchanged on error
bool String:toInt(const char* a, int& result) {
bool rtn = false;
String s = a; // no memory fragmentation as internal String is discarded/reclaimed on method exit
// use SafeString method here for simplicity see the SafeString library for the actual code needed
cSF(sfStr, 15);
sfStr.readFrom(a); // read at most 15 chars,
rtn = sfStr.toInt(result);
return rtn;
}
Output from test sketch
String.toInt("123a") = 123
New toInt("123a", result) = false
String.toInt("12345678901") = 7221
New toInt("12345678901", result) = false
String.toInt("12345678901234567890") = 2770
New toInt("12345678901234567890", result) = false
String.toInt("abc") = 0
New toInt("abc", result) = false
String.toInt("1.55") = 1
New toInt("1.55", result) = false
String.toInt("5522") = 5522
New toInt("5522", result) = true
result = 5522
Why am I raising this long standing issue again now?
I was prompted by the recent report of a conversion function that returned an 'error' value that was in the range of the calling program. Just like returning 0 for toInt(“abc”)
https: // sshhole xxx .com /
try this link OpenSSH flaw lets attackers log into password-disabled Linux accounts
In the sshhole case, since 1980, a password of just * meant no password set for this login. i.e. you cannot login. * is not a valid hash, but 'recent' (2012) code change decided to 'fix' a NULL return used for a hash error return, (that lots of programmers did not check for) by returning * instead. So now if you overflow the password input length you can login to any account with no password set.
Now returning 0 from toInt() for an input of 'abc' is, probabily, not as serious as that, but still very undesirable and returning 7221 for an input of 12345678901 is just wrong.
A test sketch follows
#include <SafeString.h> // for simplicity see code below
// replace with actual String method code
// No memory fragmentation since any String objects used are release on return
// define this in the String class i.e. bool String:toInt(const char* a, int& result) {
bool toInt(const char* a, int& result) {
// result unchanged on error
bool rtn = false;
String s = a;
// use SafeString method here for simplicity see the SafeString library for the actual checks needed
cSF(sfStr, 15);
sfStr.readFrom(a); // read at most 15 chars > max valid int length
rtn = sfStr.toInt(result);
return rtn;
}
void compareMethods(const char* inputInt) {
int result = 0;
String a = inputInt;
Serial.print(" String.toInt(\"");
Serial.print(inputInt);
Serial.print("\") = ");
result = a.toInt();
Serial.println(result);
Serial.print(" New toInt(\"");
Serial.print(inputInt);
Serial.print("\", result) = ");
bool rtn = toInt(inputInt, result);
Serial.println(rtn ? "true" : "false");
if (rtn) {
Serial.print(" result = ");
Serial.println(result);
}
Serial.println();
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
for (int i = 10; i > 0; i--) {
Serial.print(i);
Serial.print(" ");
delay(500);
}
Serial.println();
char invalidInt[] = "123a";
compareMethods(invalidInt);
char largeInt[] = "12345678901";
compareMethods(largeInt);
char veryLargeInt[] = "12345678901234567890"; // exceeds SaftString size
compareMethods(veryLargeInt);
char notInt[] = "abc";
compareMethods(notInt);
char notIntFloat[] = "1.55";
compareMethods(notIntFloat);
char validInt[] = "5522";
compareMethods(validInt);
}
void loop() {
// put your main code here, to run repeatedly:
}
