Add a template to parse integers easily/correctly (#3405)

* Adds a template to parse integers easily.

It's not enough to use intmax_t and check for empty strings: there are
limits. Adds a template to make it easy to parse an integer of any type.

Adds a compiler flag to flag existing dangers.

* nix warning, include <limits>, fix namespace error.

on MacOS `xcodebuild -quiet` will flag these intmax_t -> * conversions,
just use that if you want to find them.
This commit is contained in:
Aaron Gyes 2016-09-25 21:50:55 -07:00 committed by GitHub
parent e9b5505169
commit f843eb3d31
2 changed files with 20 additions and 2 deletions

View File

@ -1594,8 +1594,8 @@ int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_lis
e.param1.job_id = job_id;
}
} else {
pid_t pid = wcstoimax(w.woptarg, &end, 10);
if (pid < 1 || !(*w.woptarg != L'\0' && *end == L'\0')) {
pid_t pid;
if (!(parse_integer(w.woptarg, &pid)) || pid < 1) {
append_format(*out_err, _(L"%ls: Invalid process id '%ls'"), argv[0],
w.woptarg);
res = STATUS_BUILTIN_ERROR;

View File

@ -11,6 +11,9 @@
#include <string.h>
#include <sys/types.h>
#include <termios.h>
#include <stddef.h>
#include <limits>
#include <inttypes.h>
#include <wchar.h>
#include <memory>
#include <sstream>
@ -692,6 +695,21 @@ ssize_t read_loop(int fd, void *buff, size_t count);
void __attribute__((noinline)) debug(int level, const char *msg, ...);
void __attribute__((noinline)) debug(int level, const wchar_t *msg, ...);
/// Parse an integer and check limits for type
/// The only way to be safe from overflows is intmax_t.
/// Do that, and make sure the result isn't bigger than the maximum supported for whatever type.
template <typename T>
bool parse_integer(const wchar_t *in, T* out) {
wchar_t *end;
intmax_t res = wcstoimax(in, &end, 0);
if (!(*in != L'\0' && *end == L'\0')) return false;
if (std::numeric_limits<T>::max() < res || res < std::numeric_limits<T>::min()) return false;
*out = static_cast<T>(res);
return true;
}
/// Replace special characters with backslash escape sequences. Newline is replaced with \n, etc.
///
/// \param in The string to be escaped