From b05ec5ae933987e6b4a4f6a318cb13e035ad33e9 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 23 Sep 2014 14:53:10 -0700 Subject: [PATCH] Pull in upstream fixes to reject invalid bases. Also add tests to make sure the full set works correctly. Change-Id: I3e7f237f12c9c93e1185a97c9717803e7e55a73c --- .../lib/libc/stdlib/strtoimax.c | 16 ++++- .../upstream-openbsd/lib/libc/stdlib/strtol.c | 7 +- .../lib/libc/stdlib/strtoll.c | 15 +++- .../lib/libc/stdlib/strtoul.c | 11 ++- .../lib/libc/stdlib/strtoull.c | 15 ++-- .../lib/libc/stdlib/strtoumax.c | 16 +++-- tests/inttypes_test.cpp | 55 +++++++++++++- tests/stdlib_test.cpp | 48 +++++++++++++ tests/wchar_test.cpp | 72 +++++++++++++++++++ 9 files changed, 232 insertions(+), 23 deletions(-) diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoimax.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoimax.c index 2c77f4165..2fc04e485 100644 --- a/libc/upstream-openbsd/lib/libc/stdlib/strtoimax.c +++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoimax.c @@ -1,6 +1,5 @@ -/* $OpenBSD: strtoimax.c,v 1.1 2006/01/13 17:58:09 millert Exp $ */ - -/*- +/* $OpenBSD: strtoimax.c,v 1.2 2014/09/13 20:10:12 schwarze Exp $ */ +/* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * @@ -47,6 +46,17 @@ strtoimax(const char *nptr, char **endptr, int base) int c; int neg, any, cutlim; + /* + * Ensure that base is between 2 and 36 inclusive, or the special + * value of 0. + */ + if (base < 0 || base == 1 || base > 36) { + if (endptr != 0) + *endptr = (char *)nptr; + errno = EINVAL; + return 0; + } + /* * Skip white space and pick up leading +/- sign if any. * If base is 0, allow 0x for hex and 0 for octal, else diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtol.c b/libc/upstream-openbsd/lib/libc/stdlib/strtol.c index dc2cf8871..86cec3508 100644 --- a/libc/upstream-openbsd/lib/libc/stdlib/strtol.c +++ b/libc/upstream-openbsd/lib/libc/stdlib/strtol.c @@ -1,5 +1,5 @@ -/* $OpenBSD: strtol.c,v 1.9 2013/04/17 17:40:35 tedu Exp $ */ -/*- +/* $OpenBSD: strtol.c,v 1.10 2014/09/13 20:10:12 schwarze Exp $ */ +/* * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * @@ -33,7 +33,6 @@ #include #include - /* * Convert a string to a long integer. * @@ -52,7 +51,7 @@ strtol(const char *nptr, char **endptr, int base) * Ensure that base is between 2 and 36 inclusive, or the special * value of 0. */ - if (base != 0 && (base < 2 || base > 36)) { + if (base < 0 || base == 1 || base > 36) { if (endptr != 0) *endptr = (char *)nptr; errno = EINVAL; diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoll.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoll.c index 4bcc5565b..cf82c8e1a 100644 --- a/libc/upstream-openbsd/lib/libc/stdlib/strtoll.c +++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoll.c @@ -1,5 +1,5 @@ -/* $OpenBSD: strtoll.c,v 1.7 2013/03/28 18:09:38 martynas Exp $ */ -/*- +/* $OpenBSD: strtoll.c,v 1.8 2014/09/13 20:10:12 schwarze Exp $ */ +/* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * @@ -49,6 +49,17 @@ strtoll(const char *nptr, char **endptr, int base) int c; int neg, any, cutlim; + /* + * Ensure that base is between 2 and 36 inclusive, or the special + * value of 0. + */ + if (base < 0 || base == 1 || base > 36) { + if (endptr != 0) + *endptr = (char *)nptr; + errno = EINVAL; + return 0; + } + /* * Skip white space and pick up leading +/- sign if any. * If base is 0, allow 0x for hex and 0 for octal, else diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoul.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoul.c index a236365d2..2aa41b76e 100644 --- a/libc/upstream-openbsd/lib/libc/stdlib/strtoul.c +++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoul.c @@ -1,6 +1,6 @@ -/* $OpenBSD: strtoul.c,v 1.8 2013/04/17 17:40:35 tedu Exp $ */ +/* $OpenBSD: strtoul.c,v 1.9 2014/09/13 20:10:12 schwarze Exp $ */ /* - * Copyright (c) 1990 Regents of the University of California. + * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,6 +50,13 @@ strtoul(const char *nptr, char **endptr, int base) /* * See strtol for comments as to the logic used. */ + if (base < 0 || base == 1 || base > 36) { + if (endptr != 0) + *endptr = (char *)nptr; + errno = EINVAL; + return 0; + } + s = nptr; do { c = (unsigned char) *s++; diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoull.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoull.c index 28f613a08..846417630 100644 --- a/libc/upstream-openbsd/lib/libc/stdlib/strtoull.c +++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoull.c @@ -1,5 +1,5 @@ -/* $OpenBSD: strtoull.c,v 1.6 2013/03/28 18:09:38 martynas Exp $ */ -/*- +/* $OpenBSD: strtoull.c,v 1.7 2014/09/13 20:10:12 schwarze Exp $ */ +/* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * @@ -50,8 +50,15 @@ strtoull(const char *nptr, char **endptr, int base) int neg, any, cutlim; /* - * See strtoq for comments as to the logic used. + * See strtoll for comments as to the logic used. */ + if (base < 0 || base == 1 || base > 36) { + if (endptr != 0) + *endptr = (char *)nptr; + errno = EINVAL; + return 0; + } + s = nptr; do { c = (unsigned char) *s++; @@ -59,7 +66,7 @@ strtoull(const char *nptr, char **endptr, int base) if (c == '-') { neg = 1; c = *s++; - } else { + } else { neg = 0; if (c == '+') c = *s++; diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoumax.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoumax.c index ce6e2c00f..c73f7e507 100644 --- a/libc/upstream-openbsd/lib/libc/stdlib/strtoumax.c +++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoumax.c @@ -1,6 +1,5 @@ -/* $OpenBSD: strtoumax.c,v 1.1 2006/01/13 17:58:09 millert Exp $ */ - -/*- +/* $OpenBSD: strtoumax.c,v 1.2 2014/09/13 20:10:12 schwarze Exp $ */ +/* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * @@ -48,8 +47,15 @@ strtoumax(const char *nptr, char **endptr, int base) int neg, any, cutlim; /* - * See strtoq for comments as to the logic used. + * See strtoimax for comments as to the logic used. */ + if (base < 0 || base == 1 || base > 36) { + if (endptr != 0) + *endptr = (char *)nptr; + errno = EINVAL; + return 0; + } + s = nptr; do { c = (unsigned char) *s++; @@ -57,7 +63,7 @@ strtoumax(const char *nptr, char **endptr, int base) if (c == '-') { neg = 1; c = *s++; - } else { + } else { neg = 0; if (c == '+') c = *s++; diff --git a/tests/inttypes_test.cpp b/tests/inttypes_test.cpp index e58850340..dbbb6d4ca 100644 --- a/tests/inttypes_test.cpp +++ b/tests/inttypes_test.cpp @@ -14,11 +14,12 @@ * limitations under the License. */ -#include - -#include #include +#include +#include +#include + TEST(inttypes, misc) { char buf[512]; @@ -46,3 +47,51 @@ TEST(inttypes, wcstoimax) { TEST(inttypes, wcstoumax) { ASSERT_EQ(123U, wcstoumax(L"123", NULL, 10)); } + +TEST(inttypes, strtoimax_EINVAL) { + errno = 0; + strtoimax("123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoimax("123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoimax("123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(inttypes, strtoumax_EINVAL) { + errno = 0; + strtoumax("123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoumax("123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoumax("123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(inttypes, wcstoimax_EINVAL) { + errno = 0; + wcstoimax(L"123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoimax(L"123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoimax(L"123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(inttypes, wcstoumax_EINVAL) { + errno = 0; + wcstoumax(L"123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoumax(L"123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoumax(L"123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp index 553f018ed..667ccd6a4 100644 --- a/tests/stdlib_test.cpp +++ b/tests/stdlib_test.cpp @@ -361,3 +361,51 @@ TEST(stdlib, unlockpt_ENOTTY) { ASSERT_EQ(ENOTTY, errno); close(fd); } + +TEST(stdlib, strtol_EINVAL) { + errno = 0; + strtol("123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtol("123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtol("123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(stdlib, strtoll_EINVAL) { + errno = 0; + strtoll("123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoll("123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoll("123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(stdlib, strtoul_EINVAL) { + errno = 0; + strtoul("123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoul("123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoul("123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(stdlib, strtoull_EINVAL) { + errno = 0; + strtoull("123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoull("123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + strtoull("123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp index 760475fa1..887266cfa 100644 --- a/tests/wchar_test.cpp +++ b/tests/wchar_test.cpp @@ -520,3 +520,75 @@ TEST(stdio, open_wmemstream_EINVAL) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } + +TEST(wchar, wcstol_EINVAL) { + errno = 0; + wcstol(L"123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstol(L"123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstol(L"123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(wchar, wcstoll_EINVAL) { + errno = 0; + wcstoll(L"123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoll(L"123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoll(L"123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(wchar, wcstoul_EINVAL) { + errno = 0; + wcstoul(L"123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoul(L"123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoul(L"123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(wchar, wcstoull_EINVAL) { + errno = 0; + wcstoull(L"123", NULL, -1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoull(L"123", NULL, 1); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoull(L"123", NULL, 37); + ASSERT_EQ(EINVAL, errno); +} + +TEST(wchar, wcstoll_l_EINVAL) { + errno = 0; + wcstoll_l(L"123", NULL, -1, LC_GLOBAL_LOCALE); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoll_l(L"123", NULL, 1, LC_GLOBAL_LOCALE); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoll_l(L"123", NULL, 37, LC_GLOBAL_LOCALE); + ASSERT_EQ(EINVAL, errno); +} + +TEST(wchar, wcstoull_l_EINVAL) { + errno = 0; + wcstoull_l(L"123", NULL, -1, LC_GLOBAL_LOCALE); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoull_l(L"123", NULL, 1, LC_GLOBAL_LOCALE); + ASSERT_EQ(EINVAL, errno); + errno = 0; + wcstoull_l(L"123", NULL, 37, LC_GLOBAL_LOCALE); + ASSERT_EQ(EINVAL, errno); +}