diff mbox series

[2/3] kstrtox: add unit tests for memparse_safe()

Message ID 56ea15d8b430f4fe3f8e55509ad0bc72b1d9356f.1703324146.git.wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series kstrtox: introduce memparse_safe() | expand

Commit Message

Qu Wenruo Dec. 23, 2023, 9:58 a.m. UTC
The new tests cases for memparse_safe() include:

- The existing test cases for kstrtoull()
  Including all the 3 bases (8, 10, 16), and all the ok and failure
  cases.
  Although there are something we need to verify specific for
  memparse_safe():

  * @retptr and @value are not modified for failure cases

  * return value are correct for failure cases

  * @retptr is correct for the good cases

- New test cases
  Not only testing the result value, but also the @retptr, including:

  * good cases with extra tailing chars, but without valid prefix
    The @retptr should point to the first char after a valid string.
    3 cases for all the 3 bases.

  * good cases with extra tailing chars, with valid prefix
    5 cases for all the suffixes.

  * bad cases without any number but stray suffix
    Should be rejected with -EINVAL

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 lib/test-kstrtox.c | 217 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 217 insertions(+)

Comments

kernel test robot Dec. 26, 2023, 6:36 a.m. UTC | #1
Hi Qu,

kernel test robot noticed the following build warnings:

[auto build test WARNING on kdave/for-next]
[also build test WARNING on akpm-mm/mm-everything linus/master v6.7-rc7 next-20231222]
[cannot apply to akpm-mm/mm-nonmm-unstable]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Qu-Wenruo/kstrtox-introduce-a-safer-version-of-memparse/20231225-151921
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
patch link:    https://lore.kernel.org/r/56ea15d8b430f4fe3f8e55509ad0bc72b1d9356f.1703324146.git.wqu%40suse.com
patch subject: [PATCH 2/3] kstrtox: add unit tests for memparse_safe()
config: m68k-randconfig-r133-20231226 (https://download.01.org/0day-ci/archive/20231226/202312261423.zqIlU2hn-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20231226/202312261423.zqIlU2hn-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312261423.zqIlU2hn-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> lib/test-kstrtox.c:339:40: sparse: sparse: cast truncates bits from constant value (efefefef7a7a7a7a becomes 7a7a7a7a)
   lib/test-kstrtox.c:351:39: sparse: sparse: cast truncates bits from constant value (efefefef7a7a7a7a becomes 7a7a7a7a)

vim +339 lib/test-kstrtox.c

   275	
   276	/* Want to include "E" suffix for full coverage. */
   277	#define MEMPARSE_TEST_SUFFIX	(MEMPARSE_SUFFIX_K | MEMPARSE_SUFFIX_M |\
   278					 MEMPARSE_SUFFIX_G | MEMPARSE_SUFFIX_T |\
   279					 MEMPARSE_SUFFIX_P | MEMPARSE_SUFFIX_E)
   280	
   281	static void __init test_memparse_safe_fail(void)
   282	{
   283		struct memparse_test_fail {
   284			const char *str;
   285			/* Expected error number, either -EINVAL or -ERANGE. */
   286			unsigned int expected_ret;
   287		};
   288		static const struct memparse_test_fail tests[] __initconst = {
   289			/* No valid string can be found at all. */
   290			{"", -EINVAL},
   291			{"\n", -EINVAL},
   292			{"\n0", -EINVAL},
   293			{"+", -EINVAL},
   294			{"-", -EINVAL},
   295	
   296			/*
   297			 * No support for any leading "+-" chars, even followed by a valid
   298			 * number.
   299			 */
   300			{"-0", -EINVAL},
   301			{"+0", -EINVAL},
   302			{"-1", -EINVAL},
   303			{"+1", -EINVAL},
   304	
   305			/* Stray suffix would also be rejected. */
   306			{"K", -EINVAL},
   307			{"P", -EINVAL},
   308	
   309			/* Overflow in the string itself*/
   310			{"18446744073709551616", -ERANGE},
   311			{"02000000000000000000000", -ERANGE},
   312			{"0x10000000000000000",	-ERANGE},
   313	
   314			/*
   315			 * Good string but would overflow with suffix.
   316			 *
   317			 * Note, for "E" suffix, one should not use with hex, or "0x1E"
   318			 * would be treated as 0x1e (30 in decimal), not 0x1 and "E" suffix.
   319			 * Another reason "E" suffix is cursed.
   320			 */
   321			{"16E", -ERANGE},
   322			{"020E", -ERANGE},
   323			{"16384P", -ERANGE},
   324			{"040000P", -ERANGE},
   325			{"16777216T", -ERANGE},
   326			{"0100000000T", -ERANGE},
   327			{"17179869184G", -ERANGE},
   328			{"0200000000000G", -ERANGE},
   329			{"17592186044416M", -ERANGE},
   330			{"0400000000000000M", -ERANGE},
   331			{"18014398509481984K", -ERANGE},
   332			{"01000000000000000000K", -ERANGE},
   333		};
   334		unsigned int i;
   335	
   336		for_each_test(i, tests) {
   337			const struct memparse_test_fail *t = &tests[i];
   338			unsigned long long tmp = ULL_PATTERN;
 > 339			char *retptr = (char *)ULL_PATTERN;
   340			int ret;
   341	
   342			ret = memparse_safe(t->str, MEMPARSE_TEST_SUFFIX, &tmp, &retptr);
   343			if (ret != t->expected_ret) {
   344				WARN(1, "str '%s', expected ret %d got %d\n", t->str,
   345				     t->expected_ret, ret);
   346				continue;
   347			}
   348			if (tmp != ULL_PATTERN)
   349				WARN(1, "str '%s' failed as expected, but result got modified",
   350				     t->str);
   351			if (retptr != (char *)ULL_PATTERN)
   352				WARN(1, "str '%s' failed as expected, but pointer got modified",
   353				     t->str);
   354		}
   355	}
   356
Qu Wenruo Dec. 26, 2023, 7:37 a.m. UTC | #2
On 2023/12/26 17:06, kernel test robot wrote:
> Hi Qu,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on kdave/for-next]
> [also build test WARNING on akpm-mm/mm-everything linus/master v6.7-rc7 next-20231222]
> [cannot apply to akpm-mm/mm-nonmm-unstable]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Qu-Wenruo/kstrtox-introduce-a-safer-version-of-memparse/20231225-151921
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
> patch link:    https://lore.kernel.org/r/56ea15d8b430f4fe3f8e55509ad0bc72b1d9356f.1703324146.git.wqu%40suse.com
> patch subject: [PATCH 2/3] kstrtox: add unit tests for memparse_safe()
> config: m68k-randconfig-r133-20231226 (https://download.01.org/0day-ci/archive/20231226/202312261423.zqIlU2hn-lkp@intel.com/config)
> compiler: m68k-linux-gcc (GCC) 13.2.0
> reproduce: (https://download.01.org/0day-ci/archive/20231226/202312261423.zqIlU2hn-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202312261423.zqIlU2hn-lkp@intel.com/
>
> sparse warnings: (new ones prefixed by >>)
>>> lib/test-kstrtox.c:339:40: sparse: sparse: cast truncates bits from constant value (efefefef7a7a7a7a becomes 7a7a7a7a)
>     lib/test-kstrtox.c:351:39: sparse: sparse: cast truncates bits from constant value (efefefef7a7a7a7a becomes 7a7a7a7a)

Any way to suppress the warning? As long as the constant value (u64) is
checked against the same truncated value (u32), the result should be fine.

I really want to make sure the pointer is not incorrectly updated in the
failure case.

Thanks,
Qu
>
> vim +339 lib/test-kstrtox.c
>
>     275
>     276	/* Want to include "E" suffix for full coverage. */
>     277	#define MEMPARSE_TEST_SUFFIX	(MEMPARSE_SUFFIX_K | MEMPARSE_SUFFIX_M |\
>     278					 MEMPARSE_SUFFIX_G | MEMPARSE_SUFFIX_T |\
>     279					 MEMPARSE_SUFFIX_P | MEMPARSE_SUFFIX_E)
>     280
>     281	static void __init test_memparse_safe_fail(void)
>     282	{
>     283		struct memparse_test_fail {
>     284			const char *str;
>     285			/* Expected error number, either -EINVAL or -ERANGE. */
>     286			unsigned int expected_ret;
>     287		};
>     288		static const struct memparse_test_fail tests[] __initconst = {
>     289			/* No valid string can be found at all. */
>     290			{"", -EINVAL},
>     291			{"\n", -EINVAL},
>     292			{"\n0", -EINVAL},
>     293			{"+", -EINVAL},
>     294			{"-", -EINVAL},
>     295
>     296			/*
>     297			 * No support for any leading "+-" chars, even followed by a valid
>     298			 * number.
>     299			 */
>     300			{"-0", -EINVAL},
>     301			{"+0", -EINVAL},
>     302			{"-1", -EINVAL},
>     303			{"+1", -EINVAL},
>     304
>     305			/* Stray suffix would also be rejected. */
>     306			{"K", -EINVAL},
>     307			{"P", -EINVAL},
>     308
>     309			/* Overflow in the string itself*/
>     310			{"18446744073709551616", -ERANGE},
>     311			{"02000000000000000000000", -ERANGE},
>     312			{"0x10000000000000000",	-ERANGE},
>     313
>     314			/*
>     315			 * Good string but would overflow with suffix.
>     316			 *
>     317			 * Note, for "E" suffix, one should not use with hex, or "0x1E"
>     318			 * would be treated as 0x1e (30 in decimal), not 0x1 and "E" suffix.
>     319			 * Another reason "E" suffix is cursed.
>     320			 */
>     321			{"16E", -ERANGE},
>     322			{"020E", -ERANGE},
>     323			{"16384P", -ERANGE},
>     324			{"040000P", -ERANGE},
>     325			{"16777216T", -ERANGE},
>     326			{"0100000000T", -ERANGE},
>     327			{"17179869184G", -ERANGE},
>     328			{"0200000000000G", -ERANGE},
>     329			{"17592186044416M", -ERANGE},
>     330			{"0400000000000000M", -ERANGE},
>     331			{"18014398509481984K", -ERANGE},
>     332			{"01000000000000000000K", -ERANGE},
>     333		};
>     334		unsigned int i;
>     335
>     336		for_each_test(i, tests) {
>     337			const struct memparse_test_fail *t = &tests[i];
>     338			unsigned long long tmp = ULL_PATTERN;
>   > 339			char *retptr = (char *)ULL_PATTERN;
>     340			int ret;
>     341
>     342			ret = memparse_safe(t->str, MEMPARSE_TEST_SUFFIX, &tmp, &retptr);
>     343			if (ret != t->expected_ret) {
>     344				WARN(1, "str '%s', expected ret %d got %d\n", t->str,
>     345				     t->expected_ret, ret);
>     346				continue;
>     347			}
>     348			if (tmp != ULL_PATTERN)
>     349				WARN(1, "str '%s' failed as expected, but result got modified",
>     350				     t->str);
>     351			if (retptr != (char *)ULL_PATTERN)
>     352				WARN(1, "str '%s' failed as expected, but pointer got modified",
>     353				     t->str);
>     354		}
>     355	}
>     356
>
Yujie Liu Jan. 2, 2024, 1:33 a.m. UTC | #3
On Tue, Dec 26, 2023 at 06:07:40PM +1030, Qu Wenruo wrote:
> On 2023/12/26 17:06, kernel test robot wrote:
> > Hi Qu,
> > 
> > kernel test robot noticed the following build warnings:
> > 
> > [auto build test WARNING on kdave/for-next]
> > [also build test WARNING on akpm-mm/mm-everything linus/master v6.7-rc7 next-20231222]
> > [cannot apply to akpm-mm/mm-nonmm-unstable]
> > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > And when submitting patch, we suggest to use '--base' as documented in
> > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> > 
> > url:    https://github.com/intel-lab-lkp/linux/commits/Qu-Wenruo/kstrtox-introduce-a-safer-version-of-memparse/20231225-151921
> > base:   https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
> > patch link:    https://lore.kernel.org/r/56ea15d8b430f4fe3f8e55509ad0bc72b1d9356f.1703324146.git.wqu%40suse.com
> > patch subject: [PATCH 2/3] kstrtox: add unit tests for memparse_safe()
> > config: m68k-randconfig-r133-20231226 (https://download.01.org/0day-ci/archive/20231226/202312261423.zqIlU2hn-lkp@intel.com/config)
> > compiler: m68k-linux-gcc (GCC) 13.2.0
> > reproduce: (https://download.01.org/0day-ci/archive/20231226/202312261423.zqIlU2hn-lkp@intel.com/reproduce)
> > 
> > If you fix the issue in a separate patch/commit (i.e. not just a new version of
> > the same patch/commit), kindly add following tags
> > | Reported-by: kernel test robot <lkp@intel.com>
> > | Closes: https://lore.kernel.org/oe-kbuild-all/202312261423.zqIlU2hn-lkp@intel.com/
> > 
> > sparse warnings: (new ones prefixed by >>)
> > > > lib/test-kstrtox.c:339:40: sparse: sparse: cast truncates bits from constant value (efefefef7a7a7a7a becomes 7a7a7a7a)
> >     lib/test-kstrtox.c:351:39: sparse: sparse: cast truncates bits from constant value (efefefef7a7a7a7a becomes 7a7a7a7a)
> 
> Any way to suppress the warning? As long as the constant value (u64) is
> checked against the same truncated value (u32), the result should be fine.

Hi Qu, we've suppressed this warning in the bot for the specific file
lib/test-kstrtox.c, while keep it enabled for the rest. If there are
similar warnings in other files that could be false positives, we will
also suppress them later.

Thanks,
Yujie

> 
> I really want to make sure the pointer is not incorrectly updated in the
> failure case.
> 
> Thanks,
> Qu
> > 
> > vim +339 lib/test-kstrtox.c
> > 
> >     275
> >     276	/* Want to include "E" suffix for full coverage. */
> >     277	#define MEMPARSE_TEST_SUFFIX	(MEMPARSE_SUFFIX_K | MEMPARSE_SUFFIX_M |\
> >     278					 MEMPARSE_SUFFIX_G | MEMPARSE_SUFFIX_T |\
> >     279					 MEMPARSE_SUFFIX_P | MEMPARSE_SUFFIX_E)
> >     280
> >     281	static void __init test_memparse_safe_fail(void)
> >     282	{
> >     283		struct memparse_test_fail {
> >     284			const char *str;
> >     285			/* Expected error number, either -EINVAL or -ERANGE. */
> >     286			unsigned int expected_ret;
> >     287		};
> >     288		static const struct memparse_test_fail tests[] __initconst = {
> >     289			/* No valid string can be found at all. */
> >     290			{"", -EINVAL},
> >     291			{"\n", -EINVAL},
> >     292			{"\n0", -EINVAL},
> >     293			{"+", -EINVAL},
> >     294			{"-", -EINVAL},
> >     295
> >     296			/*
> >     297			 * No support for any leading "+-" chars, even followed by a valid
> >     298			 * number.
> >     299			 */
> >     300			{"-0", -EINVAL},
> >     301			{"+0", -EINVAL},
> >     302			{"-1", -EINVAL},
> >     303			{"+1", -EINVAL},
> >     304
> >     305			/* Stray suffix would also be rejected. */
> >     306			{"K", -EINVAL},
> >     307			{"P", -EINVAL},
> >     308
> >     309			/* Overflow in the string itself*/
> >     310			{"18446744073709551616", -ERANGE},
> >     311			{"02000000000000000000000", -ERANGE},
> >     312			{"0x10000000000000000",	-ERANGE},
> >     313
> >     314			/*
> >     315			 * Good string but would overflow with suffix.
> >     316			 *
> >     317			 * Note, for "E" suffix, one should not use with hex, or "0x1E"
> >     318			 * would be treated as 0x1e (30 in decimal), not 0x1 and "E" suffix.
> >     319			 * Another reason "E" suffix is cursed.
> >     320			 */
> >     321			{"16E", -ERANGE},
> >     322			{"020E", -ERANGE},
> >     323			{"16384P", -ERANGE},
> >     324			{"040000P", -ERANGE},
> >     325			{"16777216T", -ERANGE},
> >     326			{"0100000000T", -ERANGE},
> >     327			{"17179869184G", -ERANGE},
> >     328			{"0200000000000G", -ERANGE},
> >     329			{"17592186044416M", -ERANGE},
> >     330			{"0400000000000000M", -ERANGE},
> >     331			{"18014398509481984K", -ERANGE},
> >     332			{"01000000000000000000K", -ERANGE},
> >     333		};
> >     334		unsigned int i;
> >     335
> >     336		for_each_test(i, tests) {
> >     337			const struct memparse_test_fail *t = &tests[i];
> >     338			unsigned long long tmp = ULL_PATTERN;
> >   > 339			char *retptr = (char *)ULL_PATTERN;
> >     340			int ret;
> >     341
> >     342			ret = memparse_safe(t->str, MEMPARSE_TEST_SUFFIX, &tmp, &retptr);
> >     343			if (ret != t->expected_ret) {
> >     344				WARN(1, "str '%s', expected ret %d got %d\n", t->str,
> >     345				     t->expected_ret, ret);
> >     346				continue;
> >     347			}
> >     348			if (tmp != ULL_PATTERN)
> >     349				WARN(1, "str '%s' failed as expected, but result got modified",
> >     350				     t->str);
> >     351			if (retptr != (char *)ULL_PATTERN)
> >     352				WARN(1, "str '%s' failed as expected, but pointer got modified",
> >     353				     t->str);
> >     354		}
> >     355	}
> >     356
> > 
>
Qu Wenruo Jan. 2, 2024, 2:03 a.m. UTC | #4
On 2024/1/2 12:03, Yujie Liu wrote:
> On Tue, Dec 26, 2023 at 06:07:40PM +1030, Qu Wenruo wrote:
>> On 2023/12/26 17:06, kernel test robot wrote:
>>> Hi Qu,
>>>
>>> kernel test robot noticed the following build warnings:
>>>
>>> [auto build test WARNING on kdave/for-next]
>>> [also build test WARNING on akpm-mm/mm-everything linus/master v6.7-rc7 next-20231222]
>>> [cannot apply to akpm-mm/mm-nonmm-unstable]
>>> [If your patch is applied to the wrong git tree, kindly drop us a note.
>>> And when submitting patch, we suggest to use '--base' as documented in
>>> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>>>
>>> url:    https://github.com/intel-lab-lkp/linux/commits/Qu-Wenruo/kstrtox-introduce-a-safer-version-of-memparse/20231225-151921
>>> base:   https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
>>> patch link:    https://lore.kernel.org/r/56ea15d8b430f4fe3f8e55509ad0bc72b1d9356f.1703324146.git.wqu%40suse.com
>>> patch subject: [PATCH 2/3] kstrtox: add unit tests for memparse_safe()
>>> config: m68k-randconfig-r133-20231226 (https://download.01.org/0day-ci/archive/20231226/202312261423.zqIlU2hn-lkp@intel.com/config)
>>> compiler: m68k-linux-gcc (GCC) 13.2.0
>>> reproduce: (https://download.01.org/0day-ci/archive/20231226/202312261423.zqIlU2hn-lkp@intel.com/reproduce)
>>>
>>> If you fix the issue in a separate patch/commit (i.e. not just a new version of
>>> the same patch/commit), kindly add following tags
>>> | Reported-by: kernel test robot <lkp@intel.com>
>>> | Closes: https://lore.kernel.org/oe-kbuild-all/202312261423.zqIlU2hn-lkp@intel.com/
>>>
>>> sparse warnings: (new ones prefixed by >>)
>>>>> lib/test-kstrtox.c:339:40: sparse: sparse: cast truncates bits from constant value (efefefef7a7a7a7a becomes 7a7a7a7a)
>>>      lib/test-kstrtox.c:351:39: sparse: sparse: cast truncates bits from constant value (efefefef7a7a7a7a becomes 7a7a7a7a)
>>
>> Any way to suppress the warning? As long as the constant value (u64) is
>> checked against the same truncated value (u32), the result should be fine.
>
> Hi Qu, we've suppressed this warning in the bot for the specific file
> lib/test-kstrtox.c, while keep it enabled for the rest. If there are
> similar warnings in other files that could be false positives, we will
> also suppress them later.

I'll update the pattern depending on the ULL size to avoid the warning.

Thanks,
Qu
>
> Thanks,
> Yujie
>
>>
>> I really want to make sure the pointer is not incorrectly updated in the
>> failure case.
>>
>> Thanks,
>> Qu
>>>
>>> vim +339 lib/test-kstrtox.c
>>>
>>>      275
>>>      276	/* Want to include "E" suffix for full coverage. */
>>>      277	#define MEMPARSE_TEST_SUFFIX	(MEMPARSE_SUFFIX_K | MEMPARSE_SUFFIX_M |\
>>>      278					 MEMPARSE_SUFFIX_G | MEMPARSE_SUFFIX_T |\
>>>      279					 MEMPARSE_SUFFIX_P | MEMPARSE_SUFFIX_E)
>>>      280
>>>      281	static void __init test_memparse_safe_fail(void)
>>>      282	{
>>>      283		struct memparse_test_fail {
>>>      284			const char *str;
>>>      285			/* Expected error number, either -EINVAL or -ERANGE. */
>>>      286			unsigned int expected_ret;
>>>      287		};
>>>      288		static const struct memparse_test_fail tests[] __initconst = {
>>>      289			/* No valid string can be found at all. */
>>>      290			{"", -EINVAL},
>>>      291			{"\n", -EINVAL},
>>>      292			{"\n0", -EINVAL},
>>>      293			{"+", -EINVAL},
>>>      294			{"-", -EINVAL},
>>>      295
>>>      296			/*
>>>      297			 * No support for any leading "+-" chars, even followed by a valid
>>>      298			 * number.
>>>      299			 */
>>>      300			{"-0", -EINVAL},
>>>      301			{"+0", -EINVAL},
>>>      302			{"-1", -EINVAL},
>>>      303			{"+1", -EINVAL},
>>>      304
>>>      305			/* Stray suffix would also be rejected. */
>>>      306			{"K", -EINVAL},
>>>      307			{"P", -EINVAL},
>>>      308
>>>      309			/* Overflow in the string itself*/
>>>      310			{"18446744073709551616", -ERANGE},
>>>      311			{"02000000000000000000000", -ERANGE},
>>>      312			{"0x10000000000000000",	-ERANGE},
>>>      313
>>>      314			/*
>>>      315			 * Good string but would overflow with suffix.
>>>      316			 *
>>>      317			 * Note, for "E" suffix, one should not use with hex, or "0x1E"
>>>      318			 * would be treated as 0x1e (30 in decimal), not 0x1 and "E" suffix.
>>>      319			 * Another reason "E" suffix is cursed.
>>>      320			 */
>>>      321			{"16E", -ERANGE},
>>>      322			{"020E", -ERANGE},
>>>      323			{"16384P", -ERANGE},
>>>      324			{"040000P", -ERANGE},
>>>      325			{"16777216T", -ERANGE},
>>>      326			{"0100000000T", -ERANGE},
>>>      327			{"17179869184G", -ERANGE},
>>>      328			{"0200000000000G", -ERANGE},
>>>      329			{"17592186044416M", -ERANGE},
>>>      330			{"0400000000000000M", -ERANGE},
>>>      331			{"18014398509481984K", -ERANGE},
>>>      332			{"01000000000000000000K", -ERANGE},
>>>      333		};
>>>      334		unsigned int i;
>>>      335
>>>      336		for_each_test(i, tests) {
>>>      337			const struct memparse_test_fail *t = &tests[i];
>>>      338			unsigned long long tmp = ULL_PATTERN;
>>>    > 339			char *retptr = (char *)ULL_PATTERN;
>>>      340			int ret;
>>>      341
>>>      342			ret = memparse_safe(t->str, MEMPARSE_TEST_SUFFIX, &tmp, &retptr);
>>>      343			if (ret != t->expected_ret) {
>>>      344				WARN(1, "str '%s', expected ret %d got %d\n", t->str,
>>>      345				     t->expected_ret, ret);
>>>      346				continue;
>>>      347			}
>>>      348			if (tmp != ULL_PATTERN)
>>>      349				WARN(1, "str '%s' failed as expected, but result got modified",
>>>      350				     t->str);
>>>      351			if (retptr != (char *)ULL_PATTERN)
>>>      352				WARN(1, "str '%s' failed as expected, but pointer got modified",
>>>      353				     t->str);
>>>      354		}
>>>      355	}
>>>      356
>>>
>>
>
diff mbox series

Patch

diff --git a/lib/test-kstrtox.c b/lib/test-kstrtox.c
index f355f67169b6..094beab3dfac 100644
--- a/lib/test-kstrtox.c
+++ b/lib/test-kstrtox.c
@@ -268,6 +268,219 @@  static void __init test_kstrtoll_ok(void)
 	TEST_OK(kstrtoll, long long, "%lld", test_ll_ok);
 }
 
+/*
+ * The special pattern to make sure the result is not modified for error cases.
+ */
+#define ULL_PATTERN		(0xefefefef7a7a7a7aULL)
+
+/* Want to include "E" suffix for full coverage. */
+#define MEMPARSE_TEST_SUFFIX	(MEMPARSE_SUFFIX_K | MEMPARSE_SUFFIX_M |\
+				 MEMPARSE_SUFFIX_G | MEMPARSE_SUFFIX_T |\
+				 MEMPARSE_SUFFIX_P | MEMPARSE_SUFFIX_E)
+
+static void __init test_memparse_safe_fail(void)
+{
+	struct memparse_test_fail {
+		const char *str;
+		/* Expected error number, either -EINVAL or -ERANGE. */
+		unsigned int expected_ret;
+	};
+	static const struct memparse_test_fail tests[] __initconst = {
+		/* No valid string can be found at all. */
+		{"", -EINVAL},
+		{"\n", -EINVAL},
+		{"\n0", -EINVAL},
+		{"+", -EINVAL},
+		{"-", -EINVAL},
+
+		/*
+		 * No support for any leading "+-" chars, even followed by a valid
+		 * number.
+		 */
+		{"-0", -EINVAL},
+		{"+0", -EINVAL},
+		{"-1", -EINVAL},
+		{"+1", -EINVAL},
+
+		/* Stray suffix would also be rejected. */
+		{"K", -EINVAL},
+		{"P", -EINVAL},
+
+		/* Overflow in the string itself*/
+		{"18446744073709551616", -ERANGE},
+		{"02000000000000000000000", -ERANGE},
+		{"0x10000000000000000",	-ERANGE},
+
+		/*
+		 * Good string but would overflow with suffix.
+		 *
+		 * Note, for "E" suffix, one should not use with hex, or "0x1E"
+		 * would be treated as 0x1e (30 in decimal), not 0x1 and "E" suffix.
+		 * Another reason "E" suffix is cursed.
+		 */
+		{"16E", -ERANGE},
+		{"020E", -ERANGE},
+		{"16384P", -ERANGE},
+		{"040000P", -ERANGE},
+		{"16777216T", -ERANGE},
+		{"0100000000T", -ERANGE},
+		{"17179869184G", -ERANGE},
+		{"0200000000000G", -ERANGE},
+		{"17592186044416M", -ERANGE},
+		{"0400000000000000M", -ERANGE},
+		{"18014398509481984K", -ERANGE},
+		{"01000000000000000000K", -ERANGE},
+	};
+	unsigned int i;
+
+	for_each_test(i, tests) {
+		const struct memparse_test_fail *t = &tests[i];
+		unsigned long long tmp = ULL_PATTERN;
+		char *retptr = (char *)ULL_PATTERN;
+		int ret;
+
+		ret = memparse_safe(t->str, MEMPARSE_TEST_SUFFIX, &tmp, &retptr);
+		if (ret != t->expected_ret) {
+			WARN(1, "str '%s', expected ret %d got %d\n", t->str,
+			     t->expected_ret, ret);
+			continue;
+		}
+		if (tmp != ULL_PATTERN)
+			WARN(1, "str '%s' failed as expected, but result got modified",
+			     t->str);
+		if (retptr != (char *)ULL_PATTERN)
+			WARN(1, "str '%s' failed as expected, but pointer got modified",
+			     t->str);
+	}
+}
+
+static void __init test_memparse_safe_ok(void)
+{
+	struct memparse_test_ok {
+		const char *str;
+		unsigned long long expected_value;
+		/* How many bytes the @retptr pointer should be moved forward. */
+		unsigned int retptr_off;
+	};
+	static DEFINE_TEST_OK(struct memparse_test_ok, tests) = {
+		/*
+		 * The same pattern of kstrtoull, just with extra @retptr
+		 * verification.
+		 */
+		{"0",			0ULL,			1},
+		{"1",			1ULL,			1},
+		{"127",			127ULL,			3},
+		{"128",			128ULL,			3},
+		{"129",			129ULL,			3},
+		{"255",			255ULL,			3},
+		{"256",			256ULL,			3},
+		{"257",			257ULL,			3},
+		{"32767",		32767ULL,		5},
+		{"32768",		32768ULL,		5},
+		{"32769",		32769ULL,		5},
+		{"65535",		65535ULL,		5},
+		{"65536",		65536ULL,		5},
+		{"65537",		65537ULL,		5},
+		{"2147483647",		2147483647ULL,		10},
+		{"2147483648",		2147483648ULL,		10},
+		{"2147483649",		2147483649ULL,		10},
+		{"4294967295",		4294967295ULL,		10},
+		{"4294967296",		4294967296ULL,		10},
+		{"4294967297",		4294967297ULL,		10},
+		{"9223372036854775807",	9223372036854775807ULL,	19},
+		{"9223372036854775808",	9223372036854775808ULL,	19},
+		{"9223372036854775809",	9223372036854775809ULL,	19},
+		{"18446744073709551614", 18446744073709551614ULL, 20},
+		{"18446744073709551615", 18446744073709551615ULL, 20},
+
+		{"00",				00ULL,		2},
+		{"01",				01ULL,		2},
+		{"0177",			0177ULL,	4},
+		{"0200",			0200ULL,	4},
+		{"0201",			0201ULL,	4},
+		{"0377",			0377ULL,	4},
+		{"0400",			0400ULL,	4},
+		{"0401",			0401ULL,	4},
+		{"077777",			077777ULL,	6},
+		{"0100000",			0100000ULL,	7},
+		{"0100001",			0100001ULL,	7},
+		{"0177777",			0177777ULL,	7},
+		{"0200000",			0200000ULL,	7},
+		{"0200001",			0200001ULL,	7},
+		{"017777777777",		017777777777ULL,	12},
+		{"020000000000",		020000000000ULL,	12},
+		{"020000000001",		020000000001ULL,	12},
+		{"037777777777",		037777777777ULL,	12},
+		{"040000000000",		040000000000ULL,	12},
+		{"040000000001",		040000000001ULL,	12},
+		{"0777777777777777777777",	0777777777777777777777ULL, 22},
+		{"01000000000000000000000",	01000000000000000000000ULL, 23},
+		{"01000000000000000000001",	01000000000000000000001ULL, 23},
+		{"01777777777777777777776",	01777777777777777777776ULL, 23},
+		{"01777777777777777777777",	01777777777777777777777ULL, 23},
+
+		{"0x0",			0x0ULL,			3},
+		{"0x1",			0x1ULL,			3},
+		{"0x7f",		0x7fULL,		4},
+		{"0x80",		0x80ULL,		4},
+		{"0x81",		0x81ULL,		4},
+		{"0xff",		0xffULL,		4},
+		{"0x100",		0x100ULL,		5},
+		{"0x101",		0x101ULL,		5},
+		{"0x7fff",		0x7fffULL,		6},
+		{"0x8000",		0x8000ULL,		6},
+		{"0x8001",		0x8001ULL,		6},
+		{"0xffff",		0xffffULL,		6},
+		{"0x10000",		0x10000ULL,		7},
+		{"0x10001",		0x10001ULL,		7},
+		{"0x7fffffff",		0x7fffffffULL,		10},
+		{"0x80000000",		0x80000000ULL,		10},
+		{"0x80000001",		0x80000001ULL,		10},
+		{"0xffffffff",		0xffffffffULL,		10},
+		{"0x100000000",		0x100000000ULL,		11},
+		{"0x100000001",		0x100000001ULL,		11},
+		{"0x7fffffffffffffff",	0x7fffffffffffffffULL,	18},
+		{"0x8000000000000000",	0x8000000000000000ULL,	18},
+		{"0x8000000000000001",	0x8000000000000001ULL,	18},
+		{"0xfffffffffffffffe",	0xfffffffffffffffeULL,	18},
+		{"0xffffffffffffffff",	0xffffffffffffffffULL,	18},
+
+		/* Now with extra non-suffix chars to test @retptr update. */
+		{"1q84",		1,			1},
+		{"02o45",		2,			2},
+		{"0xffvii",		0xff,			4},
+
+		/*
+		 * Finally one suffix then tailing chars, to test the @retptr
+		 * behavior.
+		 */
+		{"68k ",		69632,			3},
+		{"8MS",			8388608,		2},
+		{"0xaeGis",		0x2b80000000,		5},
+		{"0xaTx",		0xa0000000000,		4},
+		{"3E8",			0x3000000000000000,	2},
+	};
+	unsigned int i;
+
+	for_each_test(i, tests) {
+		const struct memparse_test_ok *t = &tests[i];
+		unsigned long long tmp;
+		char *retptr;
+		int ret;
+
+		ret = memparse_safe(t->str, MEMPARSE_TEST_SUFFIX, &tmp, &retptr);
+		if (ret != 0) {
+			WARN(1, "str '%s', expected ret 0 got %d\n", t->str, ret);
+			continue;
+		}
+		if (tmp != t->expected_value)
+			WARN(1, "str '%s' incorrect result, expected %llu got %llu",
+			     t->str, t->expected_value, tmp);
+		if (retptr != t->str + t->retptr_off)
+			WARN(1, "str '%s' incorrect endptr, expected %u got %zu",
+			     t->str, t->retptr_off, retptr - t->str);
+	}
+}
 static void __init test_kstrtoll_fail(void)
 {
 	static DEFINE_TEST_FAIL(test_ll_fail) = {
@@ -710,6 +923,10 @@  static int __init test_kstrtox_init(void)
 	test_kstrtoll_ok();
 	test_kstrtoll_fail();
 
+	test_memparse_safe_ok();
+	test_memparse_safe_fail();
+
+
 	test_kstrtou64_ok();
 	test_kstrtou64_fail();
 	test_kstrtos64_ok();