[DTrace-devel] [PATCH v2] Fix length stored by substr() and optimize the implementation

Eugene Loh eugene.loh at oracle.com
Wed Nov 10 05:48:20 UTC 2021


Reviewed-by: Eugene Loh <eugene.loh at oracle.com>
with a few comments below.

On 11/9/21 8:43 PM, Kris Van Hees wrote:
> In certain cases, substr() would store an incorrect length for the
> result string.  This problem is resolved with this patch.
>
> Better comments have been added as well to make the code easier to
> follow.
>
> The code handling the case where (idx < 0) failed to recognize that
> when the adjusted idx value was more negative than the value of cnt,
> the result would always be the empty string.  This has been corrected
> which improved code performance as well.
>
> Another important change can be found in label .Lcheck_idx (formerly
> .Ladjust_cnt).  The original four conditionals were overkill, and the
> case for (cnt > 0) was jumping to .Lcnt_pos incorrectly (causing the
> incorrect string length value).  It now correctly jumps to .Lcopy.
> In fact, the .Lcnt_pos code was unnecessary.
>
> Copying the substring now makes use of the probe_read_str() helper
> rather than the probe_read() helper.
>
> 10 new tests are added to test various special conditions.
>
> Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> ---
>   bpf/substr.S                                  | 132 ++++++++++++------
>   .../tst.substr-multi-const-idx-neg-no-cnt.d   |  30 ++++
>   .../tst.substr-multi-const-idx-neg-no-cnt.r   |  11 ++
>   ...ubstr-multi-const-idx-neg-too-far-no-cnt.d |  30 ++++
>   ...ubstr-multi-const-idx-neg-too-far-no-cnt.r |  11 ++
>   .../tst.substr-multi-const-idx-neg-too-far.d  |  30 ++++
>   .../tst.substr-multi-const-idx-neg-too-far.r  |  11 ++
>   .../tst.substr-multi-const-idx-pos-no-cnt.d   |  31 ++++
>   .../tst.substr-multi-const-idx-pos-no-cnt.r   |  12 ++
>   .../tst.substr-multi-var-idx-neg-no-cnt.d     |  40 ++++++
>   .../tst.substr-multi-var-idx-neg-no-cnt.r     |  11 ++
>   ....substr-multi-var-idx-neg-too-far-no-cnt.d |  40 ++++++
>   ....substr-multi-var-idx-neg-too-far-no-cnt.r |  11 ++
>   .../tst.substr-multi-var-idx-neg-too-far.d    |  40 ++++++
>   .../tst.substr-multi-var-idx-neg-too-far.r    |  11 ++
>   .../tst.substr-multi-var-idx-pos-no-cnt.d     |  42 ++++++
>   .../tst.substr-multi-var-idx-pos-no-cnt.r     |  12 ++
>   .../funcs/substr/tst.substr-stored-len.d      |  29 ++++
>   .../funcs/substr/tst.substr-stored-len.r      |  10 ++
>   .../funcs/substr/tst.substr-strsize.d         |  34 +++++
>   .../funcs/substr/tst.substr-strsize.r         |  16 +++
>   21 files changed, 550 insertions(+), 44 deletions(-)
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-no-cnt.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-no-cnt.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far-no-cnt.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far-no-cnt.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-const-idx-pos-no-cnt.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-const-idx-pos-no-cnt.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-no-cnt.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-no-cnt.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far-no-cnt.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far-no-cnt.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-var-idx-pos-no-cnt.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-multi-var-idx-pos-no-cnt.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-stored-len.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-stored-len.r
>   create mode 100644 test/unittest/funcs/substr/tst.substr-strsize.d
>   create mode 100644 test/unittest/funcs/substr/tst.substr-strsize.r
>
> diff --git a/bpf/substr.S b/bpf/substr.S
> index e263274b..514dedba 100644
> --- a/bpf/substr.S
> +++ b/bpf/substr.S
> @@ -5,88 +5,132 @@
>   
>   #define DT_STRLEN_BYTES		2
>   
> -#define BPF_FUNC_probe_read	4
> +#define BPF_FUNC_probe_read_str	45
>   
>   /*
>    * void dt_substr(char *dst, const char *src, int32_t idx, int32_t cnt,
>    *		  uint64_t argc)
> + *
> + * %r1 = dst, %r2 = src, %r3 = idx, %r4 = cnt, %r5 = argc
>    */
>   	.text
>   	.align	4
>   	.global	dt_substr
>   	.type	dt_substr, @function
>   dt_substr :
> +	/* Store the arguments (sign-extend idx). */
>   	mov	%r9, %r1		/* %r9 = dst */
>   	stxdw	[%fp+-8], %r2		/* Spill src */
>   	lsh	%r3, 32			/* Sign-extend idx */
>   	arsh	%r3, 32
>   	mov	%r6, %r3		/* %r6 = idx */
>   
> -	lddw	%r8, STRSZ		/* %r8 = STRSZ (temporary) */
> -	jgt	%r5, 2, .Lhave_cnt
> -	mov	%r4, %r8		/* cnt = STRSZ */
> +	/* Initialize the string length with its maximum value.  */
> +	lddw	%r8, STRSZ		/* %r8 = len = STRSZ */
> +
> +	/*
> +	 * If we do not have a cnt, use the maximum value.
> +	 * Otherwise, sign-extend cnt.
> +	 */
> +	jgt	%r5, 2, .Lhave_cnt	/* if (argc > 2) goto Lhave_cnt; */
> +	mov	%r7, %r8		/* cnt = STRSZ */
> +	ja	.Lcnt_set
>   .Lhave_cnt:
>   	lsh	%r4, 32			/* Sign-extend cnt */
>   	arsh	%r4, 32
>   	mov	%r7, %r4		/* %r7 = cnt */
> +.Lcnt_set:
>   
>   	/*
> -	 * Get the source string length and validate it.  If the length is 0,
> -	 * the result is the empty string.  If the length is greater than the
> -	 * maximum string length (STRSZ), cap it at that value.
> +	 * Get the source string length and validate it.
> +	 * If the length is 0, the result is the empty string.
> +	 * If the length is less than the maximum string length (STRSZ), use
> +	 * the length we got.  (The length is initialized in %r8 as the default
> +	 * string length.)
>   	 */
>   	ldxdw	%r1, [%fp+-8]
>   	call	dt_strlen		/* len = dt_strlen(src) */
> -	jeq	%r0, 0, .Lempty
> -	mov	%r1, %r8		/* %r1 = STRSZ */
> -	jle	%r0, %r8, .Llen_ok
> -	mov	%r0, %r8		/* len = STRSZ */
> -.Llen_ok:
> +	jeq	%r0, 0, .Lempty		/* if (len == 0) goto Lempty; */
> +	jge	%r0, %r8, .Llen_set	/* if (len >= STRSZ) goto Llen_set; */
>   	mov	%r8, %r0		/* %r8 = len */
> +.Llen_set:
>   
> -	jsge	%r6, 0, .Ladjust_cnt
> +	jsge	%r6, 0, .Lcheck_idx	/* if (idx s>= 0) goto Lcheck_idx; */
>   
> +	/*
> +	 * If idx is negative it is a count from the end of the string.  Turn
> +	 * it into the equivalent character offset (len + idx).
> +	 * If the offset is positive, we can use it as the index.

Thanks for the wording change, but again the point is not "if the offset 
is positive."  The point is "if the offset is non-negative." We're 
perfectly happy with a zero offset.

> +	 * If not, we need to determine whether idx + cnt falls within the
> +	 * [0, len[ interval.  If it does not, the result is the empty string.

Okay, I've found some online descriptions of the [0,len[ notation, but 
[0,len) seems to be considerably more common.  I suggest the latter 
notation, but your call.

> +	 * If it does, we will slice from idx = 0 for cnt + idx characters.

At this point, this is the only occurrence of "slice."  Also, cnt+idx is 
a little ambiguous since idx=0 was just redefined. Anyhow, this text is 
in a comment and I didn't say anything about it in the other review 
so... no big deal.  But you can consider the wording:

"If it does, we form a substring of cnt+idx chars, then resetting idx=0."

No idea if that's better.

> +	 */
>   	add	%r6, %r8		/* idx += len */
> -	jsge	%r6, 0, .Ladjust_cnt
> +	jsge	%r6, 0, .Lcheck_idx	/* if (idx s>= 0) goto Lcheck_idx; */
>   	mov	%r0, 0
> -	sub32	%r0, %r6		/* neg messes up the verifier */
> -	jsle	%r7, %r0, .Ladjust_cnt
> -	add32	%r7, %r6		/* cnt += idx */
> +	sub	%r0, %r6		/* neg messes up the verifier */
> +	jsle	%r7, %r0, .Lempty	/* if (cnt s<= -idx) goto Lempty; */
> +	add	%r7, %r6		/* cnt += idx */
>   	mov	%r6, 0			/* idx = 0 */
>   
> -.Ladjust_cnt:
> -	jsge	%r6, %r1, .Lempty
> -	jsge	%r6, %r8, .Lempty
> -	jslt	%r6, 0, .Lempty
> -	jsge	%r7, 0, .Lcnt_pos
> -	mov	%r0, %r8
> -	sub32	%r0, %r6
> -	add32	%r7, %r0		/* cnt += len - idx */
> -	lsh	%r7, 32
> -	arsh	%r7, 32
> -	jsle	%r7, 0, .Lempty
> -.Lcnt_pos:
> -	sub	%r1, %r6
> -	jsge	%r1, %r7, .Lcopy
> -	mov	%r7, %r1		/* cnt = STRSZ - idx */
> +.Lcheck_idx:
> +	/*
> +	 * Validate the idx value.  If idx is greater than the string length,
> +	 * we get the empty string.
> +	 */
> +	jsge	%r6, %r8, .Lempty	/* if (idx s>= len) goto Lempty; */
>   
> -.Lcopy:
> -	ldxdw	%r8, [%fp+-8]
> -	add	%r8, DT_STRLEN_BYTES
> -	add	%r8, %r6		/* %r8 = src + DT_STRLEN_BYTES + idx */
> +	/* If cnt is positive (or 0), we are ready to copy the slice. */
> +	jsge	%r7, 0, .Lcopy		/* if (cnt s>= 0) goto Lcopy; */
>   
> -	mov	%r1, %r7
> -	mov	%r2, %r9
> -	call	dt_strlen_store		/* dt_strlen_store(cnt, dst) */
> -	add	%r9, DT_STRLEN_BYTES	/* %r9 = dst + DT_STRLEN_BYTES */
> +	/*
> +	 * If cnt is negative it is a count from the last character in string.
> +	 * Use the equivalent character offset to calculate the true (positive)
> +	 * cnt:
> +	 *	start = idx
> +	 *	end = (len - 1) - (-cnt)
> +	 *	new_cnt = end - start + 1
> +	 *		= (len - 1) - (-cnt) - idx + 1
> +	 *		= len - 1 + cnt - idx + 1
> +	 *		= len + cnt - idx
> +	 * which is equivalent with:
> +	 *	cnt += len - idx
> +	 */
> +	mov	%r0, %r8
> +	sub	%r0, %r6
> +	add	%r7, %r0		/* cnt += len - idx */
> +	jsle	%r7, 0, .Lempty		/* if (cnt s<= 0) goto Lempty; */
>   
> +.Lcopy:
> +	/*
> +	 * Use the probe_read_str() BPF helper to copy (cnt + 1) bytes from
> +	 * &src[DT_STRLEN_BYTES + idx] to &dst[DT_STRLEN_BYTES].  We ensure
> +	 * that cnt is capped at STRSZ.
> +	 */
>   	mov	%r1, %r9
> +	add	%r1, DT_STRLEN_BYTES
>   	mov	%r2, %r7
> -	mov	%r3, %r8
> -	call	BPF_FUNC_probe_read
> +	lddw	%r0, STRSZ
> +	jle	%r2, %r0, .Lcnt_ok	/* if (cnt <= STRSZ) goto Lcnt_ok; */
> +	mov	%r2, %r0		/* cnt = STRSZ */
> +.Lcnt_ok:
> +	add	%r2, 1
> +	ldxdw	%r3, [%fp+-8]
> +	add	%r3, DT_STRLEN_BYTES
> +	add	%r3, %r6
> +	call	BPF_FUNC_probe_read_str	/*
> +					 * rc = probe_read_str(
> +					 *	&dst[DT_STRLEN_BYTES],
> +					 *	cnt + 1,
> +					 *	&src[DT_STRLEN_BYTES + idx]);
> +					 */
> +
> +	/* Store the result string length (rc - 1) at dst. */
> +	mov	%r1, %r0
> +	sub	%r1, 1

