bazelbuild / bazelbuild/bazel

Crash when incoming edge transition depends on a configurable attribute

Open
#23,278 2 comments 0 reactions 1 assignee Claimed by @aranguyen View on GitHub
P2 team-Configurability type: bug
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.