linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/1] Implement character sets for sscanf()
@ 2016-02-20  1:20 Jessica Yu
  2016-02-22  9:27 ` Andy Shevchenko
  0 siblings, 1 reply; 3+ messages in thread
From: Jessica Yu @ 2016-02-20  1:20 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Rasmus Villemoes, Andy Shevchenko, Kees Cook, linux-kernel, Jessica Yu

Hi,

This patch adds support for the '%[' conversion specifier for sscanf().
Since functions that calculate substring lengths based on accepted or
rejected characters already exist in the kernel (namely strspn() and
strcspn()), it's not much of a stretch to add some basic support for the
bracket '%[' conversion specifier for sscanf(). This is useful in cases
where we'd like to match substrings delimited by something other than
spaces. The original motivation for this patch actually came from livepatch
(https://lkml.org/lkml/2016/2/8/790), where we were trying to come up with
a clean way to parse symbol names with substrings delimited by periods and
commas.

Patch based on linux-next-20160219.

Here are some test cases:
---
sscanf_tests.c
---
#include <linux/module.h>
#include <linux/kernel.h>

#define FAIL -1
#define PASS 0

static int test1(void)
{
	int ret;
	char buf[32] = { 0 };

	ret = sscanf("this is a test\n", "%[^\n]", buf);
	pr_info("test1:\n\tret: %d\n\tbuf0: %s\n", ret, buf);
	if (ret != 1)
		return FAIL;

	return PASS;
}

static int test2(void)
{
	int ret;
	char buf[32] = { 0 };

	ret = sscanf("this is a test\n", "%10[^\n]", buf);
	pr_info("test2:\n\tret: %d\n\tbuf0: %s\n", ret, buf);
	if (ret != 1 && strlen(buf) != 10)
		return FAIL;

	return PASS;
}

static int test3(void)
{
	int ret;
	char buf[32] = { 0 };

	ret = sscanf("this is a test\n", "%[^ ]", buf);
	pr_info("test3:\n\tret: %d\n\tbuf0: %s\n", ret, buf);
	if (ret != 1)
		return FAIL;

	return PASS;
}

static int test4(void)
{
	int ret;
	char buf[3][32] = { 0 };

	ret = sscanf("this is a test\n", "%[^ ] %[^ ] %[^ ]",
		     buf[0], buf[1], buf[2]);
	pr_info("test4:\n\tret: %d\n\tbuf0: %s\n\tbuf2: %s\n\tbuf3: %s\n",
		 ret, buf[0], buf[1], buf[2]);
	if (ret != 3)
		return FAIL;

	return PASS;
}

/* semicolon delimiters */
static int test5(void)
{
	int ret;
	char buf[2][32] = { 0 };

	ret = sscanf("Hello;World;\n", "%[^;];%[^;]", buf[0], buf[1]);
	pr_info("test5:\n\tret: %d\n\tbuf0: %s\n\tbuf2: %s\n",
		 ret, buf[0], buf[1]);
	if (ret != 2)
		return FAIL;

	return PASS;
}

/* colon delimiters */
static int test6(void)
{
	int ret;
	char buf[4][32] = { 0 };

	ret = sscanf("this:is:a:test", "%[^:]:%[^:]:%[^:]:%[^:]",
		     buf[0], buf[1], buf[2], buf[3]);
	pr_info("test6:\n\tret: %d\n\tbuf0: %s\n\tbuf2: %s\n\tbuf3: %s\n\tbuf4: %s\n",
	       ret, buf[0], buf[1], buf[2], buf[3]);
	if (ret != 4)
		return FAIL;

	return PASS;

}

/* tab delimiters */
static int test7(void)
{
	int ret;
	char buf[4][32] = { 0 };

	ret = sscanf("this\tis\ta\ttest",
		     "%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]",
		     buf[0], buf[1], buf[2], buf[3]);
	pr_info("test7\n\tret: %d\n\tbuf0: %s\n\tbuf2: %s\n\tbuf3: %s\n\tbuf4: %s\n",
		 ret, buf[0], buf[1], buf[2], buf[3]);
	if (ret != 4)
		return FAIL;

	return PASS;
}

/* error condition: empty char set */
static int test8(void)
{
	int ret;
	char buf[32] = { 0 };

	ret = sscanf("this is a test", "this%[] is a test", buf);
	pr_info("test8\n\tret: %d\n\tbuf0: %s\n", ret, buf);
	if (ret != 0)
		return FAIL;

	return PASS;
}

static int test9(void)
{
	int ret;
	char buf[32] = { 0 };

	ret = sscanf("aaaccbbzabccbaa", "%6[abc]", buf);
	pr_info("test9\n\tret: %d\n\tbuf0: %s\n", ret, buf);
	if (ret != 1 && strlen(buf) != 6)
		return FAIL;

	return PASS;
}

static int test10(void)
{
	int ret;
	char buf[3][32] = { 0 };

	ret = sscanf("aaaccbbxyzzcbabb",
		     "%[abc]%[^abc]%[abc]",
		     buf[0], buf[1], buf[2]);
	pr_info("test10\n\tret: %d\n\tbuf0: %s\n\tbuf1: %s\n\tbuf2: %s\n",
		ret, buf[0], buf[1], buf[2]);
	if (ret != 3)
		return FAIL;

	return PASS;
}

/* Intended usecase for livepatch symbol name parsing */
static int test11(void)
{
	int ret;
	char *sym = ".klp.sym.vmlinux.perf_ibs_event_update.isra.1,2";
	char buf[2][32] = { 0 };
	unsigned int pos;

	ret = sscanf(sym, ".klp.sym.%[^.].%[^,],%u",
		     buf[0], buf[1], &pos);
	pr_info("test11\n\tret: %d\n\tobjname: %s\n\tsymname: %s\n\tsympos: %u\n",
		ret, buf[0], buf[1], pos);

	if (ret != 3)
		return FAIL;

	return PASS;
}

/* error condition: empty set / cannot match ] bracket */
static int test12(void)
{
	int ret;
	char buf[32] = { 0 };

	ret = sscanf("aaaa]bbbb", "%[^]]", buf);
	pr_info("test12\n\tret: %d\n\tbuf0: %s\n", ret, buf);
	if (ret != 0)
		return FAIL;

	return PASS;
}

/* no matching characters from the set */
static int test13(void)
{
	int ret;
	char buf[32] = { 0 };

	ret = sscanf("this is a test\n", "%[123]", buf);
	pr_info("test13\n\tret: %d\n\tbuf0: %s\n", ret, buf);
	if (ret != 0)
		return FAIL;

	return PASS;
}

static int test14(void)
{
	int ret;
	char buf[3][32] = { 0 };

	ret = sscanf("cbcd:091555:yzyz",
		     "%[abcde]:%[0123456789]:%[xyz]",
		     buf[0], buf[1], buf[2]);
	pr_info("test13\n\tret: %d\n\tbuf0: %s\n\tbuf1: %s\n\tbuf2: %s\n",
		ret, buf[0], buf[1], buf[2]);
	if (ret != 3)
		return FAIL;

	return PASS;
}

static int __init sscanf_tests_init(void)
{
	int ret;
	int fail = 0;

	ret = test1();
	if (ret) {
		pr_err("sscanf_tests: test1 FAILED");
		fail++;
	}

	ret = test2();
	if (ret) {
		pr_err("sscanf_tests: test2 FAILED");
		fail++;
	}

	ret = test3();
	if (ret) {
		pr_err("sscanf_tests: test3 FAILED");
		fail++;
	}

	ret = test4();
	if (ret) {
		pr_err("sscanf_tests: test4 FAILED");
		fail++;
	}

	ret = test5();
	if (ret) {
		pr_err("sscanf_tests: test5 FAILED");
		fail++;
	}

	ret = test6();
	if (ret) {
		pr_err("sscanf_tests: test6 FAILED");
		fail++;
	}

	ret = test7();
	if (ret) {
		pr_err("sscanf_tests: test7 FAILED");
		fail++;
	}

	ret = test8();
	if (ret) {
		pr_err("sscanf_tests: test8 FAILED");
		fail++;
	}

	ret = test9();
	if (ret) {
		pr_err("sscanf_tests: test9 FAILED");
		fail++;
	}

	ret = test10();
	if (ret) {
		pr_err("sscanf_tests: test10 FAILED");
		fail++;
	}

	ret = test11();
	if (ret) {
		pr_err("sscanf_tests: test11 FAILED");
		fail++;
	}

	ret = test12();
	if (ret) {
		pr_err("sscanf_tests: test12 FAILED");
		fail++;
	}

	ret = test13();
	if (ret) {
		pr_err("sscanf_tests: test13 FAILED");
		fail++;
	}

	ret = test14();
	if (ret) {
		pr_err("sscanf_tests: test14 FAILED");
		fail++;
	}

	if (!fail)
		pr_info("sscanf_tests: ALL TESTS PASSED\n");
	else
		pr_info("sscanf_tests: %d TESTS FAILED\n", fail);

	return 0;
}

static void __exit sscanf_tests_exit(void)
{
}

module_init(sscanf_tests_init);
module_exit(sscanf_tests_exit);
---

Thanks,
Jessica

Jessica Yu (1):
  sscanf: implement basic character sets

 lib/vsprintf.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

-- 
2.4.3

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 0/1] Implement character sets for sscanf()
  2016-02-20  1:20 [PATCH 0/1] Implement character sets for sscanf() Jessica Yu
@ 2016-02-22  9:27 ` Andy Shevchenko
  2016-02-22 19:39   ` Jessica Yu
  0 siblings, 1 reply; 3+ messages in thread
From: Andy Shevchenko @ 2016-02-22  9:27 UTC (permalink / raw)
  To: Jessica Yu, Andrew Morton; +Cc: Rasmus Villemoes, Kees Cook, linux-kernel

On Fri, 2016-02-19 at 20:20 -0500, Jessica Yu wrote:
> Hi,
> 
> This patch adds support for the '%[' conversion specifier for
> sscanf().
> Since functions that calculate substring lengths based on accepted or
> rejected characters already exist in the kernel (namely strspn() and
> strcspn()), it's not much of a stretch to add some basic support for
> the
> bracket '%[' conversion specifier for sscanf(). This is useful in
> cases
> where we'd like to match substrings delimited by something other than
> spaces. The original motivation for this patch actually came from
> livepatch
> (https://lkml.org/lkml/2016/2/8/790), where we were trying to come up
> with
> a clean way to parse symbol names with substrings delimited by
> periods and
> commas.
> 
> Patch based on linux-next-20160219.
> 
> Here are some test cases:

Test cases should land into lib/test_scanf.c and be submitted as a
separate patch.

Also, you have something misconfigured when you sent patches. git-send-
email usually does a perfect job.

> ---
> sscanf_tests.c
> ---

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Implement character sets for sscanf()
  2016-02-22  9:27 ` Andy Shevchenko