Ah.  Nice catch.  (Length should be rc-1 rather than cnt.)  But this 
raises the question why a test hadn't caught this problem earlier. Maybe 
a test case can be added for this?  (That is, the cnt takes you beyond 
the length of the string.)  E.g., in your new test 
test/unittest/funcs/substr/tst.substr-strsize.d , you have stuff like

         trace(substr(x, 0));
         trace(substr(x, 0, 12));
         trace(substr(x, 0, 13));
         trace(substr(x, 0, 14));

but what if idx were higher?  Say,

         trace(substr(x, 8, 14));
         trace(substr(x, 8));

(I'm proposing test cases like this.  I don't know if you want them in 
this particular test.)  They would have failed with output like

              0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f 
0123456789abcdef
          0: 00 0d 39 30 31 32 33 00 37 38 39 30 31 32 33 00 
..90123.7890123.

That is, the length is some cnt=0x0d and there is a lot of garbage after 
the terminating NULL.  But you have now fixed this bug, giving output like

              0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f 
0123456789abcdef
          0: 00 05 39 30 31 32 33 00 00 00 00 00 00 00 00 00 
..90123.........

The length is a correct rc-1=0x05 and there is no trailing garbage. The 
new behavior is correct and it'd be nice to have a test to demonstrate it.


> +	mov	%r2, %r9
> +	call	dt_strlen_store		/* dt_strlen_store(rc - 1, dst) */
>   
> -	add	%r9, %r7
> -	stb	[%r9+0], 0
>   	exit
>   
>   .Lempty:
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-no-cnt.d b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-no-cnt.d
> new file mode 100644
> index 00000000..39ebf280
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-no-cnt.d
> @@ -0,0 +1,30 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine supports negative index values passed as
> + *	      constants.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +
> +BEGIN
> +{
> +	printf("\n% 3d %s", -10, substr("abcdefghijklmnop", -10));
> +	printf("\n% 3d %s",  -9, substr("abcdefghijklmnop", -9));
> +	printf("\n% 3d %s",  -8, substr("abcdefghijklmnop", -8));
> +	printf("\n% 3d %s",  -7, substr("abcdefghijklmnop", -7));
> +	printf("\n% 3d %s",  -6, substr("abcdefghijklmnop", -6));
> +	printf("\n% 3d %s",  -5, substr("abcdefghijklmnop", -5));
> +	printf("\n% 3d %s",  -4, substr("abcdefghijklmnop", -4));
> +	printf("\n% 3d %s",  -3, substr("abcdefghijklmnop", -3));
> +	printf("\n% 3d %s",  -2, substr("abcdefghijklmnop", -2));
> +	printf("\n% 3d %s",  -1, substr("abcdefghijklmnop", -1));
> +	exit(0);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-no-cnt.r b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-no-cnt.r
> new file mode 100644
> index 00000000..468f586b
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-no-cnt.r
> @@ -0,0 +1,11 @@
> +
> +-10 ghijklmnop
> + -9 hijklmnop
> + -8 ijklmnop
> + -7 jklmnop
> + -6 klmnop
> + -5 lmnop
> + -4 mnop
> + -3 nop
> + -2 op
> + -1 p
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far-no-cnt.d b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far-no-cnt.d
> new file mode 100644
> index 00000000..95af3f37
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far-no-cnt.d
> @@ -0,0 +1,30 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine supports negative index values passed as
> + *	      constants, with some values out of range.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +
> +BEGIN
> +{
> +	printf("\n% 3d %s", -10, substr("abcde", -10));
> +	printf("\n% 3d %s",  -9, substr("abcde", -9));
> +	printf("\n% 3d %s",  -8, substr("abcde", -8));
> +	printf("\n% 3d %s",  -7, substr("abcde", -7));
> +	printf("\n% 3d %s",  -6, substr("abcde", -6));
> +	printf("\n% 3d %s",  -5, substr("abcde", -5));
> +	printf("\n% 3d %s",  -4, substr("abcde", -4));
> +	printf("\n% 3d %s",  -3, substr("abcde", -3));
> +	printf("\n% 3d %s",  -2, substr("abcde", -2));
> +	printf("\n% 3d %s",  -1, substr("abcde", -1));
> +	exit(0);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far-no-cnt.r b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far-no-cnt.r
> new file mode 100644
> index 00000000..4c911183
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far-no-cnt.r
> @@ -0,0 +1,11 @@
> +
> +-10 abcde
> + -9 abcde
> + -8 abcde
> + -7 abcde
> + -6 abcde
> + -5 abcde
> + -4 bcde
> + -3 cde
> + -2 de
> + -1 e
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far.d b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far.d
> new file mode 100644
> index 00000000..05ea8f01
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far.d
> @@ -0,0 +1,30 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine supports negative index values passed as
> + *	      constants, with some values out of range.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +
> +BEGIN
> +{
> +	printf("\n% 3d % 3d %s", -10, 3, substr("abcde", -10, 3));
> +	printf("\n% 3d % 3d %s",  -9, 3, substr("abcde", -9, 3));
> +	printf("\n% 3d % 3d %s",  -8, 3, substr("abcde", -8, 3));
> +	printf("\n% 3d % 3d %s",  -7, 3, substr("abcde", -7, 3));
> +	printf("\n% 3d % 3d %s",  -6, 3, substr("abcde", -6, 3));
> +	printf("\n% 3d % 3d %s",  -5, 3, substr("abcde", -5, 3));
> +	printf("\n% 3d % 3d %s",  -4, 3, substr("abcde", -4, 3));
> +	printf("\n% 3d % 3d %s",  -3, 3, substr("abcde", -3, 3));
> +	printf("\n% 3d % 3d %s",  -2, 3, substr("abcde", -2, 3));
> +	printf("\n% 3d % 3d %s",  -1, 3, substr("abcde", -1, 3));
> +	exit(0);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far.r b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far.r
> new file mode 100644
> index 00000000..e989b7c3
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-const-idx-neg-too-far.r
> @@ -0,0 +1,11 @@
> +
> +-10   3
> + -9   3
> + -8   3
> + -7   3 a
> + -6   3 ab
> + -5   3 abc
> + -4   3 bcd
> + -3   3 cde
> + -2   3 de
> + -1   3 e
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-const-idx-pos-no-cnt.d b/test/unittest/funcs/substr/tst.substr-multi-const-idx-pos-no-cnt.d
> new file mode 100644
> index 00000000..1ef6aaf3
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-const-idx-pos-no-cnt.d
> @@ -0,0 +1,31 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine supports positive index values passed as
> + *	      constants.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +
> +BEGIN
> +{
> +	printf("\n% 3d %s",   0, substr("abcdefghijklmnop", 0));
> +	printf("\n% 3d %s",   1, substr("abcdefghijklmnop", 1));
> +	printf("\n% 3d %s",   2, substr("abcdefghijklmnop", 2));
> +	printf("\n% 3d %s",   3, substr("abcdefghijklmnop", 3));
> +	printf("\n% 3d %s",   4, substr("abcdefghijklmnop", 4));
> +	printf("\n% 3d %s",   5, substr("abcdefghijklmnop", 5));
> +	printf("\n% 3d %s",   6, substr("abcdefghijklmnop", 6));
> +	printf("\n% 3d %s",   7, substr("abcdefghijklmnop", 7));
> +	printf("\n% 3d %s",   8, substr("abcdefghijklmnop", 8));
> +	printf("\n% 3d %s",   9, substr("abcdefghijklmnop", 9));
> +	printf("\n% 3d %s",  10, substr("abcdefghijklmnop", 10));
> +	exit(0);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-const-idx-pos-no-cnt.r b/test/unittest/funcs/substr/tst.substr-multi-const-idx-pos-no-cnt.r
> new file mode 100644
> index 00000000..78f8b580
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-const-idx-pos-no-cnt.r
> @@ -0,0 +1,12 @@
> +
> +  0 abcdefghijklmnop
> +  1 bcdefghijklmnop
> +  2 cdefghijklmnop
> +  3 defghijklmnop
> +  4 efghijklmnop
> +  5 fghijklmnop
> +  6 ghijklmnop
> +  7 hijklmnop
> +  8 ijklmnop
> +  9 jklmnop
> + 10 klmnop
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-no-cnt.d b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-no-cnt.d
> new file mode 100644
> index 00000000..4b496e92
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-no-cnt.d
> @@ -0,0 +1,40 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine supports negative index values passed by
> + *	      variable.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +
> +BEGIN
> +{
> +	idx = -10;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -9;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -8;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -7;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -6;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -5;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -4;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -3;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -2;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = -1;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	exit(0);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-no-cnt.r b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-no-cnt.r
> new file mode 100644
> index 00000000..468f586b
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-no-cnt.r
> @@ -0,0 +1,11 @@
> +
> +-10 ghijklmnop
> + -9 hijklmnop
> + -8 ijklmnop
> + -7 jklmnop
> + -6 klmnop
> + -5 lmnop
> + -4 mnop
> + -3 nop
> + -2 op
> + -1 p
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far-no-cnt.d b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far-no-cnt.d
> new file mode 100644
> index 00000000..aa9bc5c7
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far-no-cnt.d
> @@ -0,0 +1,40 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine supports negative index values passed by
> + *	      variable, with some values out of range.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +
> +BEGIN
> +{
> +	idx = -10;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -9;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -8;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -7;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -6;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -5;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -4;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -3;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -2;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	idx = -1;
> +	printf("\n% 3d %s", idx, substr("abcde", idx));
> +	exit(0);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far-no-cnt.r b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far-no-cnt.r
> new file mode 100644
> index 00000000..4c911183
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far-no-cnt.r
> @@ -0,0 +1,11 @@
> +
> +-10 abcde
> + -9 abcde
> + -8 abcde
> + -7 abcde
> + -6 abcde
> + -5 abcde
> + -4 bcde
> + -3 cde
> + -2 de
> + -1 e
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far.d b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far.d
> new file mode 100644
> index 00000000..8f2a10f1
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far.d
> @@ -0,0 +1,40 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine supports negative index values passed by
> + *	      variable, with some values out of range.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +
> +BEGIN
> +{
> +	idx = -10;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -9;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -8;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -7;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -6;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -5;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -4;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -3;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -2;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	idx = -1;
> +	printf("\n% 3d % 3d %s", idx, 3, substr("abcde", idx, 3));
> +	exit(0);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far.r b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far.r
> new file mode 100644
> index 00000000..e989b7c3
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-var-idx-neg-too-far.r
> @@ -0,0 +1,11 @@
> +
> +-10   3
> + -9   3
> + -8   3
> + -7   3 a
> + -6   3 ab
> + -5   3 abc
> + -4   3 bcd
> + -3   3 cde
> + -2   3 de
> + -1   3 e
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-var-idx-pos-no-cnt.d b/test/unittest/funcs/substr/tst.substr-multi-var-idx-pos-no-cnt.d
> new file mode 100644
> index 00000000..0de17717
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-var-idx-pos-no-cnt.d
> @@ -0,0 +1,42 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine supports positive index values passed by
> + *	      variable.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +
> +BEGIN
> +{
> +	idx = 0;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 1;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 2;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 3;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 4;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 5;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 6;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 7;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 8;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 9;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	idx = 10;
> +	printf("\n% 3d %s", idx, substr("abcdefghijklmnop", idx));
> +	exit(0);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-multi-var-idx-pos-no-cnt.r b/test/unittest/funcs/substr/tst.substr-multi-var-idx-pos-no-cnt.r
> new file mode 100644
> index 00000000..78f8b580
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-multi-var-idx-pos-no-cnt.r
> @@ -0,0 +1,12 @@
> +
> +  0 abcdefghijklmnop
> +  1 bcdefghijklmnop
> +  2 cdefghijklmnop
> +  3 defghijklmnop
> +  4 efghijklmnop
> +  5 fghijklmnop
> +  6 ghijklmnop
> +  7 hijklmnop
> +  8 ijklmnop
> +  9 jklmnop
> + 10 klmnop
> diff --git a/test/unittest/funcs/substr/tst.substr-stored-len.d b/test/unittest/funcs/substr/tst.substr-stored-len.d
> new file mode 100644
> index 00000000..97d2b0f6
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-stored-len.d
> @@ -0,0 +1,29 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine stores the correct string length prefix.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +#pragma D option rawbytes
> +#pragma D option strsize=13
> +
> +BEGIN
> +{
> +	trace(strjoin((x = substr("abcdef", 2)), (y = substr("ABCDEF", 3))));
> +	trace(x);
> +	trace(y);
> +	exit(0);
> +}
> +
> +ERROR
> +{
> +	exit(1);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-stored-len.r b/test/unittest/funcs/substr/tst.substr-stored-len.r
> new file mode 100644
> index 00000000..c29f54ba
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-stored-len.r
> @@ -0,0 +1,10 @@
> +
> +             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
> +         0: 00 07 63 64 65 66 44 45 46 00 00 00 00 00 00 00  ..cdefDEF.......
> +
> +             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
> +         0: 00 04 63 64 65 66 00 00 00 00 00 00 00 00 00 00  ..cdef..........
> +
> +             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
> +         0: 00 03 44 45 46 00 00 00 00 00 00 00 00 00 00 00  ..DEF...........
> +
> diff --git a/test/unittest/funcs/substr/tst.substr-strsize.d b/test/unittest/funcs/substr/tst.substr-strsize.d
> new file mode 100644
> index 00000000..b4d0cc63
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-strsize.d
> @@ -0,0 +1,34 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: The substr() subroutine stores the correct substring when the
> + *	      count is not specified, or greater or equal to the maximum string
> + *	      size.
> + *
> + * SECTION: Actions and Subroutines/substr()
> + */
> +
> +#pragma D option quiet
> +#pragma D option rawbytes
> +#pragma D option strsize=13
> +
> +BEGIN
> +{
> +	x = "1234567890123";
> +	trace(x);
> +	trace(substr(x, 0));
> +	trace(substr(x, 0, 12));
> +	trace(substr(x, 0, 13));
> +	trace(substr(x, 0, 14));
> +	exit(0);
> +}
> +
> +ERROR
> +{
> +	exit(1);
> +}
> diff --git a/test/unittest/funcs/substr/tst.substr-strsize.r b/test/unittest/funcs/substr/tst.substr-strsize.r
> new file mode 100644
> index 00000000..d96d12f6
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-strsize.r
> @@ -0,0 +1,16 @@
> +
> +             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
> +         0: 00 0d 31 32 33 34 35 36 37 38 39 30 31 32 33 00  ..1234567890123.
> +
> +             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
> +         0: 00 0d 31 32 33 34 35 36 37 38 39 30 31 32 33 00  ..1234567890123.
> +
> +             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
> +         0: 00 0c 31 32 33 34 35 36 37 38 39 30 31 32 00 00  ..123456789012..
> +
> +             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
> +         0: 00 0d 31 32 33 34 35 36 37 38 39 30 31 32 33 00  ..1234567890123.
> +
> +             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
> +         0: 00 0d 31 32 33 34 35 36 37 38 39 30 31 32 33 00  ..1234567890123.
> +



More information about the DTrace-devel mailing list