Crash when incoming edge transition depends on a configurable attribute
- Dominant language
- Java
- Stars
- 25.8k
- Forks
- 4.6k
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 72
Description
### Description of the bug:
Bazel crashes if an incoming edge transition reads `attr` that is set to a `select()` expression.
### Which category does this issue belong to?
_No response_
### What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.
```
# MODULE.bazel
# empty file
```
```
# BUILD.bazel
load(":a.bzl", "transitioned_files")
transitioned_files(
name = "ok",
target_platform = select({
"//conditions:default": None, # LINE A
})
)
```
```
# a.bzl
def _platform_transition_impl(_settings, attr):
print(attr.target_platform) # THIS CRASHES
return None
platform_transition = transition(
implementation = _platform_transition_impl,
inputs = [],
outputs = ["//command_line_option:platforms"],
)
def _transitioned_files_impl(_ctx):
pass
transitioned_files = rule(
implementation = _transitioned_files_impl,
attrs = {
"target_platform": attr.label(),
},
cfg = platform_transition,
)
```
Then run
```
bazel build //:ok
```
This crashes with the following trace:
```
$ bazel build :ok
Starting local Bazel server and connecting to it...
Analyzing: target //:ok (1 packages loaded, 0 targets configured)
currently loading: @@bazel_tools//tools
[0 / 1] checking cached actions
FATAL: bazel crashed due to an internal error. Printing stack trace:
java.lang.RuntimeException: Unrecoverable error while evaluating node 'ConfiguredTargetKey{label=//:ok, config=BuildConfigurationKey[b357dd09923b37f48f631ab81341a90e6b4443fce0a2dddfde9d204ca537a54e]}' (requested by nodes 'BuildDriverKey of ActionLookupKey: ConfiguredTargetKey{label=//:ok, config=BuildConfigurationKey[b357dd09923b37f48f631ab81341a90e6b4443fce0a2dddfde9d204ca537a54e]}')
at com.google.devtools.build.skyframe.AbstractParallelEvaluator$Evaluate.run(AbstractParallelEvaluator.java:550)
at com.google.devtools.build.lib.concurrent.AbstractQueueVisitor$WrappedRunnable.run(AbstractQueueVisitor.java:414)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool.scan(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(Unknown Source)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source)
Caused by: net.starlark.java.eval.Starlark$UncheckedEvalException: NullPointerException thrown during Starlark evaluation (ANALYSIS)
at .print(:0)
at ._platform_transition_impl(/mnt/sdc/android/tmpdir2/a.bzl:4)
Caused by: java.lang.NullPointerException: null value in entry: //conditions:default=null
at com.google.common.collect.CollectPreconditions.checkEntryNotNull(CollectPreconditions.java:33)
at com.google.common.collect.SingletonImmutableBiMap.(SingletonImmutableBiMap.java:43)
at com.google.common.collect.ImmutableBiMap.of(ImmutableBiMap.java:83)
at com.google.common.collect.ImmutableMap.of(ImmutableMap.java:130)
at com.google.common.collect.ImmutableMap.copyOf(ImmutableMap.java:709)
at com.google.common.collect.ImmutableMap.copyOf(ImmutableMap.java:688)
at com.google.devtools.build.lib.packages.SelectorValue.(SelectorValue.java:56)
at com.google.devtools.build.lib.packages.BuildType$SelectorList.repr(BuildType.java:637)
at net.starlark.java.eval.StarlarkValue.str(StarlarkValue.java:45)
at net.starlark.java.eval.StarlarkValue.debugPrint(StarlarkValue.java:61)
at net.starlark.java.eval.Printer.debugPrint(Printer.java:119)
at net.starlark.java.eval.MethodLibrary.print(MethodLibrary.java:885)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at net.starlark.java.eval.MethodDescriptor.call(MethodDescriptor.java:178)
at net.starlark.java.eval.BuiltinFunction.fastcall(BuiltinFunction.java:78)
at net.starlark.java.eval.Starlark.fastcall(Starlark.java:806)
at net.starlark.java.eval.Eval.evalCall(Eval.java:682)
at net.starlark.java.eval.Eval.eval(Eval.java:497)
at net.starlark.java.eval.Eval.exec(Eval.java:271)
at net.starlark.java.eval.Eval.execStatements(Eval.java:82)
at net.starlark.java.eval.Eval.execFunctionBody(Eval.java:66)
at net.starlark.java.eval.StarlarkFunction.fastcall(StarlarkFunction.java:179)
at net.starlark.java.eval.Starlark.fastcall(Starlark.java:806)
at com.google.devtools.build.lib.analysis.config.StarlarkDefinedConfigTransition$RegularTransition.evaluate(StarlarkDefinedConfigTransition.java:563)
at com.google.devtools.build.lib.analysis.starlark.FunctionTransitionUtil.applyAndValidate(FunctionTransitionUtil.java:99)
at com.google.devtools.build.lib.analysis.starlark.StarlarkRuleTransitionProvider$FunctionPatchTransition.patch(StarlarkRuleTransitionProvider.java:201)
at com.google.devtools.build.lib.analysis.config.transitions.PatchTransition.apply(PatchTransition.java:75)
at com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition.apply(ComposingTransition.java:69)
at com.google.devtools.build.lib.analysis.config.StarlarkTransitionCache.computeIfAbsent(StarlarkTransitionCache.java:79)
at com.google.devtools.build.lib.analysis.producers.TransitionApplier.applyStarlarkTransition(TransitionApplier.java:126)
at com.google.devtools.build.lib.analysis.producers.TransitionApplier.step(TransitionApplier.java:96)
at com.google.devtools.build.skyframe.state.TaskTreeNode.run(TaskTreeNode.java:94)
at com.google.devtools.build.skyframe.state.Driver.drive(Driver.java:87)
at com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.computeTargetAndConfiguration(ConfiguredTargetFunction.java:479)
at com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.compute(ConfiguredTargetFunction.java:249)
at com.google.devtools.build.skyframe.AbstractParallelEvaluator$Evaluate.run(AbstractParallelEvaluator.java:461)
at com.google.devtools.build.lib.concurrent.AbstractQueueVisitor$WrappedRunnable.run(AbstractQueueVisitor.java:414)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool.scan(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(Unknown Source)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source)
```
I expect it to not crash and print `None`.
If I change BUILD.bazel, `LINE A` to the following:
```
"//conditions:default": "@platforms//host",
```
Then it will print a select expression, instead of the evaluated result:
```
$ bazel build :ok
Starting local Bazel server and connecting to it...
DEBUG: /mnt/sdc/android/tmpdir2/a.bzl:4:10: select({Label("//conditions:default"): Label("@@platforms//host:host")})
DEBUG: /mnt/sdc/android/tmpdir2/a.bzl:4:10: select({Label("//conditions:default"): Label("@@platforms//host:host")})
DEBUG: /mnt/sdc/android/tmpdir2/a.bzl:4:10: select({Label("//conditions:default"): Label("@@platforms//host:host")})
INFO: Analyzed target //:ok (6 packages loaded, 9 targets configured).
INFO: Found 1 target...
Target //:ok up-to-date (nothing to build)
INFO: Elapsed time: 2.173s, Critical Path: 0.02s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
```
I expect it to print a simple `Label("@@platforms//host:host")` instead of the un-evaluated expression.
If it were an outgoing-edge transition, then it properly prints `None` and `Label("@@platforms//host:host")` respectively. This bug only happens on the incoming edge transition.
```
transitioned_files = rule(
implementation = _transitioned_files_impl,
attrs = {
"src": attr.label(
cfg = platform_transition,
),
"target_platform": attr.label(),
},
)
```
```
$ bazel build :ok
DEBUG: /mnt/sdc/android/tmpdir2/a.bzl:4:10: @@platforms//host:host
```
### Which operating system are you running Bazel on?
Linux
### What is the output of `bazel info release`?
release 7.3.0
### If `bazel info release` returns `development version` or `(@non-git)`, tell us how you built Bazel.
_No response_
### What's the output of `git remote get-url origin; git rev-parse HEAD` ?
_No response_
### If this is a regression, please try to identify the Bazel commit where the bug was introduced with bazelisk --bisect.
_No response_
### Have you found anything relevant by searching the web?
_No response_
### Any other information, logs, or outputs that you want to share?
This is probably a WAI, but I don't see any documentation describing the behavior in https://bazel.build/extending/config. Perhaps a documentation update would be sufficient?
Also, I wouldn't expect a crash, but a proper error message that this is not a supported use case.
Contributor guide
Assessment
This issue has not been assessed yet.