[DTrace-devel] [PATCH v2 3/3] String args to dt_strcmp() need to be copied if not DPTR

Kris Van Hees kris.van.hees at oracle.com
Sat Oct 8 05:07:21 UTC 2022


On Sat, Oct 08, 2022 at 12:31:37AM -0400, Eugene Loh via DTrace-devel wrote:
> Actually, wait a minute.  Does this patch pass testing?  The new tests check
> against BPF verifier failures, but are the comparisons being performed
> correctly?  Do older tests like operators/tst.str_comparison*.d pass? 
> (str_comparison-basic.d has been failing for a while due to NULL-pointer
> support, but that's a different issue.)  Comments below:
> 
> On 10/6/22 20:48, Kris Van Hees via DTrace-devel wrote:
> > diff --git a/bpf/strcmp.S b/bpf/strcmp.S
> > @@ -86,8 +87,14 @@ dt_strcmp_not :
> >    *     // based on this location, judge if the strings are >, <, or ==
> >    *     if (r0 > r6) goto Lsame;
> >    *     if (r0 > r7) goto Lsame;
> > - *     if (s[r0] > t[r0]) return +1;
> > - *     if (s[r0] < t[r0]) return +1;
> > +
> > + *     s += r0;
> > + *     t += r0;
> > +
> > + *     if (flags & 1) { } else { bpf_probe_read(tmp1, 1, s); s = tmp1; }
> > + *     if (flags & 2) { } else { bpf_probe_read(tmp2, 1, t); t = tmp2; }
> > + *     if (s[0] > t[0]) return +1;
> > + *     if (s[0] < t[0]) return +1;
> >    *
> >    *     // if all chars are the same, break tie on string length
> >    * Lsame:
> > @@ -158,20 +166,37 @@ dt_strcmp :
> >   	jgt	%r0, %r6, .Lsame	/* if (r0 > r6) goto Lsame */
> >   	jgt	%r0, %r8, .Lsame	/* if (r0 > r8) goto Lsame */
> 
> Hmm.  The above two lines predate this patch, but presumably the second line
> is wrong.  Earlier comments claim we should be checking r0>r7, not r0>r8.

Pre-existing but obviously wrong so fixing it.

> > -	ldxdw	%r4, [%fp+-8]
> > -	add	%r4, %r0
> > -	ldxb	%r4, [%r4+0]		/* s[r0] */
> > -	and	%r4, 0xff
> > +	ldxdw	%r6, [%fp+-8]
> > +	add	%r6, %r8		/* s += r0 */
> > +	ldxdw	%r7, [%fp+-16]
> > +	add	%r7, %r8		/* t += r0 */
> 
> The code is doing +=%r8 but the comments claim +=r0.  I think the comments
> are right.  The code is wrong.  Presumably the problem is the v1 patch
> stashed r0 in r8, but that is no longer the case in the v2 patch.

Yes, I typo'd that.  Fixed.  Thanks for catching that.

Doing too many things at once, I did run the tests but sadly did that without
first actually recompiling the code (so it ran with older code).  Bah.

> By the way, this patch's fancy handling of t (identification of !DPTR via
> flags and special code to handle that case) is unnecessary.  We already
> copied t into tmp2 anyhow, and there it still sits.  So, there is no need
> for this patch's new code in the t case.  Instead of loading t (%fp+-16)
> just load tmp2 (%fp+-32). Simple fix.

How so?  Prior to the jgt branches you do:

	r0 = bpf_probe_read_str(tmp2, r8, tmp1);

which overwrites tmp2 which is therefore no longer t.

> > +	jset	%r9, 1, .Ls_is_dptr
> > +	ldxdw	%r1, [%fp+-24]
> > +	mov	%r2, 1
> > +	mov	%r3, %r6
> > +	mov	%r6, %r1		/* s = tmp1 (after the helper call) */
> > +	call	BPF_FUNC_probe_read	/* bpf_probe_read(tmp1, r8, s) */
> > +.Ls_is_dptr:
> > +
> > +	jset	%r9, 2, .Lt_is_dptr
> > +	ldxdw	%r1, [%fp+-32]
> > +	mov	%r2, 1
> > +	mov	%r3, %r7
> > +	mov	%r7, %r1		/* t = tmp2 (after the helper call) */
> > +	call	BPF_FUNC_probe_read	/* bpf_probe_read(tmp2, r8, t) */
> > +.Lt_is_dptr:
> > +
> > +	ldxb	%r6, [%r6+0]		/* s[0] */
> > +	and	%r6, 0xff
> > -	ldxdw	%r5, [%fp+-16]
> > -	add	%r5, %r0
> > -	ldxb	%r5, [%r5+0]		/* t[r0] */
> > -	and	%r5, 0xff
> > +	ldxb	%r7, [%r7+0]		/* t[0] */
> > +	and	%r7, 0xff
> > -	jle	%r4, %r5, 2		/* if (s[r0] > t[r0]) return +1 */
> > +	jle	%r6, %r7, 2		/* if (s[0] > t[0]) return +1 */
> >   	mov	%r0, 1
> >   	exit
> > -	jge	%r4, %r5, 2		/* if (s[r0] < t[r0]) return +1 */
> > +	jge	%r6, %r7, 2		/* if (s[0] < t[0]) return +1 */
> >   	mov	%r0, -1
> >   	exit
> 
> This is also a little weird -- in part due to pre-existing oddities and now
> even more peculiar due to the patch.  If that last branch (jge) jumps, we
> end up at .Lsame.  (That code doesn't show up here since the patch doesn't
> change it.)  In .Lsame, we compare %r6 and %r7, but this patch has just
> overwritten them.  So that suggests this patch is wrong.

See, this is why I prefer branches to labels rather than immediate values in
the source assembly code.  Labels are so much easier to follow.

> But, the overwriting might not matter.  (Presumably, r0 is the first byte
> that does not match.  So one we test s[r0]>t[r0] and fall through, there is
> no further need for testing.  We presumably know s[r0]!=t[r0].  So the
> pre-existing code could just have returned +1 at this point, without further
> branching.)

Well the comments are wrong in the pre-existing code also because it states
that s[r0] < t[r0] *and* s[r0] > t[r0] both return +1 which is of course wrong
(and the code does it right).

So, after the if (s[0] > t[0]) return +1 we can just do a return -1, because
we indeed know that s[0] != t[0] at that point.  And therefore there will not
be a fallthrough case, and the .Lsame comparison of r6 and r7 is fine.

v3 on the way with these changes.

> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel



More information about the DTrace-devel mailing list