-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fish converts an empty string to zero in numeric contexts #3346
Comments
Actually, the OS X/Linux difference here and the cause of the builtin_test failure are likely quite related: checking Consider how we were checking for a successful conversion by static bool parse_number(const wcstring &arg, long long *out, wcstring_list_t &errors) {
const wchar_t *str = arg.c_str();
wchar_t *endptr = NULL;
*out = wcstoll(str, &endptr, 10);
return endptr && *endptr == L'\0';
} wcstoll returns 0 in the case of failure. Here's the manpage suggesting how to test that the string was not invalid:
By only doing half of this by checking Linux vs. OS XIn my changes I went further than using only the prescribed test from the manpage for static bool parse_number(const wcstring &arg, long long *out, wcstring_list_t &errors) {
+ using namespace test_expressions;
const wchar_t *str = arg.c_str();
wchar_t *endptr = NULL;
+ // from the manual:
+ // If endptr is not NULL, wcstrtoll() stores the address of the first invalid
+ // character in *endptr. If there were no digits at all, strtol() stores
+ // the original value of str in *endptr. (Thus, if *str is not L'\0' but
+ // **endptr is `\0' on return, the entire string was valid.)
+
+ errno = 0;
*out = wcstoll(str, &endptr, 10);
- return endptr && *endptr == L'\0';
+
+ // XXX DONTCOMMITAARON use &errors instead before committing
+ if (errno == EINVAL) {
+ debug(0, L"Invalid digit: '%S'", endptr);
+ return false;
+ } else if (errno == ERANGE) {
+ debug(0, L"Out of range digit: '%S'", endptr);
+ return false;
+ }
+
+ return *str != L'\0' && *endptr == L'\0'; I recall that according to the manpage, the behavior of errno being set
My hunch would be that in So I might not want to check for |
Indeed, commenting out the errno check in void builtin_printf_state_t::verify_numeric(const wchar_t *s, const wchar_t *end, int errcode) {
/*if (errcode != 0) {
this->fatal_error(L"%ls: %s", s, strerror(errcode));
} else*/ if (*end) {
if (s == end)
this->fatal_error(_(L"%ls: expected a numeric value"), s);
else
this->fatal_error(_(L"%ls: value not completely converted"), s);
}
} > printf \%d ''
0⏎ It needs to check |
FYI I reverted f843eb3 |
Fixing issue #3570 caused me to notice that there are numerous places in the fish code that set |
This augments the previous change for issue #3346 by adding an error message when an invalid integer is seen. This change is likely to be controversial so I'm not going to squash it into the previous change.
Several recent issues involving the
test
andprintf
builtins brought to light that fish is inconsistent about how it treats an empty, null, string when converting it to a number. For example,test "" -ge 0
is considered true because the empty string is converted to a zero. Doingprintf '%f\n' ""
prints0.000000
. Yet the similarprintf '%d\n' ""
on macOS Sierra (as of git commit eeb42f5) reports the error ": Invalid argument". Whereasprintf '%f\n' ""
prints "0.00000". On the other hand theprintf '%d\n' ""
on Ubuntu 16.04 (with the same version of fish) prints "0".While I am curious why Ubuntu and macOS Sierra handle the
printf '%d\n' ""
case differently it's orthogonal to the core point of this issue. Which is, fish should consistently treat an empty, null, string (i.e., "") as an invalid number. The current behavior is problematic. It will also be inconsistent if the change I believe @floam is working on to make thetest "" -ge 0
scenario be an error rather than return a true (zero) status is merged.See also issue #3334.
The text was updated successfully, but these errors were encountered: