-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[libc] Add printf error handling (with fixes #2) #166517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-libc Author: Marcell Leleszi (mleleszi) ChangesAnother try of trying to land #166382
@michaelrj-google Patch is 60.00 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/166517.diff 39 Files Affected:
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index b0a6ef1e291b5..c75c8b11be2b5 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -125,6 +125,10 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -136,6 +140,10 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -146,6 +154,10 @@ add_entrypoint_object(
asprintf.h
DEPENDS
libc.src.stdio.printf_core.vasprintf_internal
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -157,6 +169,10 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -168,6 +184,10 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -178,6 +198,10 @@ add_entrypoint_object(
vasprintf.h
DEPENDS
libc.src.stdio.printf_core.vasprintf_internal
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_subdirectory(printf_core)
diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp
index f8cfb74ce48ea..0991dfca6a059 100644
--- a/libc/src/stdio/asprintf.cpp
+++ b/libc/src/stdio/asprintf.cpp
@@ -7,8 +7,12 @@
//===----------------------------------------------------------------------===//
#include "src/stdio/asprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vasprintf_internal.h"
namespace LIBC_NAMESPACE_DECL {
@@ -22,8 +26,18 @@ LLVM_LIBC_FUNCTION(int, asprintf,
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- int ret = printf_core::vasprintf_internal(buffer, format, args);
- return ret;
+ auto ret_val = printf_core::vasprintf_internal(buffer, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index 548938f885c94..bfeff0e2b5880 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -29,8 +29,12 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.stdio.printf_core.core_structs
libc.src.__support.arg_list
libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -87,8 +91,12 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.stdio.printf_core.core_structs
libc.src.__support.arg_list
libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp
index 7253c6549a4e4..5a9b19ff20471 100644
--- a/libc/src/stdio/baremetal/printf.cpp
+++ b/libc/src/stdio/baremetal/printf.cpp
@@ -7,10 +7,13 @@
//===----------------------------------------------------------------------===//
#include "src/stdio/printf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/OSUtil/io.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -42,13 +45,25 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) {
buffer, BUFF_SIZE, &stdout_write_hook, nullptr);
printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
- int retval = printf_core::printf_main(&writer, format, args);
+ auto retval = printf_core::printf_main(&writer, format, args);
+ if (!retval.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(retval.error());
+ return -1;
+ }
int flushval = wb.overflow_write("");
- if (flushval != printf_core::WRITE_OK)
- retval = flushval;
+ if (flushval != printf_core::WRITE_OK) {
+ libc_errno = printf_core::internal_error_to_errno(-flushval);
+ return -1;
+ }
- return retval;
+ if (retval.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(retval.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp
index ab02533f14911..c172b368d15f3 100644
--- a/libc/src/stdio/baremetal/vprintf.cpp
+++ b/libc/src/stdio/baremetal/vprintf.cpp
@@ -7,10 +7,13 @@
//===----------------------------------------------------------------------===//
#include "src/stdio/vprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/OSUtil/io.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -40,13 +43,25 @@ LLVM_LIBC_FUNCTION(int, vprintf,
buffer, BUFF_SIZE, &stdout_write_hook, nullptr);
printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
- int retval = printf_core::printf_main(&writer, format, args);
+ auto retval = printf_core::printf_main(&writer, format, args);
+ if (!retval.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(retval.error());
+ return -1;
+ }
int flushval = wb.overflow_write("");
- if (flushval != printf_core::WRITE_OK)
- retval = flushval;
+ if (flushval != printf_core::WRITE_OK) {
+ libc_errno = printf_core::internal_error_to_errno(-flushval);
+ return -1;
+ }
- return retval;
+ if (retval.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(retval.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt
index 6361822b61999..71055edea3d9e 100644
--- a/libc/src/stdio/generic/CMakeLists.txt
+++ b/libc/src/stdio/generic/CMakeLists.txt
@@ -393,7 +393,11 @@ add_generic_entrypoint_object(
list(APPEND fprintf_deps
libc.hdr.types.FILE
libc.src.__support.arg_list
+ libc.src.__support.CPP.limits
+ libc.src.__support.libc_errno
libc.src.stdio.printf_core.vfprintf_internal
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
)
if(LLVM_LIBC_FULL_BUILD)
diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp
index 087aeadfc52c5..b2033901557a0 100644
--- a/libc/src/stdio/generic/fprintf.cpp
+++ b/libc/src/stdio/generic/fprintf.cpp
@@ -8,9 +8,12 @@
#include "src/stdio/fprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vfprintf_internal.h"
#include "hdr/types/FILE.h"
@@ -27,8 +30,18 @@ LLVM_LIBC_FUNCTION(int, fprintf,
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- int ret_val = printf_core::vfprintf_internal(stream, format, args);
- return ret_val;
+ auto ret_val = printf_core::vfprintf_internal(stream, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/generic/printf.cpp b/libc/src/stdio/generic/printf.cpp
index bb7c7c86f843f..8d159d5c70870 100644
--- a/libc/src/stdio/generic/printf.cpp
+++ b/libc/src/stdio/generic/printf.cpp
@@ -8,9 +8,12 @@
#include "src/stdio/printf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vfprintf_internal.h"
#include "hdr/types/FILE.h"
@@ -31,9 +34,19 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) {
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- int ret_val = printf_core::vfprintf_internal(
+ auto ret_val = printf_core::vfprintf_internal(
reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args);
- return ret_val;
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/generic/vfprintf.cpp b/libc/src/stdio/generic/vfprintf.cpp
index 01f4265f118a6..a26f082ed9347 100644
--- a/libc/src/stdio/generic/vfprintf.cpp
+++ b/libc/src/stdio/generic/vfprintf.cpp
@@ -8,9 +8,12 @@
#include "src/stdio/vfprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vfprintf_internal.h"
#include "hdr/types/FILE.h"
@@ -24,8 +27,18 @@ LLVM_LIBC_FUNCTION(int, vfprintf,
internal::ArgList args(vlist); // This holder class allows for easier copying
// and pointer semantics, as well as handling
// destruction automatically.
- int ret_val = printf_core::vfprintf_internal(stream, format, args);
- return ret_val;
+ auto ret_val = printf_core::vfprintf_internal(stream, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp
index 08d71515646ed..ae2160219f2bb 100644
--- a/libc/src/stdio/generic/vprintf.cpp
+++ b/libc/src/stdio/generic/vprintf.cpp
@@ -8,9 +8,12 @@
#include "src/stdio/vprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vfprintf_internal.h"
#include "hdr/types/FILE.h"
@@ -29,9 +32,19 @@ LLVM_LIBC_FUNCTION(int, vprintf,
internal::ArgList args(vlist); // This holder class allows for easier copying
// and pointer semantics, as well as handling
// destruction automatically.
- int ret_val = printf_core::vfprintf_internal(
+ auto ret_val = printf_core::vfprintf_internal(
reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args);
- return ret_val;
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index ee66145e60156..624129b2b36e7 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -32,6 +32,17 @@ if(printf_config_copts)
list(PREPEND printf_config_copts "COMPILE_OPTIONS")
endif()
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${LIBC_TARGET_OS})
+else()
+ add_subdirectory(generic)
+endif()
+
+set(target_error_mapper libc.src.stdio.printf_core.${LIBC_TARGET_OS}.error_mapper)
+if(NOT TARGET ${target_error_mapper})
+ set(target_error_mapper libc.src.stdio.printf_core.generic.error_mapper)
+endif()
+
add_header_library(
printf_config
HDRS
@@ -47,6 +58,7 @@ add_header_library(
libc.include.inttypes
libc.src.__support.CPP.string_view
libc.src.__support.FPUtil.fp_bits
+ libc.hdr.errno_macros
)
add_header_library(
@@ -125,6 +137,7 @@ add_header_library(
.writer
.core_structs
libc.src.__support.arg_list
+ libc.src.__support.error_or
)
add_header_library(
@@ -136,10 +149,20 @@ add_header_library(
libc.hdr.func.free
libc.hdr.func.realloc
libc.src.__support.arg_list
+ libc.src.__support.error_or
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
)
+add_header_library(
+ error_mapper
+ HDRS
+ error_mapper.h
+ DEPENDS
+ ${target_error_mapper}
+ libc.src.__support.macros.properties.architectures
+)
+
if(NOT (TARGET libc.src.__support.File.file) AND LLVM_LIBC_FULL_BUILD)
# Not all platforms have a file implementation. If file is unvailable, and a
# full build is requested, then we must skip all file based printf sections.
@@ -152,8 +175,10 @@ add_header_library(
vfprintf_internal.h
DEPENDS
libc.src.__support.File.file
+ libc.src.__support.error_or
libc.src.__support.arg_list
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
${use_system_file}
)
+
diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h
index e27f77b6b594a..0d41f2244d8da 100644
--- a/libc/src/stdio/printf_core/core_structs.h
+++ b/libc/src/stdio/printf_core/core_structs.h
@@ -132,14 +132,17 @@ template <typename T> LIBC_INLINE constexpr TypeDesc type_desc_from_type() {
// This is the value to be returned by conversions when no error has occurred.
constexpr int WRITE_OK = 0;
-// These are the printf return values for when an error has occurred. They are
-// all negative, and should be distinct.
-constexpr int FILE_WRITE_ERROR = -1;
-constexpr int FILE_STATUS_ERROR = -2;
-constexpr int NULLPTR_WRITE_ERROR = -3;
-constexpr int INT_CONVERSION_ERROR = -4;
-constexpr int FIXED_POINT_CONVERSION_ERROR = -5;
-constexpr int ALLOCATION_ERROR = -6;
+// These are the error return values used by the printf engine when an
+// error has occurred. They are all large negative, distinct values starting
+// from -1000 to not overlap with system errors.
+constexpr int FILE_WRITE_ERROR = -1001;
+constexpr int FILE_STATUS_ERROR = -1002;
+constexpr int NULLPTR_WRITE_ERROR = -1003;
+constexpr int INT_CONVERSION_ERROR = -1004;
+constexpr int FIXED_POINT_CONVERSION_ERROR = -1005;
+constexpr int ALLOCATION_ERROR = -1006;
+constexpr int OVERFLOW_ERROR = -1007;
+
} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/error_mapper.h b/libc/src/stdio/printf_core/error_mapper.h
new file mode 100644
index 0000000000000..23030930133a1
--- /dev/null
+++ b/libc/src/stdio/printf_core/error_mapper.h
@@ -0,0 +1,21 @@
+//===-- Error mapper for printf ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_MAPPER_H
+#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_MAPPER_H
+
+#include "src/__support/macros/properties/architectures.h"
+
+// Maps internal errors to the available errnos on the platform.
+#if defined(__linux__)
+#include "linux/error_mapper.h"
+#else
+#include "generic/error_mapper.h"
+#endif
+
+#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_MAPPER_H
diff --git a/libc/src/stdio/printf_core/generic/CMakeLists.txt b/libc/src/stdio/printf_core/generic/CMakeLists.txt
new file mode 100644
index 0000000000000..2f0143d992e31
--- /dev/null
+++ b/libc/src/stdio/printf_core/generic/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_header_library(
+ error_mapper
+ HDRS
+ error_mapper.h
+ DEPENDS
+ libc.src.stdio.printf_core.core_structs
+ libc.hdr.errno_macros
+)
diff --git a/libc/src/stdio/printf_core/generic/error_mapper.h b/libc/src/stdio/printf_core/generic/error_mapper.h
new file mode 100644
index 0000000000000..d8cdd2cc2dbaa
--- /dev/null
+++ b/libc/src/stdio/printf_core/generic/error_mapper.h
@@ -0,0 +1,49 @@
+//===-- Generic implementation of error mapper ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_GENERIC_ERROR_MAPPER_H
+#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_GENERIC_ERROR_MAPPER_H
+
+#include "hdr/errno_macros.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace printf_core {
+
+LIBC_INLINE static int internal_error_to_errno(int internal_error) {
+ // System error occured, return error as is.
+ if (internal_error < 1001 && internal_error > 0) {
+ return internal_error;
+ }
+
+ // Map internal er...
[truncated]
|
|
@jhuber6 @Kewen12 Sorry for breaking your builds! |
#159474
Another try of trying to land #166382
@michaelrj-google