@ 2016-02-22 19:39   ` Jessica Yu
  0 siblings, 0 replies; 3+ messages in thread
From: Jessica Yu @ 2016-02-22 19:39 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Andrew Morton, Rasmus Villemoes, Kees Cook, linux-kernel

+++ Andy Shevchenko [22/02/16 11:27 +0200]:
>On Fri, 2016-02-19 at 20:20 -0500, Jessica Yu wrote:
>> Hi,
>>
>> This patch adds support for the '%[' conversion specifier for
>> sscanf().
>> Since functions that calculate substring lengths based on accepted or
>> rejected characters already exist in the kernel (namely strspn() and
>> strcspn()), it's not much of a stretch to add some basic support for
>> the
>> bracket '%[' conversion specifier for sscanf(). This is useful in
>> cases
>> where we'd like to match substrings delimited by something other than
>> spaces. The original motivation for this patch actually came from
>> livepatch
>> (https://lkml.org/lkml/2016/2/8/790), where we were trying to come up
>> with
>> a clean way to parse symbol names with substrings delimited by
>> periods and
>> commas.
>>
>> Patch based on linux-next-20160219.
>>
>> Here are some test cases:
>
>Test cases should land into lib/test_scanf.c and be submitted as a
>separate patch.
>
>Also, you have something misconfigured when you sent patches. git-send-
>email usually does a perfect job.

Thanks for the tip. Yeah, I had a small hiccup with git-send-email,
which is why the patchset came out like that :-\ In any case, the
attached test cases are more for the benefit of the patch reviewer,
not something I intended to be merged. For v2, I will just send the
single patch out.

Jessica

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-02-22 19:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-20  1:20 [PATCH 0/1] Implement character sets for sscanf() Jessica Yu
2016-02-22  9:27 ` Andy Shevchenko
2016-02-22 19:39   ` Jessica Yu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).