summaryrefslogtreecommitdiffstats
path: root/tests/preprocessor
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2020-07-10 11:14:11 -0700
committerGitHub <noreply@github.com>2020-07-10 11:14:11 -0700
commit6aad38a43394a60c02c6109199d427d88147e781 (patch)
treee48c535f4cfa5ccf7ee31b61871a1039b3ea7527 /tests/preprocessor
parent2503280122c7ac54cc3e42e2e54efff1d002d126 (diff)
Fix a preprocessor bug affecting X-macros (#1436)
* Fix a preprocessor bug affecting X-macros Fixes #1435 This bug exhibited as nondeterministic output from the preprocessor in release builds, but using a debug build it was narrowed down to a use-after-free issue. The core problem is subtle, but relates to how we set up the linked list that represents the "busy" status of macros in a particular expansion environment. Consider this scenario: ```hlsl X(A) ``` The flow we expect from the preprocessor is something like: 1. Read the `X` token in `X(A)` and recognize the start of a function-like macro invocation. Create an expansion environment for `X`, with the global environment as a parent, read in the arguments (just `A`), and push that expansion onto the stack. 2. Read the `M` token that starts the expansion of `M`, and recognize it as an invocation of the object-like macro representing the argument `M`. Create an expansion environment for the definition of `M` (which is just `A`), and push it onto the stack. 3. Read the token `A` from the expansion for the argument `M`, and recognize it as an invocation of the function-like macro `A`. Create an expansion environemnt for `A`, with the current environment as its parent, read in the arguments (just `0`), and push that expansion onto the stack. 4. Read the token `y` from the expansion for `A`, and recognize it as an invocation of the object-like macro representing the argument `y`. Create an expansion environment for the definition of `y` (which is just `0`) and push it onto the stack. 5. Read `0`. 6. Read a bunch of end-of-file tokens that cause all of these expansions to be popped. That all looks fine as written, but the gotcha is that the input stream for the expansion in step (2) is only a single token (`A`), which means that during step (3) the current input stream at the time we *create* the macro expansion for `A` is at the end of its input, and by the time we've read in the macro arguments that expansion will have been popped. The problem, then, is that the logic for setting up the stack of "busy" macros was being performed at the beginning of the expansion (the part referred to as "create an expansion" above), when it should only have been set up as part of pushing the xpansion onto the stack (since at that point we have a guarantee that the parent expansion cannot be popped until the child expansion has been). The fix here is thus pretty simple: we already have distinct operations for `initializeMacroExpansion()` and `pushMacroExpansion()`, and I simply moved the logic for setting up the "busy" state from the former to the latter. * fixup: typo
Diffstat (limited to 'tests/preprocessor')
-rw-r--r--tests/preprocessor/x-macro.slang13
1 files changed, 13 insertions, 0 deletions
diff --git a/tests/preprocessor/x-macro.slang b/tests/preprocessor/x-macro.slang
new file mode 100644
index 000000000..6b8d48b4e
--- /dev/null
+++ b/tests/preprocessor/x-macro.slang
@@ -0,0 +1,13 @@
+// x-macro.slang
+//TEST:SIMPLE:
+
+// Test the case of an "X macro" that takes another macro as a parameter
+
+#define X(M) M(0) M(1) M(2) M(3) M(4) M(5) M(6) M(7)
+
+#define A(x) + x + x + x
+
+int sum()
+{
+ return X(A);
+}