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

Eugene Loh eugene.loh at oracle.com
Tue Nov 9 23:22:25 UTC 2021


My main concern is that it seems strings of 256 (or STRSZ) chars are not 
being handled correctly.  We've discussed that there may be ambiguity in 
what "correctly" may mean in this case, but in any case the current 
substr() behavior is inconsistent with that of Solaris or legacy DTrace 
on Linux and even with other 256-char behavior on DTrace-on-BPF.  E.g., 
consider:

     BEGIN {
       x = 
"abc..........................................................................................................................................................................................................................................................xyz";
       printf("|%s|\n", x);
       printf("|%s|\n", substr(x,0));
       printf("|%s|\n", substr(x,0,255));
       printf("|%s|\n", substr(x,0,256));
       printf("|%s|\n", substr(x,0,257));
       exit(0);
     }

Note that the string is 256 chars and ends with "xyz".  Here is what I 
get with Solaris and legacy DTrace on Linux:

|abc..........................................................................................................................................................................................................................................................xyz|
|abc..........................................................................................................................................................................................................................................................xyz|
|abc..........................................................................................................................................................................................................................................................xy|
|abc..........................................................................................................................................................................................................................................................xyz|
|abc..........................................................................................................................................................................................................................................................xyz|

In contrast, here is with DTrace on BPF (using the proposed patch):

|abc..........................................................................................................................................................................................................................................................xyz|
|abc..........................................................................................................................................................................................................................................................xy|
|abc..........................................................................................................................................................................................................................................................xy|
|abc..........................................................................................................................................................................................................................................................xy|
|abc..........................................................................................................................................................................................................................................................xy|

Chopping off the final char is unique to substr() in the new implementation.

On 11/9/21 12:29 AM, Kris Van Hees wrote:
> In certain cases, substr() would store an incorrect length for the
> result string.  This problem is resolved with this patch.

In certain cases?  I thought the problem was in virtually every case.  
That is, it used STRSZ rather than len, so it would be unusual for the 
correct length to be stored.

> 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 the be found in label .Lcheck_idx (formerly
the be found
->
can be found
> .Ladjust_cnt).  The original four conditionals were overkill, and the
> case for (cnt > 0) was jumping to ,Lcnt_pos incorrectly (causing the
,Lcnt_pos
->
.Lcnt_pos
> incorrect string length value).  It now correctly jumps to .Lcopy.
> In fact, the .Lcnt_pos code was unnecessary.
>
> Copying the slice now makes use of the probe_read_str() helper rather
> than the probe_read() helper.
What's a slice?  Perhaps should one say "substring" (given the name of 
the action)?  Or, just omit "the slice" since it would be clear which 
copy is intended.

> 9 new tests are added to test various special conditions.
>
> Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> ---
>   bpf/substr.S                                  | 126 ++++++++++++------
>   .../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      |  27 ++++
>   .../funcs/substr/tst.substr-stored-len.r      |   4 +
>   19 files changed, 488 insertions(+), 42 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
>
> diff --git a/bpf/substr.S b/bpf/substr.S
> index e263274b..87ba6192 100644
> --- a/bpf/substr.S
> +++ b/bpf/substr.S
> @@ -5,88 +5,130 @@
>   
>   #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 arguents (sign-extend idx). */

arguments

>   	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).

idx+len

> +	 * If the offset is positive, we can use it as a (positive) index.

s/positive/non-negative/  (And then maybe remove the parenthetical 
remark to save some space???)

> +	 * 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.
> +	 * If it does, we will slice from idx = 0 for cnt - |idx| characters.
> +	 */

[0, len[
->
[0, len)
>   	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
> +.Lcheck_idx:
> +	/*
> +	 * Validte the idx value.  If idx is greater than the string length, we
> +	 * get the empty string.
> +	 */

Validate

> +	jsge	%r6, %r8, .Lempty	/* if (idx s>= len) goto Lempty; */
> +
> +	/* If cnt is positive (or 0), we are ready to copy the slice. */
> +	jsge	%r7, 0, .Lcopy		/* if (cnt s>= 0) goto Lcopy; */
> +
> +	/*
> +	 * 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
> -	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 */
> +	sub	%r0, %r6
> +	add	%r7, %r0		/* cnt += len - idx */
> +	jsle	%r7, 0, .Lempty		/* if (cnt s<= 0) goto Lempty; */
>   
>   .Lcopy:
> -	ldxdw	%r8, [%fp+-8]
> -	add	%r8, DT_STRLEN_BYTES
> -	add	%r8, %r6		/* %r8 = src + DT_STRLEN_BYTES + idx */
> +	/*
> +	 * 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 + 1) is capped at STRSZ.
> +	 */
> +	mov	%r1, %r9
> +	add	%r1, DT_STRLEN_BYTES
> +	mov	%r2, %r7
> +	add	%r2, 1
> +	lddw	%r0, STRSZ
> +	jle	%r2, %r0, .Lcnt_ok	/* if (cnt <= STRSZ) goto Lcnt_ok; */
> +	mov	%r2, %r0		/* cnt = STRSZ */

Strictly speaking, the last two comments are wrong.  cnt is not capped 
at STRSZ;  cnt+1 is (as you indicated in the preceding block comment).

> +.Lcnt_ok:
> +	ldxdw	%r3, [%fp+-8]
> +	add	%r3, DT_STRLEN_BYTES
> +	add	%r3, %r6
> +	call	BPF_FUNC_probe_read_str	/*
> +					 * probe_read_str(&dst[DT_STRLEN_BYTES],
> +					 *	cnt + 1,
> +					 *	&src[DT_STRLEN_BYTES + idx]);
> +					 */
>   
> +	/* Store the result string length at dst. */
>   	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 */
>   
> -	mov	%r1, %r9
> -	mov	%r2, %r7
> -	mov	%r3, %r8
> -	call	BPF_FUNC_probe_read
> -
> -	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..828f46e7
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-stored-len.d
> @@ -0,0 +1,27 @@
> +/*
> + * 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))));
> +	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..1141e529
> --- /dev/null
> +++ b/test/unittest/funcs/substr/tst.substr-stored-len.r
> @@ -0,0 +1,4 @@
> +
> +             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.......
> +



More information about the DTrace-devel mailing list