Linux DTrace development list
 help / color / mirror / Atom feed
From: Kris Van Hees <kris.van.hees@oracle.com>
To: dtrace@lists.linux.dev, dtrace-devel@oss.oracle.com
Subject: [PATCH] parser: validate scoped external names
Date: Fri, 12 Jun 2026 16:17:28 +0000	[thread overview]
Message-ID: <223110216617c37c5d24d454d122ff8d@oracle.com> (raw)

Centralize parsing of D scoping markers used by external type and symbol references.  The helper now returns the resolved scope and identifier pieces, supports kernel and userspace markers for both type and symbol lookup, and rejects empty operands, runs longer than two backticks, and repeated scoping markers as D_SYNTAX instead of falling through to lookup failures.

Recognize dotted scoped identifiers as a single lexer token so module names like foo.bar resolve as one external symbol reference.

Add lexer and type regression tests for malformed scoped identifiers, dotted scopes, empty scope operands, scope-kind mismatches, and scoping operators in declarations.  Update the sizeof unknown-symbol test to use a non-empty symbol name.

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
---
 libdtrace/dt_decl.c                           |   6 +-
 libdtrace/dt_lex.l                            |   5 +
 libdtrace/dt_parser.c                         | 140 ++++++++++++------
 libdtrace/dt_parser.h                         |   1 +
 .../err.D_IDENT_UNDEF.scope-dot-kernel.d      |  19 +++
 .../err.D_IDENT_UNDEF.scope-dot-kernel.r      |   2 +
 .../lexer/err.D_IDENT_UNDEF.scope-dot.d       |  19 +++
 .../lexer/err.D_IDENT_UNDEF.scope-dot.r       |   2 +
 .../err.D_SYM_BADREF.scope-kernel-as-user.d   |  18 +++
 .../err.D_SYM_BADREF.scope-kernel-as-user.r   |   2 +
 .../err.D_SYM_BADREF.scope-user-as-kernel.d   |  20 +++
 .../err.D_SYM_BADREF.scope-user-as-kernel.r   |   2 +
 .../err.D_SYNTAX.scope-empty-bare-user.d      |  19 +++
 .../err.D_SYNTAX.scope-empty-bare-user.r      |   2 +
 .../lexer/err.D_SYNTAX.scope-empty-bare.d     |  19 +++
 .../lexer/err.D_SYNTAX.scope-empty-bare.r     |   2 +
 .../lexer/err.D_SYNTAX.scope-empty-dot-user.d |  19 +++
 .../lexer/err.D_SYNTAX.scope-empty-dot-user.r |   2 +
 .../lexer/err.D_SYNTAX.scope-empty-user.d     |  19 +++
 .../lexer/err.D_SYNTAX.scope-empty-user.r     |   2 +
 .../unittest/lexer/err.D_SYNTAX.scope-empty.d |  18 +++
 .../unittest/lexer/err.D_SYNTAX.scope-empty.r |   2 +
 .../lexer/err.D_SYNTAX.scope-multiple.d       |  19 +++
 .../lexer/err.D_SYNTAX.scope-multiple.r       |   2 +
 .../lexer/err.D_SYNTAX.scope-triple.d         |  19 +++
 .../lexer/err.D_SYNTAX.scope-triple.r         |   2 +
 test/unittest/lexer/tst.scope-user-explicit.d |  22 +++
 .../sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d  |   2 +-
 .../sizeof/err.D_IDENT_UNDEF.UnknownSymbol.r  |   2 +-
 .../err.D_DECL_SCOPE.scopeop-enumerator.d     |  16 ++
 .../err.D_DECL_SCOPE.scopeop-enumerator.r     |   2 +
 .../types/err.D_DECL_SCOPE.scopeop-ident.d    |  19 +++
 .../types/err.D_DECL_SCOPE.scopeop-ident.r    |   2 +
 .../types/err.D_DECL_SCOPE.scopeop-member.d   |  16 ++
 .../types/err.D_DECL_SCOPE.scopeop-member.r   |   2 +
 35 files changed, 414 insertions(+), 51 deletions(-)
 create mode 100644 test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.d
 create mode 100644 test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.r
 create mode 100644 test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.d
 create mode 100644 test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.r
 create mode 100644 test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.d
 create mode 100644 test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.r
 create mode 100644 test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.d
 create mode 100644 test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.r
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.d
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.r
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.d
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.r
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.d
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.r
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty-user.d
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty-user.r
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty.d
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-empty.r
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-multiple.d
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-multiple.r
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-triple.d
 create mode 100644 test/unittest/lexer/err.D_SYNTAX.scope-triple.r
 create mode 100644 test/unittest/lexer/tst.scope-user-explicit.d
 create mode 100644 test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.d
 create mode 100644 test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.r
 create mode 100644 test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.d
 create mode 100644 test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.r
 create mode 100644 test/unittest/types/err.D_DECL_SCOPE.scopeop-member.d
 create mode 100644 test/unittest/types/err.D_DECL_SCOPE.scopeop-member.r

diff --git a/libdtrace/dt_decl.c b/libdtrace/dt_decl.c
index 1f4936dd..68999422 100644
--- a/libdtrace/dt_decl.c
+++ b/libdtrace/dt_decl.c
@@ -233,10 +233,8 @@ dt_decl_spec(ushort_t kind, char *name)
 	ddp->dd_kind = kind;
 	ddp->dd_name = name;
 
-	if (name != NULL && strchr(name, '`') != NULL) {
-		xyerror(D_DECL_SCOPE, "D scoping operator may not be used "
-		    "in a type name\n");
-	}
+	if (name != NULL && dt_scope_parse(name, NULL, NULL) < 0)
+		xyerror(D_SYNTAX, "syntax error near \"%s\"\n", name);
 
 	return dt_decl_check(ddp);
 }
diff --git a/libdtrace/dt_lex.l b/libdtrace/dt_lex.l
index fd70aa0a..bf133676 100644
--- a/libdtrace/dt_lex.l
+++ b/libdtrace/dt_lex.l
@@ -50,6 +50,7 @@ static size_t dt_input(char *buf, size_t max_size);
 RGX_AGG		"@"[a-zA-Z_][0-9a-zA-Z_]*
 RGX_PSPEC	[-$:a-zA-Z_.?*\\\[\]!][-$:0-9a-zA-Z_.`?*\\\[\]!]*
 RGX_IDENT	([a-zA-Z_`][0-9a-zA-Z_`]*)|([0-9][0-9a-zA-Z_]*`[0-9a-zA-Z_`]*)
+RGX_SCOPE_IDENT	[0-9a-zA-Z_][0-9a-zA-Z_]*(\.[0-9a-zA-Z_]+)+``?[0-9a-zA-Z_]+
 RGX_INT		([0-9]+|0[xX][0-9A-Fa-f]+)[uU]?[lL]?[lL]?
 RGX_FP		([0-9]+("."?)[0-9]*|"."[0-9]+)((e|E)("+"|-)?[0-9]+)?[fFlL]?
 RGX_WS		[\f\n\r\t\v ]
@@ -299,6 +300,7 @@ if (yypcb->pcb_token != 0) {
 			return DT_TOK_INT;
 		}
 
+<S0>{RGX_SCOPE_IDENT} |
 <S0,SIDENT>{RGX_IDENT}	{
 			return id_or_type(yytext);
 		}
@@ -728,6 +730,9 @@ id_or_type(const char *s)
 	int c0, c1;
 	dt_ident_t *idp;
 
+	if (dt_scope_parse(s, NULL, NULL) < 0)
+		xyerror(D_SYNTAX, "syntax error near \"%s\"\n", s);
+
 	if ((s = yylval.l_str = strdup(s)) == NULL)
 		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
 
diff --git a/libdtrace/dt_parser.c b/libdtrace/dt_parser.c
index e71c0985..1fd0f5b4 100644
--- a/libdtrace/dt_parser.c
+++ b/libdtrace/dt_parser.c
@@ -168,45 +168,96 @@ opstr(int op)
 	}
 }
 
+/*
+ * Parse the D scoping mark used in external type and symbol names.  A scoped
+ * name can contain one mark only: ` for kernel scope, or `` for user scope.
+ * Longer runs and repeated marks are malformed.  Return the scope kind as 0
+ * for no scope, 1 for kernel scope, or 2 for user scope.
+ */
 int
-dt_type_lookup(const char *s, dtrace_typeinfo_t *tip)
+dt_scope_parse(const char *s, const char **scopep, const char **identp)
 {
-	static const char delimiters[] = " \t\n\r\v\f*`";
-	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
-	const char *p, *q, *end, *obj;
+	static const char delimiters[] = " \t\n\r\v\f*";
+	const char *mark = strchr(s, '`');
+	const char *scope;
+	size_t marklen = 1;
+
+	if (mark == NULL) {
+		if (scopep != NULL)
+			*scopep = DTRACE_OBJ_EXEC;
+		if (identp != NULL)
+			*identp = s;
+		return 0;
+	}
 
-	for (p = s, end = s + strlen(s); *p != '\0'; p = q) {
-		while (isspace(*p))
-			p++;	/* skip leading whitespace prior to token */
+	if (mark[1] == '`') {
+		marklen = 2;
+		if (mark[2] == '`')
+			return -1;
+	}
 
-		if (p == end || (q = strpbrk(p + 1, delimiters)) == NULL)
-			break;	/* empty string or single token remaining */
+	if (mark[marklen] == '\0')
+		return -1;
 
-		if (*q == '`') {
-			char *object = alloca((size_t)(q - p) + 1);
-			char *type = alloca((size_t)(end - s) + 1);
+	if (strchr(mark + marklen, '`') != NULL)
+		return -1;
 
-			/*
-			 * Copy from the start of the token (p) to the location
-			 * backquote (q) to extract the nul-terminated object.
-			 */
-			memcpy(object, p, (size_t)(q - p));
-			object[(size_t)(q - p)] = '\0';
+	for (scope = mark;
+	    scope > s && strchr(delimiters, scope[-1]) == NULL; )
+		scope--;
 
-			/*
-			 * Copy the original string up to the start of this
-			 * token (p) into type, and then concatenate everything
-			 * after q.  This is the type name without the object.
-			 */
-			memcpy(type, s, (size_t)(p - s));
-			memcpy(type + (size_t)(p - s), q + 1,
-			    strlen(q + 1) + 1);
+	if (scope == mark)
+		scope = marklen == 2 ? DTRACE_OBJ_UMODS : DTRACE_OBJ_KMODS;
+
+	if (scopep != NULL)
+		*scopep = scope;
+	if (identp != NULL)
+		*identp = mark + marklen;
+
+	return marklen;
+}
+
+int
+dt_type_lookup(const char *s, dtrace_typeinfo_t *tip)
+{
+	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+	const char *scope, *ident, *start, *obj;
+	int scopekind;
+
+	scopekind = dt_scope_parse(s, &scope, &ident);
+	if (scopekind < 0)
+		return dt_set_errno(dtp, EDT_BADSCOPE);
 
-			if (strchr(q + 1, '`') != NULL)
-				return dt_set_errno(dtp, EDT_BADSCOPE);
+	if (scopekind > 0) {
+		char *type;
+
+		/*
+		 * If there is no explicit object before the mark, search all
+		 * kernel or user objects depending on the mark width.
+		 */
+		if (scope == DTRACE_OBJ_KMODS || scope == DTRACE_OBJ_UMODS) {
+			start = ident - scopekind;
+			obj = scope;
+		} else {
+			size_t objlen = (size_t)(ident - scope) - scopekind;
+			char *object = alloca(objlen + 1);
 
-			return dtrace_lookup_by_type(dtp, object, type, tip);
+			memcpy(object, scope, objlen);
+			object[objlen] = '\0';
+			start = scope;
+			obj = object;
 		}
+
+		/*
+		 * Copy the original string up to the start of this token
+		 * into type, and then concatenate everything after the scoping
+		 * mark.  This is the type name without the object and mark.
+		 */
+		type = alloca((size_t)(start - s) + strlen(ident) + 1);
+		memcpy(type, s, (size_t)(start - s));
+		memcpy(type + (size_t)(start - s), ident, strlen(ident) + 1);
+
+		return dtrace_lookup_by_type(dtp, obj, type, tip);
 	}
 
 	if (yypcb->pcb_idepth != 0)
@@ -2767,9 +2818,10 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
 	dtrace_syminfo_t dts;
 	GElf_Sym sym;
 
-	const char *scope, *mark;
+	const char *scope, *ident, *markstr;
 	uchar_t dnkind;
 	char *name;
+	int scopekind;
 
 	/*
 	 * Look for scoping marks in the identifier.  If one is found, set our
@@ -2779,18 +2831,16 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
 	 * Otherwise we set scope to DTRACE_OBJ_EXEC, indicating that normal
 	 * scope is desired and we should search the specified idhash.
 	 */
-	if ((name = strrchr(dnp->dn_string, '`')) != NULL) {
-		if (name > dnp->dn_string && name[-1] == '`') {
-			uref++;
-			name[-1] = '\0';
-		}
-
-		if (name == dnp->dn_string + uref)
-			scope = uref ? DTRACE_OBJ_UMODS : DTRACE_OBJ_KMODS;
-		else
-			scope = dnp->dn_string;
+	scopekind = dt_scope_parse(dnp->dn_string, &scope, &ident);
+	if (scopekind < 0) {
+		xyerror(D_SYNTAX, "syntax error near \"%s\"\n",
+		    dnp->dn_string);
+	}
 
-		*name++ = '\0'; /* leave name pointing after scoping mark */
+	if (scopekind > 0) {
+		uref = scopekind == 2;
+		name = (char *)ident;
+		*(char *)(ident - scopekind) = '\0';
 		dnkind = DT_NODE_VAR;
 
 	} else if (idkind == DT_IDENT_AGG) {
@@ -2810,7 +2860,7 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
 	 * errno appropriately and that error will be reported instead.
 	 */
 	dt_set_errno(dtp, EDT_NOVAR);
-	mark = uref ? "``" : "`";
+	markstr = uref ? "``" : "`";
 
 	if (scope == DTRACE_OBJ_EXEC && (
 	    (dhp != dtp->dt_globals &&
@@ -2902,13 +2952,13 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
 				xyerror(D_SYM_MODEL, "cannot use %s symbol "
 					"%s%s%s in a %s D program\n",
 					dt_module_modelname(mp), dts.object,
-					mark, dts.name,
+					markstr, dts.name,
 					dt_module_modelname(dtp->dt_ddefs));
 			}
 
 			xyerror(D_SYM_NOTYPES, "no symbolic type information "
 				"is available for %s%s%s: %s\n",
-				dts.object, mark, dts.name,
+				dts.object, markstr, dts.name,
 				dtrace_errmsg(dtp, dtrace_errno(dtp)));
 		}
 
@@ -3014,7 +3064,7 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
 
 	} else if (scope != DTRACE_OBJ_EXEC) {
 		xyerror(D_IDENT_UNDEF, "failed to resolve %s%s%s: %s\n",
-		    dnp->dn_string, mark, name,
+		    dnp->dn_string, markstr, name,
 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
 	} else {
 		xyerror(D_IDENT_UNDEF, "failed to resolve %s: %s\n",
diff --git a/libdtrace/dt_parser.h b/libdtrace/dt_parser.h
index d74d658a..b9149220 100644
--- a/libdtrace/dt_parser.h
+++ b/libdtrace/dt_parser.h
@@ -211,6 +211,7 @@ extern dt_node_t *dt_node_tstring(dt_node_t *, uintmax_t);
 extern dt_node_t *dt_node_link(dt_node_t *, dt_node_t *);
 extern dt_node_t *dt_node_cook(dt_node_t *, uint_t);
 extern void dt_cook_taint_alloca(dt_node_t *, dt_ident_t *, dt_node_t *);
+extern int dt_scope_parse(const char *, const char **, const char **);
 
 extern dt_node_t *dt_node_xalloc(dtrace_hdl_t *, int);
 extern void dt_node_free(dt_node_t *);
diff --git a/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.d b/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.d
new file mode 100644
index 00000000..2a267567
--- /dev/null
+++ b/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: Dotted kernel module scopes lex as a single external symbol
+ * reference.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(foo.bar`baz);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.r b/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.r
new file mode 100644
index 00000000..89a9f9c5
--- /dev/null
+++ b/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot-kernel.d: [D_IDENT_UNDEF] line 17: failed to resolve foo.bar`baz: Module is no longer loaded
diff --git a/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.d b/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.d
new file mode 100644
index 00000000..6b3dcfda
--- /dev/null
+++ b/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: Dotted userspace module scopes lex as a single external symbol
+ * reference.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(foo.bar``baz);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.r b/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.r
new file mode 100644
index 00000000..7734e29f
--- /dev/null
+++ b/test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_IDENT_UNDEF.scope-dot.d: [D_IDENT_UNDEF] line 17: failed to resolve foo.bar``baz: Module is no longer loaded
diff --git a/test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.d b/test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.d
new file mode 100644
index 00000000..d332191b
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.d
@@ -0,0 +1,18 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: Kernel symbols cannot be referenced using userspace scoping.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(vmlinux``major_names);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.r b/test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.r
new file mode 100644
index 00000000..718b2b31
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYM_BADREF.scope-kernel-as-user.d: [D_SYM_BADREF] line 16: kernel module 'vmlinux' symbol 'major_names' may not be referenced as a user symbol
diff --git a/test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.d b/test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.d
new file mode 100644
index 00000000..bc7e8b9f
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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.
+ */
+
+/* @@trigger: testprobe */
+
+/*
+ * ASSERTION: Userspace symbols cannot be referenced using kernel scoping.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(&testprobe`main);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.r b/test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.r
new file mode 100644
index 00000000..87169597
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYM_BADREF.scope-user-as-kernel.d: [D_SYM_BADREF] line 18: user module 'testprobe' symbol 'main' may not be referenced as a kernel symbol
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.d b/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.d
new file mode 100644
index 00000000..d7cff89f
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: A bare userspace D scoping operator with an empty identifier is a
+ * syntax error.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(``);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.r b/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.r
new file mode 100644
index 00000000..8e9cd1ff
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYNTAX.scope-empty-bare-user.d: [D_SYNTAX] line 17: syntax error near "``"
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.d b/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.d
new file mode 100644
index 00000000..44b4f60e
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: A bare D scoping operator with an empty identifier is a syntax
+ * error.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(`);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.r b/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.r
new file mode 100644
index 00000000..bbba5fe8
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYNTAX.scope-empty-bare.d: [D_SYNTAX] line 17: syntax error near "`"
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.d b/test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.d
new file mode 100644
index 00000000..5ead7b3e
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: A dotted userspace D scoping operator with an empty identifier is
+ * a syntax error.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(foo.bar``);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.r b/test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.r
new file mode 100644
index 00000000..b07c07b1
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYNTAX.scope-empty-dot-user.d: [D_SYNTAX] line 17: syntax error near "bar``"
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty-user.d b/test/unittest/lexer/err.D_SYNTAX.scope-empty-user.d
new file mode 100644
index 00000000..d3a927d7
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty-user.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: A userspace D scoping operator with an empty identifier is a
+ * syntax error.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(bar``);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty-user.r b/test/unittest/lexer/err.D_SYNTAX.scope-empty-user.r
new file mode 100644
index 00000000..dbf319ea
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty-user.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYNTAX.scope-empty-user.d: [D_SYNTAX] line 17: syntax error near "bar``"
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty.d b/test/unittest/lexer/err.D_SYNTAX.scope-empty.d
new file mode 100644
index 00000000..e32b3812
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty.d
@@ -0,0 +1,18 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: A D scoping operator with an empty identifier is a syntax error.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(foo`);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-empty.r b/test/unittest/lexer/err.D_SYNTAX.scope-empty.r
new file mode 100644
index 00000000..d78728b2
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-empty.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYNTAX.scope-empty.d: [D_SYNTAX] line 16: syntax error near "foo`"
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-multiple.d b/test/unittest/lexer/err.D_SYNTAX.scope-multiple.d
new file mode 100644
index 00000000..5e236c45
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-multiple.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: Multiple D scoping operators in one identifier are a syntax
+ * error.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(foo``bar``baz);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-multiple.r b/test/unittest/lexer/err.D_SYNTAX.scope-multiple.r
new file mode 100644
index 00000000..cefc56ad
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-multiple.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYNTAX.scope-multiple.d: [D_SYNTAX] line 17: syntax error near "foo``bar``baz"
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-triple.d b/test/unittest/lexer/err.D_SYNTAX.scope-triple.d
new file mode 100644
index 00000000..41f7391c
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-triple.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: More than two consecutive D scoping operator characters are a
+ * syntax error.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(foo```bar);
+	exit(0);
+}
diff --git a/test/unittest/lexer/err.D_SYNTAX.scope-triple.r b/test/unittest/lexer/err.D_SYNTAX.scope-triple.r
new file mode 100644
index 00000000..4474c502
--- /dev/null
+++ b/test/unittest/lexer/err.D_SYNTAX.scope-triple.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/lexer/err.D_SYNTAX.scope-triple.d: [D_SYNTAX] line 17: syntax error near "foo```bar"
diff --git a/test/unittest/lexer/tst.scope-user-explicit.d b/test/unittest/lexer/tst.scope-user-explicit.d
new file mode 100644
index 00000000..2d649f6f
--- /dev/null
+++ b/test/unittest/lexer/tst.scope-user-explicit.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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.
+ */
+
+/* @@trigger: testprobe */
+/* @@runtest-opts: -e */
+
+/*
+ * ASSERTION: Explicit userspace module scoping resolves as a userspace
+ * external symbol reference.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	trace(&testprobe``main);
+	exit(0);
+}
diff --git a/test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d b/test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d
index 56c93d43..4de9322d 100644
--- a/test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d
+++ b/test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d
@@ -16,6 +16,6 @@
 
 BEGIN
 {
-	printf("sizeof(`): %d\n", sizeof(`));
+	printf("sizeof(`unknown_symbol): %d\n", sizeof(`unknown_symbol));
 	exit(0);
 }
diff --git a/test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.r b/test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.r
index 462469b7..0f46ad1e 100644
--- a/test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.r
+++ b/test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.r
@@ -1,2 +1,2 @@
 -- @@stderr --
-dtrace: failed to compile script test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d: [D_IDENT_UNDEF] line 19: failed to resolve `: Unknown symbol name
+dtrace: failed to compile script test/unittest/sizeof/err.D_IDENT_UNDEF.UnknownSymbol.d: [D_IDENT_UNDEF] line 19: failed to resolve `unknown_symbol: Unknown symbol name
diff --git a/test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.d b/test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.d
new file mode 100644
index 00000000..51068c20
--- /dev/null
+++ b/test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.d
@@ -0,0 +1,16 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: D scoping operators are not permitted in enumerator names.
+ */
+
+#pragma D option quiet
+
+enum scopeop_enum {
+	foo`bar
+};
diff --git a/test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.r b/test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.r
new file mode 100644
index 00000000..06ef912b
--- /dev/null
+++ b/test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/types/err.D_DECL_SCOPE.scopeop-enumerator.d: [D_DECL_SCOPE] line 15: D scoping operator may not be used in an enumerator name (foo`bar)
diff --git a/test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.d b/test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.d
new file mode 100644
index 00000000..6042e208
--- /dev/null
+++ b/test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.d
@@ -0,0 +1,19 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: D scoping operators are not permitted in declaration names.
+ */
+
+#pragma D option quiet
+
+int foo`bar;
+
+BEGIN
+{
+	exit(1);
+}
diff --git a/test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.r b/test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.r
new file mode 100644
index 00000000..7b2e6797
--- /dev/null
+++ b/test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/types/err.D_DECL_SCOPE.scopeop-ident.d: [D_DECL_SCOPE] line 14: D scoping operator may not be used in a declaration name (foo`bar)
diff --git a/test/unittest/types/err.D_DECL_SCOPE.scopeop-member.d b/test/unittest/types/err.D_DECL_SCOPE.scopeop-member.d
new file mode 100644
index 00000000..5fe36a00
--- /dev/null
+++ b/test/unittest/types/err.D_DECL_SCOPE.scopeop-member.d
@@ -0,0 +1,16 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, 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: D scoping operators are not permitted in struct member names.
+ */
+
+#pragma D option quiet
+
+struct scopeop_struct {
+	int foo`bar;
+};
diff --git a/test/unittest/types/err.D_DECL_SCOPE.scopeop-member.r b/test/unittest/types/err.D_DECL_SCOPE.scopeop-member.r
new file mode 100644
index 00000000..978ef79d
--- /dev/null
+++ b/test/unittest/types/err.D_DECL_SCOPE.scopeop-member.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/types/err.D_DECL_SCOPE.scopeop-member.d: [D_DECL_SCOPE] line 15: D scoping operator may not be used in a member name (foo`bar)
-- 
2.47.3


             reply	other threads:[~2026-06-12 19:21 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-12 16:17 Kris Van Hees [this message]
  -- strict thread matches above, loose matches on Subject: below --
2026-06-12 16:28 [PATCH] parser: validate scoped external names Kris Van Hees

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=223110216617c37c5d24d454d122ff8d@oracle.com \
    --to=kris.van.hees@oracle.com \
    --cc=dtrace-devel@oss.oracle.com \
    --cc=dtrace@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox