diff options
102 files changed, 3597 insertions, 536 deletions
diff --git a/build/external_resources/ymake/public.resources.json b/build/external_resources/ymake/public.resources.json index da903b8c73a..a8a76e1b078 100644 --- a/build/external_resources/ymake/public.resources.json +++ b/build/external_resources/ymake/public.resources.json @@ -1,19 +1,19 @@ { "by_platform": { "darwin": { - "uri": "sbr:7522713648" + "uri": "sbr:7570915389" }, "darwin-arm64": { - "uri": "sbr:7522713246" + "uri": "sbr:7570915039" }, "linux": { - "uri": "sbr:7522714449" + "uri": "sbr:7570916388" }, "linux-aarch64": { - "uri": "sbr:7522712750" + "uri": "sbr:7570914495" }, "win32-clang-cl": { - "uri": "sbr:7522714072" + "uri": "sbr:7570915900" } } } diff --git a/build/external_resources/ymake/resources.json b/build/external_resources/ymake/resources.json index a3ccd61239e..de7de32951a 100644 --- a/build/external_resources/ymake/resources.json +++ b/build/external_resources/ymake/resources.json @@ -1,19 +1,19 @@ { "by_platform": { "darwin": { - "uri": "sbr:7522728679" + "uri": "sbr:7570909413" }, "darwin-arm64": { - "uri": "sbr:7522728262" + "uri": "sbr:7570909172" }, "linux": { - "uri": "sbr:7522729575" + "uri": "sbr:7570910246" }, "linux-aarch64": { - "uri": "sbr:7522727825" + "uri": "sbr:7570908880" }, "win32-clang-cl": { - "uri": "sbr:7522729138" + "uri": "sbr:7570909765" } } } diff --git a/build/mapping.conf.json b/build/mapping.conf.json index f555d8c72cf..e0f4f906c7e 100644 --- a/build/mapping.conf.json +++ b/build/mapping.conf.json @@ -624,6 +624,7 @@ "7448914799": "https://devtools-registry.s3.yandex.net/7448914799", "7478218557": "https://devtools-registry.s3.yandex.net/7478218557", "7522713648": "https://devtools-registry.s3.yandex.net/7522713648", + "7570915389": "https://devtools-registry.s3.yandex.net/7570915389", "5766171800": "https://devtools-registry.s3.yandex.net/5766171800", "5805430761": "https://devtools-registry.s3.yandex.net/5805430761", "5829025456": "https://devtools-registry.s3.yandex.net/5829025456", @@ -677,6 +678,7 @@ "7448913101": "https://devtools-registry.s3.yandex.net/7448913101", "7478218228": "https://devtools-registry.s3.yandex.net/7478218228", "7522713246": "https://devtools-registry.s3.yandex.net/7522713246", + "7570915039": "https://devtools-registry.s3.yandex.net/7570915039", "5766173070": "https://devtools-registry.s3.yandex.net/5766173070", "5805432830": "https://devtools-registry.s3.yandex.net/5805432830", "5829031598": "https://devtools-registry.s3.yandex.net/5829031598", @@ -730,6 +732,7 @@ "7448917907": "https://devtools-registry.s3.yandex.net/7448917907", "7478219259": "https://devtools-registry.s3.yandex.net/7478219259", "7522714449": "https://devtools-registry.s3.yandex.net/7522714449", + "7570916388": "https://devtools-registry.s3.yandex.net/7570916388", "5766171341": "https://devtools-registry.s3.yandex.net/5766171341", "5805430188": "https://devtools-registry.s3.yandex.net/5805430188", "5829023352": "https://devtools-registry.s3.yandex.net/5829023352", @@ -783,6 +786,7 @@ "7448911598": "https://devtools-registry.s3.yandex.net/7448911598", "7478218007": "https://devtools-registry.s3.yandex.net/7478218007", "7522712750": "https://devtools-registry.s3.yandex.net/7522712750", + "7570914495": "https://devtools-registry.s3.yandex.net/7570914495", "5766172695": "https://devtools-registry.s3.yandex.net/5766172695", "5805432230": "https://devtools-registry.s3.yandex.net/5805432230", "5829029743": "https://devtools-registry.s3.yandex.net/5829029743", @@ -836,6 +840,7 @@ "7448916360": "https://devtools-registry.s3.yandex.net/7448916360", "7478218861": "https://devtools-registry.s3.yandex.net/7478218861", "7522714072": "https://devtools-registry.s3.yandex.net/7522714072", + "7570915900": "https://devtools-registry.s3.yandex.net/7570915900", "4307890075": "https://devtools-registry.s3.yandex.net/4307890075", "5517245192": "https://devtools-registry.s3.yandex.net/5517245192", "4307901240": "https://devtools-registry.s3.yandex.net/4307901240", @@ -1690,6 +1695,7 @@ "7448914799": "devtools/ymake/bin/ymake for darwin", "7478218557": "devtools/ymake/bin/ymake for darwin", "7522713648": "devtools/ymake/bin/ymake for darwin", + "7570915389": "devtools/ymake/bin/ymake for darwin", "5766171800": "devtools/ymake/bin/ymake for darwin-arm64", "5805430761": "devtools/ymake/bin/ymake for darwin-arm64", "5829025456": "devtools/ymake/bin/ymake for darwin-arm64", @@ -1743,6 +1749,7 @@ "7448913101": "devtools/ymake/bin/ymake for darwin-arm64", "7478218228": "devtools/ymake/bin/ymake for darwin-arm64", "7522713246": "devtools/ymake/bin/ymake for darwin-arm64", + "7570915039": "devtools/ymake/bin/ymake for darwin-arm64", "5766173070": "devtools/ymake/bin/ymake for linux", "5805432830": "devtools/ymake/bin/ymake for linux", "5829031598": "devtools/ymake/bin/ymake for linux", @@ -1796,6 +1803,7 @@ "7448917907": "devtools/ymake/bin/ymake for linux", "7478219259": "devtools/ymake/bin/ymake for linux", "7522714449": "devtools/ymake/bin/ymake for linux", + "7570916388": "devtools/ymake/bin/ymake for linux", "5766171341": "devtools/ymake/bin/ymake for linux-aarch64", "5805430188": "devtools/ymake/bin/ymake for linux-aarch64", "5829023352": "devtools/ymake/bin/ymake for linux-aarch64", @@ -1849,6 +1857,7 @@ "7448911598": "devtools/ymake/bin/ymake for linux-aarch64", "7478218007": "devtools/ymake/bin/ymake for linux-aarch64", "7522712750": "devtools/ymake/bin/ymake for linux-aarch64", + "7570914495": "devtools/ymake/bin/ymake for linux-aarch64", "5766172695": "devtools/ymake/bin/ymake for win32-clang-cl", "5805432230": "devtools/ymake/bin/ymake for win32-clang-cl", "5829029743": "devtools/ymake/bin/ymake for win32-clang-cl", @@ -1902,6 +1911,7 @@ "7448916360": "devtools/ymake/bin/ymake for win32-clang-cl", "7478218861": "devtools/ymake/bin/ymake for win32-clang-cl", "7522714072": "devtools/ymake/bin/ymake for win32-clang-cl", + "7570915900": "devtools/ymake/bin/ymake for win32-clang-cl", "4307890075": "flake8_linter for linux", "5517245192": "flake8_linter for linux", "4307901240": "flake8_linter for linux-aarch64", diff --git a/build/platform/mold/mold.json b/build/platform/mold/mold.json new file mode 100644 index 00000000000..ee314b2a2e0 --- /dev/null +++ b/build/platform/mold/mold.json @@ -0,0 +1,16 @@ +{ + "by_platform": { + "darwin-arm64": { + "uri": "sbr:7421008516" + }, + "darwin-x86_64": { + "uri": "sbr:7421180051" + }, + "linux-aarch64": { + "uri": "sbr:7421207790" + }, + "linux-x86_64": { + "uri": "sbr:7421606584" + } + } +} diff --git a/build/platform/mold/ya.make b/build/platform/mold/ya.make new file mode 100644 index 00000000000..2d5f8cde455 --- /dev/null +++ b/build/platform/mold/ya.make @@ -0,0 +1,13 @@ +RESOURCES_LIBRARY() + +TOOLCHAIN(mold) +VERSION(2.34.1) + +DECLARE_EXTERNAL_HOST_RESOURCES_BUNDLE_BY_JSON(MOLD_ROOT mold.json) + +LDFLAGS( + -fuse-ld=mold + --ld-path=${MOLD_ROOT_RESOURCE_GLOBAL}/bin/ld.mold +) + +END() diff --git a/build/plugins/_dart_fields.py b/build/plugins/_dart_fields.py index aa1b5d9a161..eb5a0baa759 100644 --- a/build/plugins/_dart_fields.py +++ b/build/plugins/_dart_fields.py @@ -611,15 +611,37 @@ class LintConfigs: def cpp_configs(cls, unit, flat_args, spec_args): custom_config = spec_args.get('CUSTOM_CONFIG') if custom_config: + # TODO delete CUSTOM_CONFIG, it's used only by arc config = custom_config[0] assert_file_exists(unit, config) - else: - # file with default configs - config = spec_args.get('CONFIGS')[0] - assert_file_exists(unit, config) - name = spec_args['NAME'][0] - config = get_linter_configs(unit, config)[name] - assert_file_exists(unit, config) + return {cls.KEY: serialize_list([config])} + linter_name = spec_args['NAME'][0] + if config_type := spec_args.get('CONFIG_TYPE'): + config_type = config_type[0] + if config_type not in consts.LINTER_CONFIG_TYPES[linter_name]: + message = "Unknown CPP linter config type: {}. Allowed types: {}".format( + config_type, ', '.join(consts.LINTER_CONFIG_TYPES[linter_name]) + ) + ymake.report_configure_error(message) + raise DartValueError() + if common_configs_dir := unit.get('MODULE_COMMON_CONFIGS_DIR'): + config = os.path.join(common_configs_dir, config_type) + path = unit.resolve(config) + if os.path.exists(path): + config = _common.strip_roots(config) + return {cls.KEY: serialize_list([config])} + message = "File not found: {}".format(path) + ymake.report_configure_error(message) + raise DartValueError() + else: + message = "Config type specifier is only allowed with autoincludes" + ymake.report_configure_error(message) + raise DartValueError() + # default config + config = spec_args.get('CONFIGS')[0] + assert_file_exists(unit, config) + config = get_linter_configs(unit, config)[linter_name] + assert_file_exists(unit, config) return {cls.KEY: serialize_list([config])} diff --git a/build/plugins/lib/test_const/__init__.py b/build/plugins/lib/test_const/__init__.py index 02c3c5313ad..cc2536d6fed 100644 --- a/build/plugins/lib/test_const/__init__.py +++ b/build/plugins/lib/test_const/__init__.py @@ -437,6 +437,7 @@ class ServiceTags(Enum): AnyTag = "ya:anytag" +# Linter names must match `NAME` set in `_ADD_*_LINTER_CHECK` class PythonLinterName(Enum): Black = "black" DummyLinter = "dummy_linter" diff --git a/build/plugins/ytest.py b/build/plugins/ytest.py index 33eeac4403f..dd540baf829 100644 --- a/build/plugins/ytest.py +++ b/build/plugins/ytest.py @@ -1014,6 +1014,7 @@ def on_add_cpp_linter_check(fields, unit, *args): "GLOBAL_RESOURCES": unlimited, "FILE_PROCESSING_TIME": 1, "EXTRA_PARAMS": unlimited, + "CONFIG_TYPE": 1, } _, spec_args = _common.sort_by_keywords(keywords, args) diff --git a/build/sysincl/darwin.yml b/build/sysincl/darwin.yml index 06eaa50480f..d583225dfad 100644 --- a/build/sysincl/darwin.yml +++ b/build/sysincl/darwin.yml @@ -37,6 +37,7 @@ - MacTypes.h - TargetConditionals.h - architecture/byte_order.h + - arm/cpu_capabilities_public.h - asl.h - copyfile.h - crt_externs.h diff --git a/build/ymake.core.conf b/build/ymake.core.conf index 3fe44f55fe8..a2fa9450cca 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -2358,7 +2358,7 @@ multimodule PACKAGE { .USE_PEERS_LATE_OUTS=yes .PEERDIR_POLICY=as_build_from .FINAL_TARGET=yes - SET(PEERDIR_TAGS CPP_PROTO CPP_PROTO_FROM_SCHEMA CPP_FBS PY2 PY3 PY2_NATIVE PY3_NATIVE YQL_UDF_SHARED __EMPTY__ RESOURCE_LIB DOCSBOOK JAR_RUNNABLE PY3_BIN PY3TEST_PROGRAM DLL GO_PROGRAM PACKAGE_UNION) + SET(PEERDIR_TAGS CPP_PROTO CPP_PROTO_FROM_SCHEMA CPP_FBS PY2 PY3 PY2_NATIVE PY3_NATIVE YQL_UDF_SHARED __EMPTY__ RESOURCE_LIB DOCSBOOK JAR_RUNNABLE PY3_BIN PY3TEST_PROGRAM DLL GO_PROGRAM TS PACKAGE_UNION) SET(MODULE_SUFFIX .final.pkg.fake) SET(DONT_RESOLVE_INCLUDES yes) @@ -2376,7 +2376,7 @@ multimodule PACKAGE { .IGNORED=VCS_INFO_FILE SET(MODULE_SUFFIX .pkg.fake) - SET(PEERDIR_TAGS CPP_PROTO CPP_PROTO_FROM_SCHEMA CPP_FBS PY2 PY3 PY2_NATIVE PY3_NATIVE YQL_UDF_SHARED __EMPTY__ RESOURCE_LIB DOCSBOOK JAR_RUNNABLE PY3_BIN PY3TEST_PROGRAM DLL GO_PROGRAM PACKAGE_UNION) + SET(PEERDIR_TAGS CPP_PROTO CPP_PROTO_FROM_SCHEMA CPP_FBS PY2 PY3 PY2_NATIVE PY3_NATIVE YQL_UDF_SHARED __EMPTY__ RESOURCE_LIB DOCSBOOK JAR_RUNNABLE PY3_BIN PY3TEST_PROGRAM DLL GO_PROGRAM TS PACKAGE_UNION) DISABLE(START_TARGET) SET(_COPY_FILE_CONTEXT TEXT) @@ -2423,7 +2423,7 @@ module UNION: _BASE_UNIT { SET(MODULE_SUFFIX .pkg.fake) SET(DONT_RESOLVE_INCLUDES yes) SET(NEED_PLATFORM_PEERDIRS no) - PEERDIR_TAGS=CPP_PROTO CPP_PROTO_FROM_SCHEMA CPP_FBS PY2 PY2_NATIVE PY3_NATIVE YQL_UDF_SHARED __EMPTY__ RESOURCE_LIB DOCSBOOK JAR_RUNNABLE PY3_BIN DLL PACKAGE_UNION + PEERDIR_TAGS=CPP_PROTO CPP_PROTO_FROM_SCHEMA CPP_FBS PY2 PY2_NATIVE PY3_NATIVE YQL_UDF_SHARED __EMPTY__ RESOURCE_LIB DOCSBOOK JAR_RUNNABLE PY3_BIN DLL TS PACKAGE_UNION UNION_OUTS=${hide;late_out:AUTO_INPUT} when ($_UNION_EXPLICIT_OUTPUTS) { @@ -3125,9 +3125,26 @@ macro _SRC("ssqls", SRC, SRCFLAGS...) { .CMD=${tool:"metrika/core/tools/ssqls"} ${input;notransformbuilddir:SRC} -S $ARCADIA_ROOT -B $ARCADIA_BUILD_ROOT $SRCFLAGS ${output;noext;hide:SRC.cpp} ${output;noext;hide:SRC.h} ${hide;kv:"p SS"} ${hide;kv:"pc yellow"} } +macro _SRC_f_new(SRC, SRCFLAGS...) { + .CMD=${tool:"build/platform/flang"} -c ${input:SRC} -o ${output:SRC.o} ${hide;kv:"p FL"} ${hide;kv:"pc light-green"} +} + +macro _SRC_f_old(SRC, SRCFLAGS...) { + .CMD=$YMAKE_PYTHON ${input:"build/scripts/f2c.py"} -t ${tool:"contrib/tools/f2c"} -c ${input:SRC} -o ${output:SRC.c} ${hide;output_include:"f2c.h"} ${hide;kv:"p FT"} ${hide;kv:"pc light-green"} +} + +USE_FLANG=no + +when ($USE_FLANG == "yes") { + _SRC_FLANG=$_SRC_f_new($SRC, $SRCFLAGS) +} +otherwise { + _SRC_FLANG=$_SRC_f_old($SRC, $SRCFLAGS) +} + # tag:src-processing macro _SRC("f", SRC, SRCFLAGS...) { - .CMD=$YMAKE_PYTHON ${input:"build/scripts/f2c.py"} -t ${tool:"contrib/tools/f2c"} -c ${input:SRC} -o ${output:SRC.c} ${hide;output_include:"f2c.h"} ${hide;kv:"p FT"} ${hide;kv:"pc light-green"} + .CMD=$_SRC_FLANG .PEERDIR=contrib/libs/libf2c .ADDINCL=contrib/libs/libf2c } @@ -5837,7 +5854,7 @@ macro _STYLE_CPP(CONFIG...) { } # tag:internal -### @usage: _ADD_CPP_LINTER_CHECK(NAME name LINTER linter [DEPENDS deps] CONFIGS configs_file [GLOBAL_RESOURCES gr] [FILE_PROCESSING_TIME fpt] [EXTRA_PARAMS params] [CUSTOM_CONFIG cc]) +### @usage: _ADD_CPP_LINTER_CHECK(NAME name LINTER linter [DEPENDS deps] CONFIGS configs_file [GLOBAL_RESOURCES gr] [FILE_PROCESSING_TIME fpt] [EXTRA_PARAMS params] [CUSTOM_CONFIG cc] [CONFIG_TYPE ct]) ### ### Triggers respective plugin macro _ADD_CPP_LINTER_CHECK(Args...) { @@ -5847,12 +5864,12 @@ macro _ADD_CPP_LINTER_CHECK(Args...) { } # tag:test -### @usage STYLE_CPP() +### @usage STYLE_CPP([CONFIG_TYPE config_type]) ### ### Run 'ya tool clang-format' test on all cpp sources and headers of the current module -macro STYLE_CPP() { +macro STYLE_CPP(CONFIG_TYPE="") { .ALLOWED_IN_COMMON=yes - _ADD_CPP_LINTER_CHECK(NAME clang_format LINTER tools/cpp_style_checker/cpp_style_checker GLOBAL_RESOURCES build/platform/clang/clang-format CONFIGS $CPP_LINTERS_DEFAULT_CONFIGS) + _ADD_CPP_LINTER_CHECK(NAME clang_format LINTER tools/cpp_style_checker/cpp_style_checker GLOBAL_RESOURCES build/platform/clang/clang-format CONFIGS $CPP_LINTERS_DEFAULT_CONFIGS CONFIG_TYPE $CONFIG_TYPE) } ### @usage: HEADERS(<Dirs...> [EXCLUDE patterns...]) diff --git a/contrib/libs/clang14-rt/lib/asan/ya.make b/contrib/libs/clang14-rt/lib/asan/ya.make index 981e911a745..c3cd19e360f 100644 --- a/contrib/libs/clang14-rt/lib/asan/ya.make +++ b/contrib/libs/clang14-rt/lib/asan/ya.make @@ -15,8 +15,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - ADDINCL( contrib/libs/clang14-rt/lib ) diff --git a/contrib/libs/clang14-rt/lib/asan_cxx/ya.make b/contrib/libs/clang14-rt/lib/asan_cxx/ya.make index 9dad0117181..0d46e10dfe8 100644 --- a/contrib/libs/clang14-rt/lib/asan_cxx/ya.make +++ b/contrib/libs/clang14-rt/lib/asan_cxx/ya.make @@ -15,8 +15,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - ADDINCL( contrib/libs/clang14-rt/lib ) diff --git a/contrib/libs/clang14-rt/lib/asan_static/ya.make b/contrib/libs/clang14-rt/lib/asan_static/ya.make index f721a6a6e30..6339dbec829 100644 --- a/contrib/libs/clang14-rt/lib/asan_static/ya.make +++ b/contrib/libs/clang14-rt/lib/asan_static/ya.make @@ -15,8 +15,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - ADDINCL( contrib/libs/clang14-rt/lib ) diff --git a/contrib/libs/clang14-rt/lib/msan/ya.make b/contrib/libs/clang14-rt/lib/msan/ya.make index 67938fa41c0..25dfe3000e1 100644 --- a/contrib/libs/clang14-rt/lib/msan/ya.make +++ b/contrib/libs/clang14-rt/lib/msan/ya.make @@ -15,8 +15,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - ADDINCL( contrib/libs/clang14-rt/lib ) diff --git a/contrib/libs/clang14-rt/lib/msan_cxx/ya.make b/contrib/libs/clang14-rt/lib/msan_cxx/ya.make index af50884296f..ef8af1073f2 100644 --- a/contrib/libs/clang14-rt/lib/msan_cxx/ya.make +++ b/contrib/libs/clang14-rt/lib/msan_cxx/ya.make @@ -15,8 +15,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - ADDINCL( contrib/libs/clang14-rt/lib ) diff --git a/contrib/libs/clang14-rt/lib/tsan/ya.make b/contrib/libs/clang14-rt/lib/tsan/ya.make index 488aa06f7ac..f999fab5763 100644 --- a/contrib/libs/clang14-rt/lib/tsan/ya.make +++ b/contrib/libs/clang14-rt/lib/tsan/ya.make @@ -15,8 +15,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - ADDINCL( contrib/libs/clang14-rt/lib ) diff --git a/contrib/libs/clang14-rt/lib/tsan_cxx/ya.make b/contrib/libs/clang14-rt/lib/tsan_cxx/ya.make index 362b60067c3..d34ca6e4405 100644 --- a/contrib/libs/clang14-rt/lib/tsan_cxx/ya.make +++ b/contrib/libs/clang14-rt/lib/tsan_cxx/ya.make @@ -15,8 +15,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - ADDINCL( contrib/libs/clang14-rt/lib ) diff --git a/contrib/libs/clang18-rt/lib/asan/ya.make b/contrib/libs/clang18-rt/lib/asan/ya.make index df9c2230d8b..b73b1c80816 100644 --- a/contrib/libs/clang18-rt/lib/asan/ya.make +++ b/contrib/libs/clang18-rt/lib/asan/ya.make @@ -13,8 +13,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - VERSION(18.1.8) ADDINCL( diff --git a/contrib/libs/clang18-rt/lib/asan_cxx/ya.make b/contrib/libs/clang18-rt/lib/asan_cxx/ya.make index c3905d6faf0..08e0825cf1a 100644 --- a/contrib/libs/clang18-rt/lib/asan_cxx/ya.make +++ b/contrib/libs/clang18-rt/lib/asan_cxx/ya.make @@ -13,8 +13,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - VERSION(18.1.8) ADDINCL( diff --git a/contrib/libs/clang18-rt/lib/asan_static/ya.make b/contrib/libs/clang18-rt/lib/asan_static/ya.make index 89daf049d96..6187b6e8a78 100644 --- a/contrib/libs/clang18-rt/lib/asan_static/ya.make +++ b/contrib/libs/clang18-rt/lib/asan_static/ya.make @@ -13,8 +13,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - VERSION(18.1.8) ADDINCL( diff --git a/contrib/libs/clang18-rt/lib/msan/ya.make b/contrib/libs/clang18-rt/lib/msan/ya.make index 8089773feb2..54b50bfca3d 100644 --- a/contrib/libs/clang18-rt/lib/msan/ya.make +++ b/contrib/libs/clang18-rt/lib/msan/ya.make @@ -13,8 +13,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - VERSION(18.1.8) ADDINCL( diff --git a/contrib/libs/clang18-rt/lib/msan_cxx/ya.make b/contrib/libs/clang18-rt/lib/msan_cxx/ya.make index bc9beb80ec0..06bbcad52a3 100644 --- a/contrib/libs/clang18-rt/lib/msan_cxx/ya.make +++ b/contrib/libs/clang18-rt/lib/msan_cxx/ya.make @@ -13,8 +13,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - VERSION(18.1.8) ADDINCL( diff --git a/contrib/libs/clang18-rt/lib/profile/ya.make b/contrib/libs/clang18-rt/lib/profile/ya.make index 63ecb242140..685644c6804 100644 --- a/contrib/libs/clang18-rt/lib/profile/ya.make +++ b/contrib/libs/clang18-rt/lib/profile/ya.make @@ -13,8 +13,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - VERSION(18.1.8) ADDINCL( diff --git a/contrib/libs/clang18-rt/lib/tsan/ya.make b/contrib/libs/clang18-rt/lib/tsan/ya.make index 92ce585becd..6900ab53022 100644 --- a/contrib/libs/clang18-rt/lib/tsan/ya.make +++ b/contrib/libs/clang18-rt/lib/tsan/ya.make @@ -13,8 +13,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - VERSION(18.1.8) ADDINCL( diff --git a/contrib/libs/clang18-rt/lib/tsan_cxx/ya.make b/contrib/libs/clang18-rt/lib/tsan_cxx/ya.make index a752c10fb42..6739560227e 100644 --- a/contrib/libs/clang18-rt/lib/tsan_cxx/ya.make +++ b/contrib/libs/clang18-rt/lib/tsan_cxx/ya.make @@ -13,8 +13,6 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -SUBSCRIBER(g:cpp-contrib) - VERSION(18.1.8) ADDINCL( diff --git a/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym b/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym index 20967507889..e454ac162ac 100644 --- a/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym +++ b/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym @@ -1,6 +1,6 @@ {% extends '//builtin/bag.ym' %} -{% block current_version %}18.1.8{% endblock %} +{% block current_version %}19.1.3{% endblock %} {% block current_url %} https://github.com/llvm/llvm-project/releases/download/llvmorg-{{self.version().strip()}}/compiler-rt-{{self.version().strip()}}.src.tar.xz diff --git a/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report b/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report index ce8fb1f4bb7..874c592edd9 100644 --- a/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report +++ b/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report @@ -103,7 +103,9 @@ BELONGS ya.make aarch64/chkstk.S [1:2] aarch64/fp_mode.c [3:4] aarch64/sme-abi-init.c [1:2] + aarch64/sme-abi-vg.c [1:2] aarch64/sme-abi.S [1:2] + aarch64/sme-libc-mem-routines.S [1:2] absvdi2.c [3:4] absvsi2.c [3:4] absvti2.c [3:4] @@ -237,7 +239,9 @@ BELONGS ya.make comparedf2.c [3:4] comparesf2.c [3:4] comparetf2.c [3:4] + cpu_model/AArch64CPUFeatures.inc [3:4] cpu_model/aarch64.c [3:4] + cpu_model/aarch64.h [3:4] cpu_model/cpu_model.h [3:4] cpu_model/x86.c [3:4] crtbegin.c [3:4] @@ -261,6 +265,7 @@ BELONGS ya.make emutls.c [3:4] enable_execute_stack.c [3:4] eprintf.c [3:4] + extendbfsf2.c [3:4] extenddftf2.c [3:4] extendhfsf2.c [3:4] extendsfdf2.c [3:4] @@ -486,7 +491,9 @@ BELONGS ya.make aarch64/chkstk.S [1:2] aarch64/fp_mode.c [3:4] aarch64/sme-abi-init.c [1:2] + aarch64/sme-abi-vg.c [1:2] aarch64/sme-abi.S [1:2] + aarch64/sme-libc-mem-routines.S [1:2] absvdi2.c [3:4] absvsi2.c [3:4] absvti2.c [3:4] @@ -620,7 +627,9 @@ BELONGS ya.make comparedf2.c [3:4] comparesf2.c [3:4] comparetf2.c [3:4] + cpu_model/AArch64CPUFeatures.inc [3:4] cpu_model/aarch64.c [3:4] + cpu_model/aarch64.h [3:4] cpu_model/cpu_model.h [3:4] cpu_model/x86.c [3:4] crtbegin.c [3:4] @@ -644,6 +653,7 @@ BELONGS ya.make emutls.c [3:4] enable_execute_stack.c [3:4] eprintf.c [3:4] + extendbfsf2.c [3:4] extenddftf2.c [3:4] extendhfsf2.c [3:4] extendsfdf2.c [3:4] @@ -927,7 +937,9 @@ BELONGS ya.make aarch64/chkstk.S [3:3] aarch64/fp_mode.c [5:5] aarch64/sme-abi-init.c [3:3] + aarch64/sme-abi-vg.c [3:3] aarch64/sme-abi.S [3:3] + aarch64/sme-libc-mem-routines.S [3:3] absvdi2.c [5:5] absvsi2.c [5:5] absvti2.c [5:5] @@ -1061,7 +1073,9 @@ BELONGS ya.make comparedf2.c [5:5] comparesf2.c [5:5] comparetf2.c [5:5] + cpu_model/AArch64CPUFeatures.inc [5:5] cpu_model/aarch64.c [5:5] + cpu_model/aarch64.h [5:5] cpu_model/cpu_model.h [5:5] cpu_model/x86.c [5:5] crtbegin.c [5:5] @@ -1085,6 +1099,7 @@ BELONGS ya.make emutls.c [5:5] enable_execute_stack.c [5:5] eprintf.c [5:5] + extendbfsf2.c [5:5] extenddftf2.c [5:5] extendhfsf2.c [5:5] extendsfdf2.c [5:5] @@ -1310,7 +1325,9 @@ BELONGS ya.make aarch64/chkstk.S [3:3] aarch64/fp_mode.c [5:5] aarch64/sme-abi-init.c [3:3] + aarch64/sme-abi-vg.c [3:3] aarch64/sme-abi.S [3:3] + aarch64/sme-libc-mem-routines.S [3:3] absvdi2.c [5:5] absvsi2.c [5:5] absvti2.c [5:5] @@ -1444,7 +1461,9 @@ BELONGS ya.make comparedf2.c [5:5] comparesf2.c [5:5] comparetf2.c [5:5] + cpu_model/AArch64CPUFeatures.inc [5:5] cpu_model/aarch64.c [5:5] + cpu_model/aarch64.h [5:5] cpu_model/cpu_model.h [5:5] cpu_model/x86.c [5:5] crtbegin.c [5:5] @@ -1468,6 +1487,7 @@ BELONGS ya.make emutls.c [5:5] enable_execute_stack.c [5:5] eprintf.c [5:5] + extendbfsf2.c [5:5] extenddftf2.c [5:5] extendhfsf2.c [5:5] extendsfdf2.c [5:5] diff --git a/contrib/libs/cxxsupp/builtins/CODE_OWNERS.TXT b/contrib/libs/cxxsupp/builtins/CODE_OWNERS.TXT index ad136edf967..bd51a1073cc 100644 --- a/contrib/libs/cxxsupp/builtins/CODE_OWNERS.TXT +++ b/contrib/libs/cxxsupp/builtins/CODE_OWNERS.TXT @@ -67,3 +67,11 @@ D: ThreadSanitizer N: Bill Wendling D: Profile runtime library + +N: Christopher Apple, David Trevelyan +D: Realtime Sanitizer (RTSan) + +N: Alexander Shaposhnikov +D: Numerical Sanitizer (NSAN) diff --git a/contrib/libs/cxxsupp/builtins/README.txt b/contrib/libs/cxxsupp/builtins/README.txt index 2d213d95f33..19f26c92a0f 100644 --- a/contrib/libs/cxxsupp/builtins/README.txt +++ b/contrib/libs/cxxsupp/builtins/README.txt @@ -272,6 +272,11 @@ switch32 switch8 switchu8 +// This function generates a custom trampoline function with the specific +// realFunc and localsPtr values. +void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated, + const void* realFunc, void* localsPtr); + // There is no C interface to the *_vfp_d8_d15_regs functions. There are // called in the prolog and epilog of Thumb1 functions. When the C++ ABI use // SJLJ for exceptions, each function with a catch clause or destructors needs diff --git a/contrib/libs/cxxsupp/builtins/aarch64/sme-abi-vg.c b/contrib/libs/cxxsupp/builtins/aarch64/sme-abi-vg.c new file mode 100644 index 00000000000..20061012e16 --- /dev/null +++ b/contrib/libs/cxxsupp/builtins/aarch64/sme-abi-vg.c @@ -0,0 +1,21 @@ +// 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 + +#include "../cpu_model/aarch64.h" + +struct FEATURES { + unsigned long long features; +}; + +extern struct FEATURES __aarch64_cpu_features; + +#if __GNUC__ >= 9 +#pragma GCC diagnostic ignored "-Wprio-ctor-dtor" +#endif +__attribute__((constructor(90))) static void get_aarch64_cpu_features(void) { + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) + return; + + __init_cpu_features(); +} diff --git a/contrib/libs/cxxsupp/builtins/aarch64/sme-abi.S b/contrib/libs/cxxsupp/builtins/aarch64/sme-abi.S index d470ecaf7aa..cd8153f6067 100644 --- a/contrib/libs/cxxsupp/builtins/aarch64/sme-abi.S +++ b/contrib/libs/cxxsupp/builtins/aarch64/sme-abi.S @@ -12,11 +12,15 @@ #if !defined(__APPLE__) #define TPIDR2_SYMBOL SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0) #define TPIDR2_SYMBOL_OFFSET :lo12:SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0) +#define CPU_FEATS_SYMBOL SYMBOL_NAME(__aarch64_cpu_features) +#define CPU_FEATS_SYMBOL_OFFSET :lo12:SYMBOL_NAME(__aarch64_cpu_features) #else // MachO requires @page/@pageoff directives because the global is defined // in a different file. Otherwise this file may fail to build. #define TPIDR2_SYMBOL SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)@page #define TPIDR2_SYMBOL_OFFSET SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)@pageoff +#define CPU_FEATS_SYMBOL SYMBOL_NAME(__aarch64_cpu_features)@page +#define CPU_FEATS_SYMBOL_OFFSET SYMBOL_NAME(__aarch64_cpu_features)@pageoff #endif .arch armv9-a+sme @@ -26,9 +30,10 @@ // abort(). Note that there is no need to preserve any state before the call, // because the function does not return. DEFINE_COMPILERRT_PRIVATE_FUNCTION(do_abort) -.cfi_startproc - .variant_pcs SYMBOL_NAME(do_abort) - stp x29, x30, [sp, #-32]! + .cfi_startproc + .variant_pcs SYMBOL_NAME(do_abort) + BTI_C + stp x29, x30, [sp, #-32]! cntd x0 // Store VG to a stack location that we describe with .cfi_offset str x0, [sp, #16] @@ -36,22 +41,23 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(do_abort) .cfi_offset w30, -24 .cfi_offset w29, -32 .cfi_offset 46, -16 - bl __arm_sme_state - tbz x0, #0, 2f + bl __arm_sme_state + tbz x0, #0, 2f 1: - smstop sm + smstop sm 2: // We can't make this into a tail-call because the unwinder would // need to restore the value of VG. - bl SYMBOL_NAME(abort) -.cfi_endproc + bl SYMBOL_NAME(abort) + .cfi_endproc END_COMPILERRT_FUNCTION(do_abort) // __arm_sme_state fills the result registers based on a local // that is set as part of the compiler-rt startup code. // __aarch64_has_sme_and_tpidr2_el0 DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sme_state) - .variant_pcs __arm_sme_state + .variant_pcs __arm_sme_state + BTI_C mov x0, xzr mov x1, xzr @@ -68,7 +74,8 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sme_state) END_COMPILERRT_OUTLINE_FUNCTION(__arm_sme_state) DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_restore) - .variant_pcs __arm_tpidr2_restore + .variant_pcs __arm_tpidr2_restore + BTI_C // If TPIDR2_EL0 is nonnull, the subroutine aborts in some platform-specific // manner. mrs x14, TPIDR2_EL0 @@ -103,7 +110,8 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_restore) END_COMPILERRT_OUTLINE_FUNCTION(__arm_tpidr2_restore) DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_save) - .variant_pcs __arm_tpidr2_restore + .variant_pcs __arm_tpidr2_restore + BTI_C // If the current thread does not have access to TPIDR2_EL0, the subroutine // does nothing. adrp x14, TPIDR2_SYMBOL @@ -143,7 +151,8 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_save) END_COMPILERRT_OUTLINE_FUNCTION(__arm_tpidr2_save) DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable) - .variant_pcs __arm_tpidr2_restore + .variant_pcs __arm_tpidr2_restore + BTI_C // If the current thread does not have access to SME, the subroutine does // nothing. adrp x14, TPIDR2_SYMBOL @@ -174,3 +183,48 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable) 0: ret END_COMPILERRT_OUTLINE_FUNCTION(__arm_za_disable) + +DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_get_current_vg) + .variant_pcs __arm_get_current_vg + BTI_C + + stp x29, x30, [sp, #-16]! + .cfi_def_cfa_offset 16 + mov x29, sp + .cfi_def_cfa w29, 16 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + adrp x17, CPU_FEATS_SYMBOL + ldr w17, [x17, CPU_FEATS_SYMBOL_OFFSET] + tbnz w17, #30, 0f + adrp x16, TPIDR2_SYMBOL + ldrb w16, [x16, TPIDR2_SYMBOL_OFFSET] + cbz w16, 1f +0: + mov x18, x1 + bl __arm_sme_state + mov x1, x18 + and x17, x17, #0x40000000 + bfxil x17, x0, #0, #1 + cbz x17, 1f + cntd x0 + .cfi_def_cfa wsp, 16 + ldp x29, x30, [sp], #16 + .cfi_def_cfa_offset 0 + .cfi_restore w30 + .cfi_restore w29 + ret +1: + mov x0, xzr + .cfi_def_cfa wsp, 16 + ldp x29, x30, [sp], #16 + .cfi_def_cfa_offset 0 + .cfi_restore w30 + .cfi_restore w29 + ret +END_COMPILERRT_OUTLINE_FUNCTION(__arm_get_current_vg) + +NO_EXEC_STACK_DIRECTIVE + +// GNU property note for BTI and PAC +GNU_PROPERTY_BTI_PAC diff --git a/contrib/libs/cxxsupp/builtins/aarch64/sme-libc-mem-routines.S b/contrib/libs/cxxsupp/builtins/aarch64/sme-libc-mem-routines.S new file mode 100644 index 00000000000..0318d9a6f1e --- /dev/null +++ b/contrib/libs/cxxsupp/builtins/aarch64/sme-libc-mem-routines.S @@ -0,0 +1,352 @@ +// 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 + +// Routines taken from libc/AOR_v20.02/string/aarch64 + +#include "../assembly.h" + +#ifdef __aarch64__ + +#define L(l) .L ## l + +// +// __arm_sc_memcpy / __arm_sc_memmove +// + +#define dstin x0 +#define src x1 +#define count x2 +#define dst x3 +#define srcend1 x4 +#define dstend1 x5 +#define A_l x6 +#define A_lw w6 +#define A_h x7 +#define B_l x8 +#define B_lw w8 +#define B_h x9 +#define C_l x10 +#define C_lw w10 +#define C_h x11 +#define D_l x12 +#define D_h x13 +#define E_l x14 +#define E_h x15 +#define F_l x16 +#define F_h x17 +#define G_l count +#define G_h dst +#define H_l src +#define H_h srcend1 +#define tmp1 x14 + +/* This implementation handles overlaps and supports both memcpy and memmove + from a single entry point. It uses unaligned accesses and branchless + sequences to keep the code small, simple and improve performance. + + Copies are split into 3 main cases: small copies of up to 32 bytes, medium + copies of up to 128 bytes, and large copies. The overhead of the overlap + check is negligible since it is only required for large copies. + + Large copies use a software pipelined loop processing 64 bytes per iteration. + The destination pointer is 16-byte aligned to minimize unaligned accesses. + The loop tail is handled by always copying 64 bytes from the end. +*/ + +DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memcpy) + add srcend1, src, count + add dstend1, dstin, count + cmp count, 128 + b.hi L(copy_long) + cmp count, 32 + b.hi L(copy32_128) + + /* Small copies: 0..32 bytes. */ + cmp count, 16 + b.lo L(copy16) + ldp A_l, A_h, [src] + ldp D_l, D_h, [srcend1, -16] + stp A_l, A_h, [dstin] + stp D_l, D_h, [dstend1, -16] + ret + + /* Copy 8-15 bytes. */ +L(copy16): + tbz count, 3, L(copy8) + ldr A_l, [src] + ldr A_h, [srcend1, -8] + str A_l, [dstin] + str A_h, [dstend1, -8] + ret + + .p2align 3 + /* Copy 4-7 bytes. */ +L(copy8): + tbz count, 2, L(copy4) + ldr A_lw, [src] + ldr B_lw, [srcend1, -4] + str A_lw, [dstin] + str B_lw, [dstend1, -4] + ret + + /* Copy 0..3 bytes using a branchless sequence. */ +L(copy4): + cbz count, L(copy0) + lsr tmp1, count, 1 + ldrb A_lw, [src] + ldrb C_lw, [srcend1, -1] + ldrb B_lw, [src, tmp1] + strb A_lw, [dstin] + strb B_lw, [dstin, tmp1] + strb C_lw, [dstend1, -1] +L(copy0): + ret + + .p2align 4 + /* Medium copies: 33..128 bytes. */ +L(copy32_128): + ldp A_l, A_h, [src] + ldp B_l, B_h, [src, 16] + ldp C_l, C_h, [srcend1, -32] + ldp D_l, D_h, [srcend1, -16] + cmp count, 64 + b.hi L(copy128) + stp A_l, A_h, [dstin] + stp B_l, B_h, [dstin, 16] + stp C_l, C_h, [dstend1, -32] + stp D_l, D_h, [dstend1, -16] + ret + + .p2align 4 + /* Copy 65..128 bytes. */ +L(copy128): + ldp E_l, E_h, [src, 32] + ldp F_l, F_h, [src, 48] + cmp count, 96 + b.ls L(copy96) + ldp G_l, G_h, [srcend1, -64] + ldp H_l, H_h, [srcend1, -48] + stp G_l, G_h, [dstend1, -64] + stp H_l, H_h, [dstend1, -48] +L(copy96): + stp A_l, A_h, [dstin] + stp B_l, B_h, [dstin, 16] + stp E_l, E_h, [dstin, 32] + stp F_l, F_h, [dstin, 48] + stp C_l, C_h, [dstend1, -32] + stp D_l, D_h, [dstend1, -16] + ret + + .p2align 4 + /* Copy more than 128 bytes. */ +L(copy_long): + /* Use backwards copy if there is an overlap. */ + sub tmp1, dstin, src + cbz tmp1, L(copy0) + cmp tmp1, count + b.lo L(copy_long_backwards) + + /* Copy 16 bytes and then align dst to 16-byte alignment. */ + + ldp D_l, D_h, [src] + and tmp1, dstin, 15 + bic dst, dstin, 15 + sub src, src, tmp1 + add count, count, tmp1 /* Count is now 16 too large. */ + ldp A_l, A_h, [src, 16] + stp D_l, D_h, [dstin] + ldp B_l, B_h, [src, 32] + ldp C_l, C_h, [src, 48] + ldp D_l, D_h, [src, 64]! + subs count, count, 128 + 16 /* Test and readjust count. */ + b.ls L(copy64_from_end) +L(loop64): + stp A_l, A_h, [dst, 16] + ldp A_l, A_h, [src, 16] + stp B_l, B_h, [dst, 32] + ldp B_l, B_h, [src, 32] + stp C_l, C_h, [dst, 48] + ldp C_l, C_h, [src, 48] + stp D_l, D_h, [dst, 64]! + ldp D_l, D_h, [src, 64]! + subs count, count, 64 + b.hi L(loop64) + + /* Write the last iteration and copy 64 bytes from the end. */ +L(copy64_from_end): + ldp E_l, E_h, [srcend1, -64] + stp A_l, A_h, [dst, 16] + ldp A_l, A_h, [srcend1, -48] + stp B_l, B_h, [dst, 32] + ldp B_l, B_h, [srcend1, -32] + stp C_l, C_h, [dst, 48] + ldp C_l, C_h, [srcend1, -16] + stp D_l, D_h, [dst, 64] + stp E_l, E_h, [dstend1, -64] + stp A_l, A_h, [dstend1, -48] + stp B_l, B_h, [dstend1, -32] + stp C_l, C_h, [dstend1, -16] + ret + + .p2align 4 + + /* Large backwards copy for overlapping copies. + Copy 16 bytes and then align dst to 16-byte alignment. */ +L(copy_long_backwards): + ldp D_l, D_h, [srcend1, -16] + and tmp1, dstend1, 15 + sub srcend1, srcend1, tmp1 + sub count, count, tmp1 + ldp A_l, A_h, [srcend1, -16] + stp D_l, D_h, [dstend1, -16] + ldp B_l, B_h, [srcend1, -32] + ldp C_l, C_h, [srcend1, -48] + ldp D_l, D_h, [srcend1, -64]! + sub dstend1, dstend1, tmp1 + subs count, count, 128 + b.ls L(copy64_from_start) + +L(loop64_backwards): + stp A_l, A_h, [dstend1, -16] + ldp A_l, A_h, [srcend1, -16] + stp B_l, B_h, [dstend1, -32] + ldp B_l, B_h, [srcend1, -32] + stp C_l, C_h, [dstend1, -48] + ldp C_l, C_h, [srcend1, -48] + stp D_l, D_h, [dstend1, -64]! + ldp D_l, D_h, [srcend1, -64]! + subs count, count, 64 + b.hi L(loop64_backwards) + + /* Write the last iteration and copy 64 bytes from the start. */ +L(copy64_from_start): + ldp G_l, G_h, [src, 48] + stp A_l, A_h, [dstend1, -16] + ldp A_l, A_h, [src, 32] + stp B_l, B_h, [dstend1, -32] + ldp B_l, B_h, [src, 16] + stp C_l, C_h, [dstend1, -48] + ldp C_l, C_h, [src] + stp D_l, D_h, [dstend1, -64] + stp G_l, G_h, [dstin, 48] + stp A_l, A_h, [dstin, 32] + stp B_l, B_h, [dstin, 16] + stp C_l, C_h, [dstin] + ret +END_COMPILERRT_OUTLINE_FUNCTION(__arm_sc_memcpy) + +DEFINE_COMPILERRT_FUNCTION_ALIAS(__arm_sc_memmove, __arm_sc_memcpy) + + +// +// __arm_sc_memset +// + +#define dstin x0 +#define val x1 +#define valw w1 +#define count x2 +#define dst x3 +#define dstend2 x4 +#define zva_val x5 + +DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memset) +#ifdef __ARM_FEATURE_SVE + mov z0.b, valw +#else + bfi valw, valw, #8, #8 + bfi valw, valw, #16, #16 + bfi val, val, #32, #32 + fmov d0, val + fmov v0.d[1], val +#endif + add dstend2, dstin, count + + cmp count, 96 + b.hi L(set_long) + cmp count, 16 + b.hs L(set_medium) + mov val, v0.D[0] + + /* Set 0..15 bytes. */ + tbz count, 3, 1f + str val, [dstin] + str val, [dstend2, -8] + ret + nop +1: tbz count, 2, 2f + str valw, [dstin] + str valw, [dstend2, -4] + ret +2: cbz count, 3f + strb valw, [dstin] + tbz count, 1, 3f + strh valw, [dstend2, -2] +3: ret + + /* Set 17..96 bytes. */ +L(set_medium): + str q0, [dstin] + tbnz count, 6, L(set96) + str q0, [dstend2, -16] + tbz count, 5, 1f + str q0, [dstin, 16] + str q0, [dstend2, -32] +1: ret + + .p2align 4 + /* Set 64..96 bytes. Write 64 bytes from the start and + 32 bytes from the end. */ +L(set96): + str q0, [dstin, 16] + stp q0, q0, [dstin, 32] + stp q0, q0, [dstend2, -32] + ret + + .p2align 4 +L(set_long): + and valw, valw, 255 + bic dst, dstin, 15 + str q0, [dstin] + cmp count, 160 + ccmp valw, 0, 0, hs + b.ne L(no_zva) + +#ifndef SKIP_ZVA_CHECK + mrs zva_val, dczid_el0 + and zva_val, zva_val, 31 + cmp zva_val, 4 /* ZVA size is 64 bytes. */ + b.ne L(no_zva) +#endif + str q0, [dst, 16] + stp q0, q0, [dst, 32] + bic dst, dst, 63 + sub count, dstend2, dst /* Count is now 64 too large. */ + sub count, count, 128 /* Adjust count and bias for loop. */ + + .p2align 4 +L(zva_loop): + add dst, dst, 64 + dc zva, dst + subs count, count, 64 + b.hi L(zva_loop) + stp q0, q0, [dstend2, -64] + stp q0, q0, [dstend2, -32] + ret + +L(no_zva): + sub count, dstend2, dst /* Count is 16 too large. */ + sub dst, dst, 16 /* Dst is biased by -32. */ + sub count, count, 64 + 16 /* Adjust count and bias for loop. */ +L(no_zva_loop): + stp q0, q0, [dst, 32] + stp q0, q0, [dst, 64]! + subs count, count, 64 + b.hi L(no_zva_loop) + stp q0, q0, [dstend2, -64] + stp q0, q0, [dstend2, -32] + ret +END_COMPILERRT_OUTLINE_FUNCTION(__arm_sc_memset) + +#endif // __aarch64__ diff --git a/contrib/libs/cxxsupp/builtins/aarch64/sme-libc-routines.c b/contrib/libs/cxxsupp/builtins/aarch64/sme-libc-routines.c index cd73025a19c..315490e73ea 100644 --- a/contrib/libs/cxxsupp/builtins/aarch64/sme-libc-routines.c +++ b/contrib/libs/cxxsupp/builtins/aarch64/sme-libc-routines.c @@ -1,79 +1,4 @@ -#include <stdlib.h> - -// WARNING: When building the scalar versions of these functions you need to -// use the compiler flag "-mllvm -disable-loop-idiom-all" to prevent clang -// from recognising a loop idiom and planting calls to memcpy! - -static void *__arm_sc_memcpy_fwd(void *dest, const void *src, - size_t n) __arm_streaming_compatible { - unsigned char *destp = (unsigned char *)dest; - const unsigned char *srcp = (const unsigned char *)src; - for (size_t i = 0; i < n; ++i) - destp[i] = srcp[i]; - - return dest; -} - -// If dest and src overlap then behaviour is undefined, hence we can add the -// restrict keywords here. This also matches the definition of the libc memcpy -// according to the man page. -void *__arm_sc_memcpy(void *__restrict__ dest, const void *__restrict__ src, - size_t n) __arm_streaming_compatible { - return __arm_sc_memcpy_fwd(dest, src, n); -} - -void *__arm_sc_memset(void *dest, int c, size_t n) __arm_streaming_compatible { - unsigned char *destp = (unsigned char *)dest; - unsigned char c8 = (unsigned char)c; - for (size_t i = 0; i < n; ++i) - destp[i] = c8; - - return dest; -} - -static void *__arm_sc_memcpy_rev(void *dest, const void *src, - size_t n) __arm_streaming_compatible { - unsigned char *destp = (unsigned char *)dest; - const unsigned char *srcp = (const unsigned char *)src; - // TODO: Improve performance by copying larger chunks in reverse, or by - // using SVE. - while (n > 0) { - --n; - destp[n] = srcp[n]; - } - return dest; -} - -// Semantically a memmove is equivalent to the following: -// 1. Copy the entire contents of src to a temporary array that does not -// overlap with src or dest. -// 2. Copy the contents of the temporary array into dest. -void *__arm_sc_memmove(void *dest, const void *src, - size_t n) __arm_streaming_compatible { - unsigned char *destp = (unsigned char *)dest; - const unsigned char *srcp = (const unsigned char *)src; - - // If src and dest don't overlap then just invoke memcpy - if ((srcp > (destp + n)) || (destp > (srcp + n))) - return __arm_sc_memcpy_fwd(dest, src, n); - - // Overlap case 1: - // src: Low | -> | High - // dest: Low | -> | High - // Here src is always ahead of dest at a higher addres. If we first read a - // chunk of data from src we can safely write the same chunk to dest without - // corrupting future reads of src. - if (srcp > destp) - return __arm_sc_memcpy_fwd(dest, src, n); - - // Overlap case 2: - // src: Low | -> | High - // dest: Low | -> | High - // While we're in the overlap region we're always corrupting future reads of - // src when writing to dest. An efficient way to do this is to copy the data - // in reverse by starting at the highest address. - return __arm_sc_memcpy_rev(dest, src, n); -} +#include <stddef.h> const void *__arm_sc_memchr(const void *src, int c, size_t n) __arm_streaming_compatible { diff --git a/contrib/libs/cxxsupp/builtins/atomic.c b/contrib/libs/cxxsupp/builtins/atomic.c index 852bb20f086..aded25d9baa 100644 --- a/contrib/libs/cxxsupp/builtins/atomic.c +++ b/contrib/libs/cxxsupp/builtins/atomic.c @@ -12,7 +12,7 @@ // // 1) This code must work with C programs that do not link to anything // (including pthreads) and so it should not depend on any pthread -// functions. +// functions. If the user wishes to opt into using pthreads, they may do so. // 2) Atomic operations, rather than explicit mutexes, are most commonly used // on code where contended operations are rate. // @@ -56,7 +56,17 @@ static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1; // defined. Each platform should define the Lock type, and corresponding // lock() and unlock() functions. //////////////////////////////////////////////////////////////////////////////// -#if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(_LIBATOMIC_USE_PTHREAD) +#include <pthread.h> +typedef pthread_mutex_t Lock; +/// Unlock a lock. This is a release operation. +__inline static void unlock(Lock *l) { pthread_mutex_unlock(l); } +/// Locks a lock. +__inline static void lock(Lock *l) { pthread_mutex_lock(l); } +/// locks for atomic operations +static Lock locks[SPINLOCK_COUNT]; + +#elif defined(__FreeBSD__) || defined(__DragonFly__) #include <errno.h> // clang-format off #include <sys/types.h> diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/AArch64CPUFeatures.inc b/contrib/libs/cxxsupp/builtins/cpu_model/AArch64CPUFeatures.inc new file mode 100644 index 00000000000..e78bb88cfed --- /dev/null +++ b/contrib/libs/cxxsupp/builtins/cpu_model/AArch64CPUFeatures.inc @@ -0,0 +1,91 @@ +//===- AArch64CPUFeatures.inc - AArch64 CPU Features enum -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the CPUFeatures enum for AArch64 to facilitate better +// testing of this code between LLVM and compiler-rt, primarily that the files +// are an exact match. +// +// This file has two identical copies. The primary copy lives in LLVM and +// the other one sits in compiler-rt/lib/builtins/cpu_model directory. To make +// changes in this file, first modify the primary copy and copy it over to +// compiler-rt. compiler-rt tests will fail if the two files are not synced up. +// +//===----------------------------------------------------------------------===// + +#ifndef AARCH64_CPU_FEATURS_INC_H +#define AARCH64_CPU_FEATURS_INC_H + +// Function Multi Versioning CPU features. +enum CPUFeatures { + FEAT_RNG, + FEAT_FLAGM, + FEAT_FLAGM2, + FEAT_FP16FML, + FEAT_DOTPROD, + FEAT_SM4, + FEAT_RDM, + FEAT_LSE, + FEAT_FP, + FEAT_SIMD, + FEAT_CRC, + FEAT_SHA1, + FEAT_SHA2, + FEAT_SHA3, + FEAT_AES, + FEAT_PMULL, + FEAT_FP16, + FEAT_DIT, + FEAT_DPB, + FEAT_DPB2, + FEAT_JSCVT, + FEAT_FCMA, + FEAT_RCPC, + FEAT_RCPC2, + FEAT_FRINTTS, + FEAT_DGH, + FEAT_I8MM, + FEAT_BF16, + FEAT_EBF16, + FEAT_RPRES, + FEAT_SVE, + FEAT_SVE_BF16, + FEAT_SVE_EBF16, + FEAT_SVE_I8MM, + FEAT_SVE_F32MM, + FEAT_SVE_F64MM, + FEAT_SVE2, + FEAT_SVE_AES, + FEAT_SVE_PMULL128, + FEAT_SVE_BITPERM, + FEAT_SVE_SHA3, + FEAT_SVE_SM4, + FEAT_SME, + FEAT_MEMTAG, + FEAT_MEMTAG2, + FEAT_MEMTAG3, + FEAT_SB, + FEAT_PREDRES, + FEAT_SSBS, + FEAT_SSBS2, + FEAT_BTI, + FEAT_LS64, + FEAT_LS64_V, + FEAT_LS64_ACCDATA, + FEAT_WFXT, + FEAT_SME_F64, + FEAT_SME_I64, + FEAT_SME2, + FEAT_RCPC3, + FEAT_MOPS, + FEAT_MAX, + FEAT_EXT = 62, // Reserved to indicate presence of additional features field + // in __aarch64_cpu_features + FEAT_INIT // Used as flag of features initialization completion +}; + +#endif diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64.c b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64.c index 17bddfca46f..b868caa991b 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64.c +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64.c @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "cpu_model.h" +#include "aarch64.h" #if !defined(__aarch64__) #error This file is intended only for aarch64-based targets @@ -53,74 +53,6 @@ _Bool __aarch64_have_lse_atomics #endif #if !defined(DISABLE_AARCH64_FMV) -// CPUFeatures must correspond to the same AArch64 features in -// AArch64TargetParser.h -enum CPUFeatures { - FEAT_RNG, - FEAT_FLAGM, - FEAT_FLAGM2, - FEAT_FP16FML, - FEAT_DOTPROD, - FEAT_SM4, - FEAT_RDM, - FEAT_LSE, - FEAT_FP, - FEAT_SIMD, - FEAT_CRC, - FEAT_SHA1, - FEAT_SHA2, - FEAT_SHA3, - FEAT_AES, - FEAT_PMULL, - FEAT_FP16, - FEAT_DIT, - FEAT_DPB, - FEAT_DPB2, - FEAT_JSCVT, - FEAT_FCMA, - FEAT_RCPC, - FEAT_RCPC2, - FEAT_FRINTTS, - FEAT_DGH, - FEAT_I8MM, - FEAT_BF16, - FEAT_EBF16, - FEAT_RPRES, - FEAT_SVE, - FEAT_SVE_BF16, - FEAT_SVE_EBF16, - FEAT_SVE_I8MM, - FEAT_SVE_F32MM, - FEAT_SVE_F64MM, - FEAT_SVE2, - FEAT_SVE_AES, - FEAT_SVE_PMULL128, - FEAT_SVE_BITPERM, - FEAT_SVE_SHA3, - FEAT_SVE_SM4, - FEAT_SME, - FEAT_MEMTAG, - FEAT_MEMTAG2, - FEAT_MEMTAG3, - FEAT_SB, - FEAT_PREDRES, - FEAT_SSBS, - FEAT_SSBS2, - FEAT_BTI, - FEAT_LS64, - FEAT_LS64_V, - FEAT_LS64_ACCDATA, - FEAT_WFXT, - FEAT_SME_F64, - FEAT_SME_I64, - FEAT_SME2, - FEAT_RCPC3, - FEAT_MOPS, - FEAT_MAX, - FEAT_EXT = 62, // Reserved to indicate presence of additional features field - // in __aarch64_cpu_features - FEAT_INIT // Used as flag of features initialization completion -}; // Architecture features used // in Function Multi Versioning diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64.h b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64.h new file mode 100644 index 00000000000..f6cbf75d582 --- /dev/null +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64.h @@ -0,0 +1,21 @@ +//===-- cpu_model/aarch64.h --------------------------------------------- -===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "cpu_model.h" + +#if !defined(__aarch64__) +#error This file is intended only for aarch64-based targets +#endif + +#if !defined(DISABLE_AARCH64_FMV) + +#include "AArch64CPUFeatures.inc" + +void __init_cpu_features(void); + +#endif // !defined(DISABLE_AARCH64_FMV) diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/android.inc b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/android.inc index f711431489c..a9e3594e93c 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/android.inc +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/android.inc @@ -1,6 +1,6 @@ void __init_cpu_features_resolver(unsigned long hwcap, const __ifunc_arg_t *arg) { - if (__aarch64_cpu_features.features) + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) return; // ifunc resolvers don't have hwcaps in arguments on Android API lower @@ -17,7 +17,7 @@ void __init_cpu_features_resolver(unsigned long hwcap, void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) { // CPU features already initialized. - if (__aarch64_cpu_features.features) + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) return; // Don't set any CPU features, diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/apple.inc b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/apple.inc index 0bb755f4b30..f0694900f23 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/apple.inc +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/apple.inc @@ -1,8 +1,27 @@ #include <TargetConditionals.h> #if TARGET_OS_OSX || TARGET_OS_IPHONE -#include <dispatch/dispatch.h> #include <sys/sysctl.h> +#if __has_include(<arm/cpu_capabilities_public.h>) +#include <arm/cpu_capabilities_public.h> +#define HAS_CPU_CAPABILITIES_PUBLIC_H 1 + +// FB13964283 - A few of these didn't make it into the public SDK yet. +#ifndef CAP_BIT_FEAT_SME +#define CAP_BIT_FEAT_SME 40 +#endif +#ifndef CAP_BIT_FEAT_SME2 +#define CAP_BIT_FEAT_SME2 41 +#endif +#ifndef CAP_BIT_FEAT_SME_F64F64 +#define CAP_BIT_FEAT_SME_F64F64 42 +#endif +#ifndef CAP_BIT_FEAT_SME_I16I64 +#define CAP_BIT_FEAT_SME_I16I64 43 +#endif + +#endif + static bool isKnownAndSupported(const char *name) { int32_t val = 0; size_t size = sizeof(val); @@ -11,61 +30,130 @@ static bool isKnownAndSupported(const char *name) { return val; } +static uint64_t deriveImplicitFeatures(uint64_t features) { + // FEAT_SSBS2 implies FEAT_SSBS + if ((1ULL << FEAT_SSBS2) & features) + features |= (1ULL << FEAT_SSBS); + + // FEAT_FP is always enabled + features |= (1ULL << FEAT_FP); + + features |= (1ULL << FEAT_INIT); + + return features; +} + void __init_cpu_features_resolver(void) { // On Darwin platforms, this may be called concurrently by multiple threads // because the resolvers that use it are called lazily at runtime (unlike on // ELF platforms, where IFuncs are resolved serially at load time). This // function's effect on __aarch64_cpu_features must be idempotent. - if (!__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) { - uint64_t features = 0; + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) + return; + + uint64_t features = 0; - // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics - static const struct { - const char *sysctl_name; - enum CPUFeatures feature; - } feature_checks[] = { - {"hw.optional.arm.FEAT_FlagM", FEAT_FLAGM}, - {"hw.optional.arm.FEAT_FlagM2", FEAT_FLAGM2}, - {"hw.optional.arm.FEAT_FHM", FEAT_FP16FML}, - {"hw.optional.arm.FEAT_DotProd", FEAT_DOTPROD}, - {"hw.optional.arm.FEAT_RDM", FEAT_RDM}, - {"hw.optional.arm.FEAT_LSE", FEAT_LSE}, - {"hw.optional.floatingpoint", FEAT_FP}, - {"hw.optional.AdvSIMD", FEAT_SIMD}, - {"hw.optional.armv8_crc32", FEAT_CRC}, - {"hw.optional.arm.FEAT_SHA1", FEAT_SHA1}, - {"hw.optional.arm.FEAT_SHA256", FEAT_SHA2}, - {"hw.optional.arm.FEAT_SHA3", FEAT_SHA3}, - {"hw.optional.arm.FEAT_AES", FEAT_AES}, - {"hw.optional.arm.FEAT_PMULL", FEAT_PMULL}, - {"hw.optional.arm.FEAT_FP16", FEAT_FP16}, - {"hw.optional.arm.FEAT_DIT", FEAT_DIT}, - {"hw.optional.arm.FEAT_DPB", FEAT_DPB}, - {"hw.optional.arm.FEAT_DPB2", FEAT_DPB2}, - {"hw.optional.arm.FEAT_JSCVT", FEAT_JSCVT}, - {"hw.optional.arm.FEAT_FCMA", FEAT_FCMA}, - {"hw.optional.arm.FEAT_LRCPC", FEAT_RCPC}, - {"hw.optional.arm.FEAT_LRCPC2", FEAT_RCPC2}, - {"hw.optional.arm.FEAT_FRINTTS", FEAT_FRINTTS}, - {"hw.optional.arm.FEAT_I8MM", FEAT_I8MM}, - {"hw.optional.arm.FEAT_BF16", FEAT_BF16}, - {"hw.optional.arm.FEAT_SB", FEAT_SB}, - {"hw.optional.arm.FEAT_SPECRES", FEAT_PREDRES}, - {"hw.optional.arm.FEAT_SSBS", FEAT_SSBS2}, - {"hw.optional.arm.FEAT_BTI", FEAT_BTI}, - }; +#ifdef HAS_CPU_CAPABILITIES_PUBLIC_H + uint8_t feats_bitvec[(CAP_BIT_NB + 7) / 8] = {0}; + size_t len = sizeof(feats_bitvec); + // When hw.optional.arm.feats is available (macOS 15.0+, iOS 18.0+), use the + // fast path to get all the feature bits, otherwise fall back to the slow + // ~20-something sysctls path. + if (!sysctlbyname("hw.optional.arm.caps", &feats_bitvec, &len, 0, 0)) { - for (size_t I = 0, E = sizeof(feature_checks) / sizeof(feature_checks[0]); - I != E; ++I) - if (isKnownAndSupported(feature_checks[I].sysctl_name)) - features |= (1ULL << feature_checks[I].feature); +#define CHECK_BIT(FROM, TO) \ + do { \ + if (feats_bitvec[FROM / 8] & (1u << ((FROM) & 7))) { \ + features |= (1ULL << TO); \ + } \ + } while (0) - features |= (1ULL << FEAT_INIT); + CHECK_BIT(CAP_BIT_FEAT_FlagM, FEAT_FLAGM); + CHECK_BIT(CAP_BIT_FEAT_FlagM2, FEAT_FLAGM2); + CHECK_BIT(CAP_BIT_FEAT_FHM, FEAT_FP16FML); + CHECK_BIT(CAP_BIT_FEAT_DotProd, FEAT_DOTPROD); + CHECK_BIT(CAP_BIT_FEAT_SHA3, FEAT_SHA3); + CHECK_BIT(CAP_BIT_FEAT_RDM, FEAT_RDM); + CHECK_BIT(CAP_BIT_FEAT_LSE, FEAT_LSE); + CHECK_BIT(CAP_BIT_FEAT_SHA256, FEAT_SHA2); + CHECK_BIT(CAP_BIT_FEAT_SHA1, FEAT_SHA1); + CHECK_BIT(CAP_BIT_FEAT_AES, FEAT_AES); + CHECK_BIT(CAP_BIT_FEAT_PMULL, FEAT_PMULL); + CHECK_BIT(CAP_BIT_FEAT_SPECRES, FEAT_PREDRES); + CHECK_BIT(CAP_BIT_FEAT_SB, FEAT_SB); + CHECK_BIT(CAP_BIT_FEAT_FRINTTS, FEAT_FRINTTS); + CHECK_BIT(CAP_BIT_FEAT_LRCPC, FEAT_RCPC); + CHECK_BIT(CAP_BIT_FEAT_LRCPC2, FEAT_RCPC2); + CHECK_BIT(CAP_BIT_FEAT_FCMA, FEAT_FCMA); + CHECK_BIT(CAP_BIT_FEAT_JSCVT, FEAT_JSCVT); + CHECK_BIT(CAP_BIT_FEAT_DPB, FEAT_DPB); + CHECK_BIT(CAP_BIT_FEAT_DPB2, FEAT_DPB2); + CHECK_BIT(CAP_BIT_FEAT_BF16, FEAT_BF16); + CHECK_BIT(CAP_BIT_FEAT_I8MM, FEAT_I8MM); + CHECK_BIT(CAP_BIT_FEAT_DIT, FEAT_DIT); + CHECK_BIT(CAP_BIT_FEAT_FP16, FEAT_FP16); + CHECK_BIT(CAP_BIT_FEAT_SSBS, FEAT_SSBS2); + CHECK_BIT(CAP_BIT_FEAT_BTI, FEAT_BTI); + CHECK_BIT(CAP_BIT_AdvSIMD, FEAT_SIMD); + CHECK_BIT(CAP_BIT_CRC32, FEAT_CRC); + CHECK_BIT(CAP_BIT_FEAT_SME, FEAT_SME); + CHECK_BIT(CAP_BIT_FEAT_SME2, FEAT_SME2); + CHECK_BIT(CAP_BIT_FEAT_SME_F64F64, FEAT_SME_F64); + CHECK_BIT(CAP_BIT_FEAT_SME_I16I64, FEAT_SME_I64); + + features = deriveImplicitFeatures(features); __atomic_store(&__aarch64_cpu_features.features, &features, __ATOMIC_RELAXED); + return; } +#endif + + // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics + static const struct { + const char *sysctl_name; + enum CPUFeatures feature; + } feature_checks[] = { + {"hw.optional.arm.FEAT_FlagM", FEAT_FLAGM}, + {"hw.optional.arm.FEAT_FlagM2", FEAT_FLAGM2}, + {"hw.optional.arm.FEAT_FHM", FEAT_FP16FML}, + {"hw.optional.arm.FEAT_DotProd", FEAT_DOTPROD}, + {"hw.optional.arm.FEAT_RDM", FEAT_RDM}, + {"hw.optional.arm.FEAT_LSE", FEAT_LSE}, + {"hw.optional.AdvSIMD", FEAT_SIMD}, + {"hw.optional.armv8_crc32", FEAT_CRC}, + {"hw.optional.arm.FEAT_SHA1", FEAT_SHA1}, + {"hw.optional.arm.FEAT_SHA256", FEAT_SHA2}, + {"hw.optional.arm.FEAT_SHA3", FEAT_SHA3}, + {"hw.optional.arm.FEAT_AES", FEAT_AES}, + {"hw.optional.arm.FEAT_PMULL", FEAT_PMULL}, + {"hw.optional.arm.FEAT_FP16", FEAT_FP16}, + {"hw.optional.arm.FEAT_DIT", FEAT_DIT}, + {"hw.optional.arm.FEAT_DPB", FEAT_DPB}, + {"hw.optional.arm.FEAT_DPB2", FEAT_DPB2}, + {"hw.optional.arm.FEAT_JSCVT", FEAT_JSCVT}, + {"hw.optional.arm.FEAT_FCMA", FEAT_FCMA}, + {"hw.optional.arm.FEAT_LRCPC", FEAT_RCPC}, + {"hw.optional.arm.FEAT_LRCPC2", FEAT_RCPC2}, + {"hw.optional.arm.FEAT_FRINTTS", FEAT_FRINTTS}, + {"hw.optional.arm.FEAT_I8MM", FEAT_I8MM}, + {"hw.optional.arm.FEAT_BF16", FEAT_BF16}, + {"hw.optional.arm.FEAT_SB", FEAT_SB}, + {"hw.optional.arm.FEAT_SPECRES", FEAT_PREDRES}, + {"hw.optional.arm.FEAT_SSBS", FEAT_SSBS2}, + {"hw.optional.arm.FEAT_BTI", FEAT_BTI}, + }; + + for (size_t I = 0, E = sizeof(feature_checks) / sizeof(feature_checks[0]); + I != E; ++I) + if (isKnownAndSupported(feature_checks[I].sysctl_name)) + features |= (1ULL << feature_checks[I].feature); + + features = deriveImplicitFeatures(features); + + __atomic_store(&__aarch64_cpu_features.features, &features, + __ATOMIC_RELAXED); } #endif // TARGET_OS_OSX || TARGET_OS_IPHONE diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/freebsd.inc b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/freebsd.inc index 793adef44b9..aa975dc854f 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/freebsd.inc +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/freebsd.inc @@ -1,6 +1,6 @@ void __init_cpu_features_resolver(unsigned long hwcap, const __ifunc_arg_t *arg) { - if (__aarch64_cpu_features.features) + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) return; __init_cpu_features_constructor(hwcap, arg); @@ -10,7 +10,7 @@ void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) { unsigned long hwcap = 0; unsigned long hwcap2 = 0; // CPU features already initialized. - if (__aarch64_cpu_features.features) + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) return; int res = 0; diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/fuchsia.inc b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/fuchsia.inc index 329b6b43a8a..fd0800dd11e 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/fuchsia.inc +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/fuchsia.inc @@ -2,7 +2,7 @@ #include <zircon/syscalls.h> void __init_cpu_features_resolver() { - if (__aarch64_cpu_features.features) + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) return; // This ensures the vDSO is a direct link-time dependency of anything that @@ -13,8 +13,8 @@ void __init_cpu_features_resolver() { if (status != ZX_OK) return; -#define setCPUFeature(cpu_feature) \ - __aarch64_cpu_features.features |= 1ULL << cpu_feature + unsigned long long feat = 0; +#define setCPUFeature(cpu_feature) feat |= 1ULL << cpu_feature if (features & ZX_ARM64_FEATURE_ISA_FP) setCPUFeature(FEAT_FP); @@ -48,4 +48,6 @@ void __init_cpu_features_resolver() { setCPUFeature(FEAT_SVE); setCPUFeature(FEAT_INIT); + + __atomic_store_n(&__aarch64_cpu_features.features, feat, __ATOMIC_RELAXED); } diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/mrs.inc b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/mrs.inc index 32a21a2fba9..e4d5e7f2bd7 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/mrs.inc +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/mrs.inc @@ -3,11 +3,10 @@ #define HAVE_SYS_AUXV_H #endif - - static void __init_cpu_features_constructor(unsigned long hwcap, const __ifunc_arg_t *arg) { -#define setCPUFeature(F) __aarch64_cpu_features.features |= 1ULL << F + unsigned long long feat = 0; +#define setCPUFeature(F) feat |= 1ULL << F #define getCPUFeature(id, ftr) __asm__("mrs %0, " #id : "=r"(ftr)) #define extractBits(val, start, number) \ (val & ((1ULL << number) - 1ULL) << start) >> start @@ -20,26 +19,20 @@ static void __init_cpu_features_constructor(unsigned long hwcap, setCPUFeature(FEAT_PMULL); if (hwcap & HWCAP_FLAGM) setCPUFeature(FEAT_FLAGM); - if (hwcap2 & HWCAP2_FLAGM2) { - setCPUFeature(FEAT_FLAGM); + if (hwcap2 & HWCAP2_FLAGM2) setCPUFeature(FEAT_FLAGM2); - } - if (hwcap & HWCAP_SM3 && hwcap & HWCAP_SM4) + if (hwcap & HWCAP_SM4) setCPUFeature(FEAT_SM4); if (hwcap & HWCAP_ASIMDDP) setCPUFeature(FEAT_DOTPROD); if (hwcap & HWCAP_ASIMDFHM) setCPUFeature(FEAT_FP16FML); - if (hwcap & HWCAP_FPHP) { + if (hwcap & HWCAP_FPHP) setCPUFeature(FEAT_FP16); - setCPUFeature(FEAT_FP); - } if (hwcap & HWCAP_DIT) setCPUFeature(FEAT_DIT); if (hwcap & HWCAP_ASIMDRDM) setCPUFeature(FEAT_RDM); - if (hwcap & HWCAP_ILRCPC) - setCPUFeature(FEAT_RCPC2); if (hwcap & HWCAP_AES) setCPUFeature(FEAT_AES); if (hwcap & HWCAP_SHA1) @@ -52,23 +45,20 @@ static void __init_cpu_features_constructor(unsigned long hwcap, setCPUFeature(FEAT_FCMA); if (hwcap & HWCAP_SB) setCPUFeature(FEAT_SB); - if (hwcap & HWCAP_SSBS) + if (hwcap & HWCAP_SSBS) { + setCPUFeature(FEAT_SSBS); setCPUFeature(FEAT_SSBS2); + } if (hwcap2 & HWCAP2_MTE) { setCPUFeature(FEAT_MEMTAG); setCPUFeature(FEAT_MEMTAG2); } - if (hwcap2 & HWCAP2_MTE3) { - setCPUFeature(FEAT_MEMTAG); - setCPUFeature(FEAT_MEMTAG2); + if (hwcap2 & HWCAP2_MTE3) setCPUFeature(FEAT_MEMTAG3); - } if (hwcap2 & HWCAP2_SVEAES) setCPUFeature(FEAT_SVE_AES); - if (hwcap2 & HWCAP2_SVEPMULL) { - setCPUFeature(FEAT_SVE_AES); + if (hwcap2 & HWCAP2_SVEPMULL) setCPUFeature(FEAT_SVE_PMULL128); - } if (hwcap2 & HWCAP2_SVEBITPERM) setCPUFeature(FEAT_SVE_BITPERM); if (hwcap2 & HWCAP2_SVESHA3) @@ -105,6 +95,8 @@ static void __init_cpu_features_constructor(unsigned long hwcap, setCPUFeature(FEAT_WFXT); if (hwcap2 & HWCAP2_SME) setCPUFeature(FEAT_SME); + if (hwcap2 & HWCAP2_SME2) + setCPUFeature(FEAT_SME2); if (hwcap2 & HWCAP2_SME_I16I64) setCPUFeature(FEAT_SME_I64); if (hwcap2 & HWCAP2_SME_F64F64) @@ -113,86 +105,45 @@ static void __init_cpu_features_constructor(unsigned long hwcap, setCPUFeature(FEAT_MOPS); if (hwcap & HWCAP_CPUID) { unsigned long ftr; - getCPUFeature(ID_AA64PFR1_EL1, ftr); - // ID_AA64PFR1_EL1.MTE >= 0b0001 - if (extractBits(ftr, 8, 4) >= 0x1) - setCPUFeature(FEAT_MEMTAG); - // ID_AA64PFR1_EL1.SSBS == 0b0001 - if (extractBits(ftr, 4, 4) == 0x1) - setCPUFeature(FEAT_SSBS); - // ID_AA64PFR1_EL1.SME == 0b0010 - if (extractBits(ftr, 24, 4) == 0x2) - setCPUFeature(FEAT_SME2); - getCPUFeature(ID_AA64PFR0_EL1, ftr); - // ID_AA64PFR0_EL1.FP != 0b1111 - if (extractBits(ftr, 16, 4) != 0xF) { - setCPUFeature(FEAT_FP); - // ID_AA64PFR0_EL1.AdvSIMD has the same value as ID_AA64PFR0_EL1.FP - setCPUFeature(FEAT_SIMD); - } - // ID_AA64PFR0_EL1.SVE != 0b0000 - if (extractBits(ftr, 32, 4) != 0x0) { - // get ID_AA64ZFR0_EL1, that name supported - // if sve enabled only - getCPUFeature(S3_0_C0_C4_4, ftr); - // ID_AA64ZFR0_EL1.SVEver == 0b0000 - if (extractBits(ftr, 0, 4) == 0x0) - setCPUFeature(FEAT_SVE); - // ID_AA64ZFR0_EL1.SVEver == 0b0001 - if (extractBits(ftr, 0, 4) == 0x1) - setCPUFeature(FEAT_SVE2); - // ID_AA64ZFR0_EL1.BF16 != 0b0000 - if (extractBits(ftr, 20, 4) != 0x0) - setCPUFeature(FEAT_SVE_BF16); - } - getCPUFeature(ID_AA64ISAR0_EL1, ftr); - // ID_AA64ISAR0_EL1.SHA3 != 0b0000 - if (extractBits(ftr, 32, 4) != 0x0) - setCPUFeature(FEAT_SHA3); + getCPUFeature(ID_AA64ISAR1_EL1, ftr); - // ID_AA64ISAR1_EL1.DPB >= 0b0001 - if (extractBits(ftr, 0, 4) >= 0x1) - setCPUFeature(FEAT_DPB); - // ID_AA64ISAR1_EL1.LRCPC != 0b0000 - if (extractBits(ftr, 20, 4) != 0x0) - setCPUFeature(FEAT_RCPC); - // ID_AA64ISAR1_EL1.LRCPC == 0b0011 - if (extractBits(ftr, 20, 4) == 0x3) - setCPUFeature(FEAT_RCPC3); - // ID_AA64ISAR1_EL1.SPECRES == 0b0001 - if (extractBits(ftr, 40, 4) == 0x2) + /* ID_AA64ISAR1_EL1.SPECRES >= 0b0001 */ + if (extractBits(ftr, 40, 4) >= 0x1) setCPUFeature(FEAT_PREDRES); - // ID_AA64ISAR1_EL1.BF16 != 0b0000 - if (extractBits(ftr, 44, 4) != 0x0) - setCPUFeature(FEAT_BF16); - // ID_AA64ISAR1_EL1.LS64 >= 0b0001 + /* ID_AA64ISAR1_EL1.LS64 >= 0b0001 */ if (extractBits(ftr, 60, 4) >= 0x1) setCPUFeature(FEAT_LS64); - // ID_AA64ISAR1_EL1.LS64 >= 0b0010 + /* ID_AA64ISAR1_EL1.LS64 >= 0b0010 */ if (extractBits(ftr, 60, 4) >= 0x2) setCPUFeature(FEAT_LS64_V); - // ID_AA64ISAR1_EL1.LS64 >= 0b0011 + /* ID_AA64ISAR1_EL1.LS64 >= 0b0011 */ if (extractBits(ftr, 60, 4) >= 0x3) setCPUFeature(FEAT_LS64_ACCDATA); - } else { - // Set some features in case of no CPUID support - if (hwcap & (HWCAP_FP | HWCAP_FPHP)) { - setCPUFeature(FEAT_FP); - // FP and AdvSIMD fields have the same value - setCPUFeature(FEAT_SIMD); - } - if (hwcap & HWCAP_DCPOP || hwcap2 & HWCAP2_DCPODP) - setCPUFeature(FEAT_DPB); - if (hwcap & HWCAP_LRCPC || hwcap & HWCAP_ILRCPC) - setCPUFeature(FEAT_RCPC); - if (hwcap2 & HWCAP2_BF16 || hwcap2 & HWCAP2_EBF16) - setCPUFeature(FEAT_BF16); - if (hwcap2 & HWCAP2_SVEBF16) - setCPUFeature(FEAT_SVE_BF16); - if (hwcap2 & HWCAP2_SVE2 && hwcap & HWCAP_SVE) - setCPUFeature(FEAT_SVE2); - if (hwcap & HWCAP_SHA3) - setCPUFeature(FEAT_SHA3); } + if (hwcap & HWCAP_FP) { + setCPUFeature(FEAT_FP); + // FP and AdvSIMD fields have the same value + setCPUFeature(FEAT_SIMD); + } + if (hwcap & HWCAP_DCPOP) + setCPUFeature(FEAT_DPB); + if (hwcap & HWCAP_LRCPC) + setCPUFeature(FEAT_RCPC); + if (hwcap & HWCAP_ILRCPC) + setCPUFeature(FEAT_RCPC2); + if (hwcap2 & HWCAP2_LRCPC3) + setCPUFeature(FEAT_RCPC3); + if (hwcap2 & HWCAP2_BF16) + setCPUFeature(FEAT_BF16); + if (hwcap2 & HWCAP2_SVEBF16) + setCPUFeature(FEAT_SVE_BF16); + if (hwcap & HWCAP_SVE) + setCPUFeature(FEAT_SVE); + if (hwcap2 & HWCAP2_SVE2) + setCPUFeature(FEAT_SVE2); + if (hwcap & HWCAP_SHA3) + setCPUFeature(FEAT_SHA3); setCPUFeature(FEAT_INIT); + + __atomic_store_n(&__aarch64_cpu_features.features, feat, __ATOMIC_RELAXED); } diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/sysauxv.inc b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/sysauxv.inc index fb5722c4306..486f77a1e4d 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/sysauxv.inc +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/fmv/sysauxv.inc @@ -1,13 +1,13 @@ void __init_cpu_features_resolver(unsigned long hwcap, const __ifunc_arg_t *arg) { - if (__aarch64_cpu_features.features) + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) return; __init_cpu_features_constructor(hwcap, arg); } void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) { // CPU features already initialized. - if (__aarch64_cpu_features.features) + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) return; unsigned long hwcap = getauxval(AT_HWCAP); diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/hwcap.inc b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/hwcap.inc index 7ddc125b26d..41aba82ef95 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/hwcap.inc +++ b/contrib/libs/cxxsupp/builtins/cpu_model/aarch64/hwcap.inc @@ -178,6 +178,12 @@ #ifndef HWCAP2_SVE_EBF16 #define HWCAP2_SVE_EBF16 (1ULL << 33) #endif +#ifndef HWCAP2_SME2 +#define HWCAP2_SME2 (1UL << 37) +#endif #ifndef HWCAP2_MOPS #define HWCAP2_MOPS (1ULL << 43) #endif +#ifndef HWCAP2_LRCPC3 +#define HWCAP2_LRCPC3 (1UL << 46) +#endif diff --git a/contrib/libs/cxxsupp/builtins/cpu_model/x86.c b/contrib/libs/cxxsupp/builtins/cpu_model/x86.c index 0750e29f989..b1c4abd9d11 100644 --- a/contrib/libs/cxxsupp/builtins/cpu_model/x86.c +++ b/contrib/libs/cxxsupp/builtins/cpu_model/x86.c @@ -59,6 +59,7 @@ enum ProcessorTypes { INTEL_SIERRAFOREST, INTEL_GRANDRIDGE, INTEL_CLEARWATERFOREST, + AMDFAM1AH, CPU_TYPE_MAX }; @@ -97,6 +98,7 @@ enum ProcessorSubtypes { INTEL_COREI7_ARROWLAKE, INTEL_COREI7_ARROWLAKE_S, INTEL_COREI7_PANTHERLAKE, + AMDFAM1AH_ZNVER5, CPU_SUBTYPE_MAX }; @@ -139,20 +141,88 @@ enum ProcessorFeatures { FEATURE_AVX512BITALG, FEATURE_AVX512BF16, FEATURE_AVX512VP2INTERSECT, - - FEATURE_CMPXCHG16B = 46, - FEATURE_F16C = 49, + // FIXME: Below Features has some missings comparing to gcc, it's because gcc + // has some not one-to-one mapped in llvm. + // FEATURE_3DNOW, + // FEATURE_3DNOWP, + FEATURE_ADX = 40, + // FEATURE_ABM, + FEATURE_CLDEMOTE = 42, + FEATURE_CLFLUSHOPT, + FEATURE_CLWB, + FEATURE_CLZERO, + FEATURE_CMPXCHG16B, + // FIXME: Not adding FEATURE_CMPXCHG8B is a workaround to make 'generic' as + // a cpu string with no X86_FEATURE_COMPAT features, which is required in + // current implementantion of cpu_specific/cpu_dispatch FMV feature. + // FEATURE_CMPXCHG8B, + FEATURE_ENQCMD = 48, + FEATURE_F16C, + FEATURE_FSGSBASE, + // FEATURE_FXSAVE, + // FEATURE_HLE, + // FEATURE_IBT, FEATURE_LAHF_LM = 54, FEATURE_LM, - FEATURE_WP, + FEATURE_LWP, FEATURE_LZCNT, FEATURE_MOVBE, - - FEATURE_AVX512FP16 = 94, + FEATURE_MOVDIR64B, + FEATURE_MOVDIRI, + FEATURE_MWAITX, + // FEATURE_OSXSAVE, + FEATURE_PCONFIG = 63, + FEATURE_PKU, + FEATURE_PREFETCHWT1, + FEATURE_PRFCHW, + FEATURE_PTWRITE, + FEATURE_RDPID, + FEATURE_RDRND, + FEATURE_RDSEED, + FEATURE_RTM, + FEATURE_SERIALIZE, + FEATURE_SGX, + FEATURE_SHA, + FEATURE_SHSTK, + FEATURE_TBM, + FEATURE_TSXLDTRK, + FEATURE_VAES, + FEATURE_WAITPKG, + FEATURE_WBNOINVD, + FEATURE_XSAVE, + FEATURE_XSAVEC, + FEATURE_XSAVEOPT, + FEATURE_XSAVES, + FEATURE_AMX_TILE, + FEATURE_AMX_INT8, + FEATURE_AMX_BF16, + FEATURE_UINTR, + FEATURE_HRESET, + FEATURE_KL, + // FEATURE_AESKLE, + FEATURE_WIDEKL = 92, + FEATURE_AVXVNNI, + FEATURE_AVX512FP16, FEATURE_X86_64_BASELINE, FEATURE_X86_64_V2, FEATURE_X86_64_V3, FEATURE_X86_64_V4, + FEATURE_AVXIFMA, + FEATURE_AVXVNNIINT8, + FEATURE_AVXNECONVERT, + FEATURE_CMPCCXADD, + FEATURE_AMX_FP16, + FEATURE_PREFETCHI, + FEATURE_RAOINT, + FEATURE_AMX_COMPLEX, + FEATURE_AVXVNNIINT16, + FEATURE_SM3, + FEATURE_SHA512, + FEATURE_SM4, + FEATURE_APXF, + FEATURE_USERMSR, + FEATURE_AVX10_1_256, + FEATURE_AVX10_1_512, CPU_FEATURE_MAX }; @@ -299,13 +369,13 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family, } } +#define testFeature(F) (Features[F / 32] & (1 << (F % 32))) != 0 + static const char *getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, const unsigned *Features, unsigned *Type, unsigned *Subtype) { -#define testFeature(F) (Features[F / 32] & (1 << (F % 32))) != 0 - // We select CPU strings to match the code in Host.cpp, but we don't use them // in compiler-rt. const char *CPU = 0; @@ -594,14 +664,48 @@ static const char *getAMDProcessorTypeAndSubtype(unsigned Family, const unsigned *Features, unsigned *Type, unsigned *Subtype) { - // We select CPU strings to match the code in Host.cpp, but we don't use them - // in compiler-rt. const char *CPU = 0; switch (Family) { + case 4: + CPU = "i486"; + break; + case 5: + CPU = "pentium"; + switch (Model) { + case 6: + case 7: + CPU = "k6"; + break; + case 8: + CPU = "k6-2"; + break; + case 9: + case 13: + CPU = "k6-3"; + break; + case 10: + CPU = "geode"; + break; + } + break; + case 6: + if (testFeature(FEATURE_SSE)) { + CPU = "athlon-xp"; + break; + } + CPU = "athlon"; + break; + case 15: + if (testFeature(FEATURE_SSE3)) { + CPU = "k8-sse3"; + break; + } + CPU = "k8"; + break; case 16: CPU = "amdfam10"; - *Type = AMDFAM10H; + *Type = AMDFAM10H; // "amdfam10" switch (Model) { case 2: *Subtype = AMDFAM10H_BARCELONA; @@ -677,7 +781,7 @@ static const char *getAMDProcessorTypeAndSubtype(unsigned Family, case 25: CPU = "znver3"; *Type = AMDFAM19H; - if ((Model <= 0x0f) || (Model >= 0x20 && Model <= 0x2f) || + if (Model <= 0x0f || (Model >= 0x20 && Model <= 0x2f) || (Model >= 0x30 && Model <= 0x3f) || (Model >= 0x40 && Model <= 0x4f) || (Model >= 0x50 && Model <= 0x5f)) { // Family 19h Models 00h-0Fh (Genesis, Chagall) Zen 3 @@ -701,6 +805,24 @@ static const char *getAMDProcessorTypeAndSubtype(unsigned Family, break; // "znver4" } break; // family 19h + case 26: + CPU = "znver5"; + *Type = AMDFAM1AH; + if (Model <= 0x77) { + // Models 00h-0Fh (Breithorn). + // Models 10h-1Fh (Breithorn-Dense). + // Models 20h-2Fh (Strix 1). + // Models 30h-37h (Strix 2). + // Models 38h-3Fh (Strix 3). + // Models 40h-4Fh (Granite Ridge). + // Models 50h-5Fh (Weisshorn). + // Models 60h-6Fh (Krackan1). + // Models 70h-77h (Sarlak). + CPU = "znver5"; + *Subtype = AMDFAM1AH_ZNVER5; + break; // "znver5" + } + break; default: break; // Unknown AMD CPU. } @@ -708,6 +830,8 @@ static const char *getAMDProcessorTypeAndSubtype(unsigned Family, return CPU; } +#undef testFeature + static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, unsigned *Features) { unsigned EAX = 0, EBX = 0; @@ -746,13 +870,15 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, setFeature(FEATURE_AES); if ((ECX >> 29) & 1) setFeature(FEATURE_F16C); + if ((ECX >> 30) & 1) + setFeature(FEATURE_RDRND); // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV // indicates that the AVX registers will be saved and restored on context // switch, then we have full AVX support. const unsigned AVXBits = (1 << 27) | (1 << 28); - bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && - ((EAX & 0x6) == 0x6); + bool HasAVXSave = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && + ((EAX & 0x6) == 0x6); #if defined(__APPLE__) // Darwin lazily saves the AVX512 context on first use: trust that the OS will // save the AVX512 context if we use AVX512 instructions, even the bit is not @@ -760,45 +886,76 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, bool HasAVX512Save = true; #else // AVX512 requires additional context to be saved by the OS. - bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); + bool HasAVX512Save = HasAVXSave && ((EAX & 0xe0) == 0xe0); #endif + // AMX requires additional context to be saved by the OS. + const unsigned AMXBits = (1 << 17) | (1 << 18); + bool HasXSave = ((ECX >> 27) & 1) && !getX86XCR0(&EAX, &EDX); + bool HasAMXSave = HasXSave && ((EAX & AMXBits) == AMXBits); - if (HasAVX) + if (HasAVXSave) setFeature(FEATURE_AVX); + if (((ECX >> 26) & 1) && HasAVXSave) + setFeature(FEATURE_XSAVE); + bool HasLeaf7 = MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + if (HasLeaf7 && ((EBX >> 0) & 1)) + setFeature(FEATURE_FSGSBASE); + if (HasLeaf7 && ((EBX >> 2) & 1)) + setFeature(FEATURE_SGX); if (HasLeaf7 && ((EBX >> 3) & 1)) setFeature(FEATURE_BMI); - if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) + if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVXSave) setFeature(FEATURE_AVX2); if (HasLeaf7 && ((EBX >> 8) & 1)) setFeature(FEATURE_BMI2); + if (HasLeaf7 && ((EBX >> 11) & 1)) + setFeature(FEATURE_RTM); if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512F); if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512DQ); + if (HasLeaf7 && ((EBX >> 18) & 1)) + setFeature(FEATURE_RDSEED); + if (HasLeaf7 && ((EBX >> 19) & 1)) + setFeature(FEATURE_ADX); if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512IFMA); + if (HasLeaf7 && ((EBX >> 24) & 1)) + setFeature(FEATURE_CLWB); if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512PF); if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512ER); if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512CD); + if (HasLeaf7 && ((EBX >> 29) & 1)) + setFeature(FEATURE_SHA); if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512BW); if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512VL); + if (HasLeaf7 && ((ECX >> 0) & 1)) + setFeature(FEATURE_PREFETCHWT1); if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512VBMI); + if (HasLeaf7 && ((ECX >> 4) & 1)) + setFeature(FEATURE_PKU); + if (HasLeaf7 && ((ECX >> 5) & 1)) + setFeature(FEATURE_WAITPKG); if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512VBMI2); + if (HasLeaf7 && ((ECX >> 7) & 1)) + setFeature(FEATURE_SHSTK); if (HasLeaf7 && ((ECX >> 8) & 1)) setFeature(FEATURE_GFNI); - if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX) + if (HasLeaf7 && ((ECX >> 9) & 1) && HasAVXSave) + setFeature(FEATURE_VAES); + if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVXSave) setFeature(FEATURE_VPCLMULQDQ); if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512VNNI); @@ -806,23 +963,100 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, setFeature(FEATURE_AVX512BITALG); if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512VPOPCNTDQ); + if (HasLeaf7 && ((ECX >> 22) & 1)) + setFeature(FEATURE_RDPID); + if (HasLeaf7 && ((ECX >> 23) & 1)) + setFeature(FEATURE_KL); + if (HasLeaf7 && ((ECX >> 25) & 1)) + setFeature(FEATURE_CLDEMOTE); + if (HasLeaf7 && ((ECX >> 27) & 1)) + setFeature(FEATURE_MOVDIRI); + if (HasLeaf7 && ((ECX >> 28) & 1)) + setFeature(FEATURE_MOVDIR64B); + if (HasLeaf7 && ((ECX >> 29) & 1)) + setFeature(FEATURE_ENQCMD); if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) setFeature(FEATURE_AVX5124VNNIW); if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) setFeature(FEATURE_AVX5124FMAPS); + if (HasLeaf7 && ((EDX >> 5) & 1)) + setFeature(FEATURE_UINTR); if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512VP2INTERSECT); + if (HasLeaf7 && ((EDX >> 14) & 1)) + setFeature(FEATURE_SERIALIZE); + if (HasLeaf7 && ((EDX >> 16) & 1)) + setFeature(FEATURE_TSXLDTRK); + if (HasLeaf7 && ((EDX >> 18) & 1)) + setFeature(FEATURE_PCONFIG); + if (HasLeaf7 && ((EDX >> 22) & 1) && HasAMXSave) + setFeature(FEATURE_AMX_BF16); if (HasLeaf7 && ((EDX >> 23) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512FP16); + if (HasLeaf7 && ((EDX >> 24) & 1) && HasAMXSave) + setFeature(FEATURE_AMX_TILE); + if (HasLeaf7 && ((EDX >> 25) & 1) && HasAMXSave) + setFeature(FEATURE_AMX_INT8); // EAX from subleaf 0 is the maximum subleaf supported. Some CPUs don't // return all 0s for invalid subleaves so check the limit. bool HasLeaf7Subleaf1 = HasLeaf7 && EAX >= 1 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); + if (HasLeaf7Subleaf1 && ((EAX >> 0) & 1)) + setFeature(FEATURE_SHA512); + if (HasLeaf7Subleaf1 && ((EAX >> 1) & 1)) + setFeature(FEATURE_SM3); + if (HasLeaf7Subleaf1 && ((EAX >> 2) & 1)) + setFeature(FEATURE_SM4); + if (HasLeaf7Subleaf1 && ((EAX >> 3) & 1)) + setFeature(FEATURE_RAOINT); + if (HasLeaf7Subleaf1 && ((EAX >> 4) & 1) && HasAVXSave) + setFeature(FEATURE_AVXVNNI); if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512BF16); + if (HasLeaf7Subleaf1 && ((EAX >> 7) & 1)) + setFeature(FEATURE_CMPCCXADD); + if (HasLeaf7Subleaf1 && ((EAX >> 21) & 1) && HasAMXSave) + setFeature(FEATURE_AMX_FP16); + if (HasLeaf7Subleaf1 && ((EAX >> 22) & 1)) + setFeature(FEATURE_HRESET); + if (HasLeaf7Subleaf1 && ((EAX >> 23) & 1) && HasAVXSave) + setFeature(FEATURE_AVXIFMA); + + if (HasLeaf7Subleaf1 && ((EDX >> 4) & 1) && HasAVXSave) + setFeature(FEATURE_AVXVNNIINT8); + if (HasLeaf7Subleaf1 && ((EDX >> 5) & 1) && HasAVXSave) + setFeature(FEATURE_AVXNECONVERT); + if (HasLeaf7Subleaf1 && ((EDX >> 8) & 1) && HasAMXSave) + setFeature(FEATURE_AMX_COMPLEX); + if (HasLeaf7Subleaf1 && ((EDX >> 10) & 1) && HasAVXSave) + setFeature(FEATURE_AVXVNNIINT16); + if (HasLeaf7Subleaf1 && ((EDX >> 14) & 1)) + setFeature(FEATURE_PREFETCHI); + if (HasLeaf7Subleaf1 && ((EDX >> 15) & 1)) + setFeature(FEATURE_USERMSR); + if (HasLeaf7Subleaf1 && ((EDX >> 19) & 1)) + setFeature(FEATURE_AVX10_1_256); + if (HasLeaf7Subleaf1 && ((EDX >> 21) & 1)) + setFeature(FEATURE_APXF); + + unsigned MaxLevel; + getX86CpuIDAndInfo(0, &MaxLevel, &EBX, &ECX, &EDX); + bool HasLeafD = MaxLevel >= 0xd && + !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); + if (HasLeafD && ((EAX >> 0) & 1) && HasAVXSave) + setFeature(FEATURE_XSAVEOPT); + if (HasLeafD && ((EAX >> 1) & 1) && HasAVXSave) + setFeature(FEATURE_XSAVEC); + if (HasLeafD && ((EAX >> 3) & 1) && HasAVXSave) + setFeature(FEATURE_XSAVES); + + bool HasLeaf24 = + MaxLevel >= 0x24 && !getX86CpuIDAndInfo(0x24, &EAX, &EBX, &ECX, &EDX); + if (HasLeaf7Subleaf1 && ((EDX >> 19) & 1) && HasLeaf24 && ((EBX >> 18) & 1)) + setFeature(FEATURE_AVX10_1_512); unsigned MaxExtLevel; getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); @@ -836,14 +1070,40 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, setFeature(FEATURE_LZCNT); if (((ECX >> 6) & 1)) setFeature(FEATURE_SSE4_A); + if (((ECX >> 8) & 1)) + setFeature(FEATURE_PRFCHW); if (((ECX >> 11) & 1)) setFeature(FEATURE_XOP); + if (((ECX >> 15) & 1)) + setFeature(FEATURE_LWP); if (((ECX >> 16) & 1)) setFeature(FEATURE_FMA4); + if (((ECX >> 21) & 1)) + setFeature(FEATURE_TBM); + if (((ECX >> 29) & 1)) + setFeature(FEATURE_MWAITX); + if (((EDX >> 29) & 1)) setFeature(FEATURE_LM); } + bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 && + !getX86CpuIDAndInfo(0x80000008, &EAX, &EBX, &ECX, &EDX); + if (HasExtLeaf8 && ((EBX >> 0) & 1)) + setFeature(FEATURE_CLZERO); + if (HasExtLeaf8 && ((EBX >> 9) & 1)) + setFeature(FEATURE_WBNOINVD); + + bool HasLeaf14 = MaxLevel >= 0x14 && + !getX86CpuIDAndInfoEx(0x14, 0x0, &EAX, &EBX, &ECX, &EDX); + if (HasLeaf14 && ((EBX >> 4) & 1)) + setFeature(FEATURE_PTWRITE); + + bool HasLeaf19 = + MaxLevel >= 0x19 && !getX86CpuIDAndInfo(0x19, &EAX, &EBX, &ECX, &EDX); + if (HasLeaf7 && HasLeaf19 && ((EBX >> 2) & 1)) + setFeature(FEATURE_WIDEKL); + if (hasFeature(FEATURE_LM) && hasFeature(FEATURE_SSE2)) { setFeature(FEATURE_X86_64_BASELINE); if (hasFeature(FEATURE_CMPXCHG16B) && hasFeature(FEATURE_POPCNT) && diff --git a/contrib/libs/cxxsupp/builtins/divtc3.c b/contrib/libs/cxxsupp/builtins/divtc3.c index 099de5802da..c393de81533 100644 --- a/contrib/libs/cxxsupp/builtins/divtc3.c +++ b/contrib/libs/cxxsupp/builtins/divtc3.c @@ -13,7 +13,7 @@ #define QUAD_PRECISION #include "fp_lib.h" -#if defined(CRT_HAS_F128) +#if defined(CRT_HAS_128BIT) && defined(CRT_HAS_F128) // Returns: the quotient of (a + ib) / (c + id) diff --git a/contrib/libs/cxxsupp/builtins/extendbfsf2.c b/contrib/libs/cxxsupp/builtins/extendbfsf2.c new file mode 100644 index 00000000000..e159d7997f6 --- /dev/null +++ b/contrib/libs/cxxsupp/builtins/extendbfsf2.c @@ -0,0 +1,13 @@ +//===-- lib/extendbfsf2.c - bfloat -> single conversion -----------*- 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 +// +//===----------------------------------------------------------------------===// + +#define SRC_BFLOAT16 +#define DST_SINGLE +#include "fp_extend_impl.inc" + +COMPILER_RT_ABI float __extendbfsf2(src_t a) { return __extendXfYf2__(a); } diff --git a/contrib/libs/cxxsupp/builtins/fp_add_impl.inc b/contrib/libs/cxxsupp/builtins/fp_add_impl.inc index 7133358df9b..d20599921e7 100644 --- a/contrib/libs/cxxsupp/builtins/fp_add_impl.inc +++ b/contrib/libs/cxxsupp/builtins/fp_add_impl.inc @@ -91,7 +91,7 @@ static __inline fp_t __addXf3__(fp_t a, fp_t b) { // Shift the significand of b by the difference in exponents, with a sticky // bottom bit to get rounding correct. - const unsigned int align = aExponent - bExponent; + const unsigned int align = (unsigned int)(aExponent - bExponent); if (align) { if (align < typeWidth) { const bool sticky = (bSignificand << (typeWidth - align)) != 0; diff --git a/contrib/libs/cxxsupp/builtins/fp_extend.h b/contrib/libs/cxxsupp/builtins/fp_extend.h index 95ea2a7ac4b..22bf2b2514e 100644 --- a/contrib/libs/cxxsupp/builtins/fp_extend.h +++ b/contrib/libs/cxxsupp/builtins/fp_extend.h @@ -37,16 +37,7 @@ static const int srcSigFracBits = 52; // srcBits - srcSigFracBits - 1 static const int srcExpBits = 11; -static inline int src_rep_t_clz_impl(src_rep_t a) { -#if defined __LP64__ - return __builtin_clzl(a); -#else - if (a & REP_C(0xffffffff00000000)) - return clzsi(a >> 32); - else - return 32 + clzsi(a & REP_C(0xffffffff)); -#endif -} +static inline int src_rep_t_clz_impl(src_rep_t a) { return __builtin_clzll(a); } #define src_rep_t_clz src_rep_t_clz_impl #elif defined SRC_80 @@ -81,6 +72,21 @@ static inline int src_rep_t_clz_impl(src_rep_t a) { #define src_rep_t_clz src_rep_t_clz_impl +#elif defined SRC_BFLOAT16 +#ifdef COMPILER_RT_HAS_BFLOAT16 +typedef __bf16 src_t; +#else +typedef uint16_t src_t; +#endif +typedef uint16_t src_rep_t; +#define SRC_REP_C UINT16_C +static const int srcBits = sizeof(src_t) * CHAR_BIT; +static const int srcSigFracBits = 7; +// -1 accounts for the sign bit. +// srcBits - srcSigFracBits - 1 +static const int srcExpBits = 8; +#define src_rep_t_clz __builtin_clz + #else #error Source should be half, single, or double precision! #endif // end source precision diff --git a/contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc b/contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc index 3556bad9990..2f2f77ce781 100644 --- a/contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc +++ b/contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc @@ -34,7 +34,7 @@ static __inline fixint_t __fixint(fp_t a) { // If 0 <= exponent < significandBits, right shift to get the result. // Otherwise, shift left. if (exponent < significandBits) - return sign * (significand >> (significandBits - exponent)); + return (fixint_t)(sign * (significand >> (significandBits - exponent))); else - return sign * ((fixuint_t)significand << (exponent - significandBits)); + return (fixint_t)(sign * ((fixuint_t)significand << (exponent - significandBits))); } diff --git a/contrib/libs/cxxsupp/builtins/fp_lib.h b/contrib/libs/cxxsupp/builtins/fp_lib.h index c4f0a5b9587..b2a89506135 100644 --- a/contrib/libs/cxxsupp/builtins/fp_lib.h +++ b/contrib/libs/cxxsupp/builtins/fp_lib.h @@ -43,8 +43,8 @@ static __inline int rep_clz(rep_t a) { return clzsi(a); } // 32x32 --> 64 bit multiply static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { const uint64_t product = (uint64_t)a * b; - *hi = product >> 32; - *lo = product; + *hi = (rep_t)(product >> 32); + *lo = (rep_t)product; } COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b); @@ -58,16 +58,7 @@ typedef double fp_t; #define REP_C UINT64_C #define significandBits 52 -static __inline int rep_clz(rep_t a) { -#if defined __LP64__ - return __builtin_clzl(a); -#else - if (a & REP_C(0xffffffff00000000)) - return clzsi(a >> 32); - else - return 32 + clzsi(a & REP_C(0xffffffff)); -#endif -} +static inline int rep_clz(rep_t a) { return __builtin_clzll(a); } #define loWord(a) (a & 0xffffffffU) #define hiWord(a) (a >> 32) @@ -239,7 +230,7 @@ static __inline int normalize(rep_t *significand) { return 1 - shift; } -static __inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) { +static __inline void wideLeftShift(rep_t *hi, rep_t *lo, unsigned int count) { *hi = *hi << count | *lo >> (typeWidth - count); *lo = *lo << count; } diff --git a/contrib/libs/cxxsupp/builtins/int_types.h b/contrib/libs/cxxsupp/builtins/int_types.h index ca97391fc28..48862f36421 100644 --- a/contrib/libs/cxxsupp/builtins/int_types.h +++ b/contrib/libs/cxxsupp/builtins/int_types.h @@ -107,8 +107,8 @@ typedef union { static __inline ti_int make_ti(di_int h, di_int l) { twords r; - r.s.high = h; - r.s.low = l; + r.s.high = (du_int)h; + r.s.low = (du_int)l; return r.all; } diff --git a/contrib/libs/cxxsupp/builtins/multc3.c b/contrib/libs/cxxsupp/builtins/multc3.c index 61a3f45e472..a89832f0e88 100644 --- a/contrib/libs/cxxsupp/builtins/multc3.c +++ b/contrib/libs/cxxsupp/builtins/multc3.c @@ -15,7 +15,7 @@ #include "int_lib.h" #include "int_math.h" -#if defined(CRT_HAS_F128) +#if defined(CRT_HAS_128BIT) && defined(CRT_HAS_F128) // Returns: the product of a + ib and c + id diff --git a/contrib/libs/cxxsupp/builtins/os_version_check.c b/contrib/libs/cxxsupp/builtins/os_version_check.c index 182eabe7a6a..01fae834ab2 100644 --- a/contrib/libs/cxxsupp/builtins/os_version_check.c +++ b/contrib/libs/cxxsupp/builtins/os_version_check.c @@ -316,8 +316,8 @@ int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) { static pthread_once_t once = PTHREAD_ONCE_INIT; pthread_once(&once, readSystemProperties); - return SdkVersion >= Major || - (IsPreRelease && Major == __ANDROID_API_FUTURE__); + // Allow all on pre-release. Note that we still rely on compile-time checks. + return SdkVersion >= Major || IsPreRelease; } #else diff --git a/contrib/libs/cxxsupp/builtins/riscv/restore.S b/contrib/libs/cxxsupp/builtins/riscv/restore.S index 6f43842c8ca..d87dfc1ac71 100644 --- a/contrib/libs/cxxsupp/builtins/riscv/restore.S +++ b/contrib/libs/cxxsupp/builtins/riscv/restore.S @@ -22,7 +22,7 @@ #if __riscv_xlen == 32 -#ifndef __riscv_32e +#ifndef __riscv_abi_rve .globl __riscv_restore_12 .type __riscv_restore_12,@function @@ -109,7 +109,7 @@ __riscv_restore_0: #elif __riscv_xlen == 64 -#ifndef __riscv_64e +#ifndef __riscv_abi_rve .globl __riscv_restore_12 .type __riscv_restore_12,@function diff --git a/contrib/libs/cxxsupp/builtins/riscv/save.S b/contrib/libs/cxxsupp/builtins/riscv/save.S index 3e044179ff7..6324e05e971 100644 --- a/contrib/libs/cxxsupp/builtins/riscv/save.S +++ b/contrib/libs/cxxsupp/builtins/riscv/save.S @@ -18,7 +18,7 @@ #if __riscv_xlen == 32 -#ifndef __riscv_32e +#ifndef __riscv_abi_rve .globl __riscv_save_12 .type __riscv_save_12,@function @@ -115,7 +115,7 @@ __riscv_save_0: #elif __riscv_xlen == 64 -#ifndef __riscv_64e +#ifndef __riscv_abi_rve .globl __riscv_save_12 .type __riscv_save_12,@function diff --git a/contrib/libs/cxxsupp/builtins/trampoline_setup.c b/contrib/libs/cxxsupp/builtins/trampoline_setup.c index 844eb279441..830e25e4c03 100644 --- a/contrib/libs/cxxsupp/builtins/trampoline_setup.c +++ b/contrib/libs/cxxsupp/builtins/trampoline_setup.c @@ -41,3 +41,45 @@ COMPILER_RT_ABI void __trampoline_setup(uint32_t *trampOnStack, __clear_cache(trampOnStack, &trampOnStack[10]); } #endif // __powerpc__ && !defined(__powerpc64__) + +// The AArch64 compiler generates calls to __trampoline_setup() when creating +// trampoline functions on the stack for use with nested functions. +// This function creates a custom 36-byte trampoline function on the stack +// which loads x18 with a pointer to the outer function's locals +// and then jumps to the target nested function. +// Note: x18 is a reserved platform register on Windows and macOS. + +#if defined(__aarch64__) && defined(__ELF__) +COMPILER_RT_ABI void __trampoline_setup(uint32_t *trampOnStack, + int trampSizeAllocated, + const void *realFunc, void *localsPtr) { + // This should never happen, but if compiler did not allocate + // enough space on stack for the trampoline, abort. + if (trampSizeAllocated < 36) + compilerrt_abort(); + + // create trampoline + // Load realFunc into x17. mov/movk 16 bits at a time. + trampOnStack[0] = + 0xd2800000u | ((((uint64_t)realFunc >> 0) & 0xffffu) << 5) | 0x11; + trampOnStack[1] = + 0xf2a00000u | ((((uint64_t)realFunc >> 16) & 0xffffu) << 5) | 0x11; + trampOnStack[2] = + 0xf2c00000u | ((((uint64_t)realFunc >> 32) & 0xffffu) << 5) | 0x11; + trampOnStack[3] = + 0xf2e00000u | ((((uint64_t)realFunc >> 48) & 0xffffu) << 5) | 0x11; + // Load localsPtr into x18 + trampOnStack[4] = + 0xd2800000u | ((((uint64_t)localsPtr >> 0) & 0xffffu) << 5) | 0x12; + trampOnStack[5] = + 0xf2a00000u | ((((uint64_t)localsPtr >> 16) & 0xffffu) << 5) | 0x12; + trampOnStack[6] = + 0xf2c00000u | ((((uint64_t)localsPtr >> 32) & 0xffffu) << 5) | 0x12; + trampOnStack[7] = + 0xf2e00000u | ((((uint64_t)localsPtr >> 48) & 0xffffu) << 5) | 0x12; + trampOnStack[8] = 0xd61f0220; // br x17 + + // Clear instruction cache. + __clear_cache(trampOnStack, &trampOnStack[9]); +} +#endif // defined(__aarch64__) && !defined(__APPLE__) && !defined(_WIN64) diff --git a/contrib/libs/cxxsupp/builtins/ya.make b/contrib/libs/cxxsupp/builtins/ya.make index 5f9c60552aa..ae250c5db79 100644 --- a/contrib/libs/cxxsupp/builtins/ya.make +++ b/contrib/libs/cxxsupp/builtins/ya.make @@ -12,9 +12,9 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(18.1.8) +VERSION(19.1.3) -ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.8/compiler-rt-18.1.8.src.tar.xz) +ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.3/compiler-rt-19.1.3.src.tar.xz) NO_COMPILER_WARNINGS() @@ -65,7 +65,9 @@ IF (ARCH_AARCH64) aarch64/chkstk.S aarch64/fp_mode.c aarch64/sme-abi-init.c + aarch64/sme-abi-vg.c aarch64/sme-abi.S + aarch64/sme-libc-mem-routines.S absvdi2.c absvsi2.c absvti2.c @@ -117,6 +119,7 @@ IF (ARCH_AARCH64) emutls.c enable_execute_stack.c eprintf.c + extendbfsf2.c extenddftf2.c extendhfsf2.c extendhftf2.c @@ -284,6 +287,7 @@ ELSEIF (ARCH_X86_64) emutls.c enable_execute_stack.c eprintf.c + extendbfsf2.c extenddftf2.c extendhfsf2.c extendhftf2.c @@ -467,6 +471,7 @@ ELSE() emutls.c enable_execute_stack.c eprintf.c + extendbfsf2.c extenddftf2.c extendhfsf2.c extendhftf2.c diff --git a/contrib/libs/cxxsupp/libcxxrt/exception.cc b/contrib/libs/cxxsupp/libcxxrt/exception.cc index 2fe90c3e1c6..97f499f882c 100644 --- a/contrib/libs/cxxsupp/libcxxrt/exception.cc +++ b/contrib/libs/cxxsupp/libcxxrt/exception.cc @@ -811,7 +811,7 @@ static void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exce case _URC_END_OF_STACK: __cxa_begin_catch (&(thrown_exception->unwindHeader)); std::terminate(); - fprintf(stderr, "uncaught exception:\n address -> %p\n", + fprintf(stderr, "Terminating due to uncaught exception %p", static_cast<void*>(thrown_exception)); thrown_exception = realExceptionFromException(thrown_exception); static const __class_type_info *e_ti = @@ -825,7 +825,7 @@ static void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exce throw_ti)); if (e) { - fprintf(stderr, " what() -> \"%s\"\n", e->what()); + fprintf(stderr, " '%s'", e->what()); } } @@ -834,7 +834,7 @@ static void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exce const char *mangled = thrown_exception->exceptionType->name(); int status; demangled = __cxa_demangle(mangled, demangled, &bufferSize, &status); - fprintf(stderr, " type -> %s\n", + fprintf(stderr, " of type %s\n", status == 0 ? demangled : mangled); if (status == 0) { free(demangled); } // Print a back trace if no handler is found. diff --git a/contrib/libs/cxxsupp/libsan/ya.make b/contrib/libs/cxxsupp/libsan/ya.make index e770d0ac3df..016fa270d29 100644 --- a/contrib/libs/cxxsupp/libsan/ya.make +++ b/contrib/libs/cxxsupp/libsan/ya.make @@ -12,8 +12,6 @@ NO_SANITIZE() NO_SANITIZE_COVERAGE() -SUBSCRIBER(somov) - RUN_PYTHON3( generate_symbolizer.py ${CXX_COMPILER} STDOUT symbolizer.c diff --git a/contrib/restricted/aws/aws-c-auth/.yandex_meta/__init__.py b/contrib/restricted/aws/aws-c-auth/.yandex_meta/__init__.py index 11284abdb3c..17cf7612e10 100644 --- a/contrib/restricted/aws/aws-c-auth/.yandex_meta/__init__.py +++ b/contrib/restricted/aws/aws-c-auth/.yandex_meta/__init__.py @@ -1,7 +1,21 @@ +from devtools.yamaker.modules import Linkable, Switch from devtools.yamaker.project import CMakeNinjaNixProject +def post_install(self): + with self.yamakes["."] as m: + m.after( + "CFLAGS", + Switch( + OS_WINDOWS=Linkable( + CFLAGS=["-DAWS_AUTH_EXPORTS"], + ), + ), + ) + + aws_c_auth = CMakeNinjaNixProject( arcdir="contrib/restricted/aws/aws-c-auth", nixattr="aws-c-auth", + post_install=post_install, ) diff --git a/contrib/restricted/aws/aws-c-auth/.yandex_meta/devtools.copyrights.report b/contrib/restricted/aws/aws-c-auth/.yandex_meta/devtools.copyrights.report index 18eebfd75d7..6870cbe6c1c 100644 --- a/contrib/restricted/aws/aws-c-auth/.yandex_meta/devtools.copyrights.report +++ b/contrib/restricted/aws/aws-c-auth/.yandex_meta/devtools.copyrights.report @@ -53,6 +53,8 @@ BELONGS ya.make include/aws/auth/private/credentials_utils.h [5:5] include/aws/auth/private/key_derivation.h [5:5] include/aws/auth/private/sigv4_http_request.h [5:5] + include/aws/auth/private/sso_token_providers.h [5:5] + include/aws/auth/private/sso_token_utils.h [5:5] include/aws/auth/signing.h [5:5] include/aws/auth/signing_config.h [5:5] include/aws/auth/signing_result.h [5:5] @@ -72,6 +74,7 @@ BELONGS ya.make source/credentials_provider_imds.c [2:2] source/credentials_provider_process.c [2:2] source/credentials_provider_profile.c [2:2] + source/credentials_provider_sso.c [2:2] source/credentials_provider_static.c [2:2] source/credentials_provider_sts.c [2:2] source/credentials_provider_sts_web_identity.c [2:2] @@ -86,3 +89,6 @@ BELONGS ya.make source/signing_config.c [2:2] source/signing_result.c [2:2] source/sigv4_http_request.c [2:2] + source/sso_token_utils.c [2:2] + source/token_provider_sso_profile.c [2:2] + source/token_provider_sso_session.c [2:2] diff --git a/contrib/restricted/aws/aws-c-auth/.yandex_meta/devtools.licenses.report b/contrib/restricted/aws/aws-c-auth/.yandex_meta/devtools.licenses.report index 72747329987..3e77c3fc299 100644 --- a/contrib/restricted/aws/aws-c-auth/.yandex_meta/devtools.licenses.report +++ b/contrib/restricted/aws/aws-c-auth/.yandex_meta/devtools.licenses.report @@ -101,6 +101,8 @@ BELONGS ya.make include/aws/auth/private/credentials_utils.h [6:6] include/aws/auth/private/key_derivation.h [6:6] include/aws/auth/private/sigv4_http_request.h [6:6] + include/aws/auth/private/sso_token_providers.h [6:6] + include/aws/auth/private/sso_token_utils.h [6:6] include/aws/auth/signing.h [6:6] include/aws/auth/signing_config.h [6:6] include/aws/auth/signing_result.h [6:6] @@ -120,6 +122,7 @@ BELONGS ya.make source/credentials_provider_imds.c [3:3] source/credentials_provider_process.c [3:3] source/credentials_provider_profile.c [3:3] + source/credentials_provider_sso.c [3:3] source/credentials_provider_static.c [3:3] source/credentials_provider_sts.c [3:3] source/credentials_provider_sts_web_identity.c [3:3] @@ -134,6 +137,9 @@ BELONGS ya.make source/signing_config.c [3:3] source/signing_result.c [3:3] source/sigv4_http_request.c [3:3] + source/sso_token_utils.c [3:3] + source/token_provider_sso_profile.c [3:3] + source/token_provider_sso_session.c [3:3] SKIP LicenseRef-scancode-generic-cla ee24fdc60600747c7d12c32055b0011d BELONGS ya.make diff --git a/contrib/restricted/aws/aws-c-auth/.yandex_meta/override.nix b/contrib/restricted/aws/aws-c-auth/.yandex_meta/override.nix index d770242b9a3..6a964efc618 100644 --- a/contrib/restricted/aws/aws-c-auth/.yandex_meta/override.nix +++ b/contrib/restricted/aws/aws-c-auth/.yandex_meta/override.nix @@ -1,10 +1,10 @@ pkgs: attrs: with pkgs; with attrs; rec { - version = "0.6.26"; + version = "0.6.27"; src = fetchFromGitHub { owner = "awslabs"; repo = "aws-c-auth"; rev = "v${version}"; - hash = "sha256-PvdkTw5JydJT0TbXLB2C9tk4T+ho+fAbaw4jU9m5KuU="; + hash = "sha256-rjluBj8C4GjE67Os0+1CKKI/2V9RnkbYKhpdqQBryik="; }; } diff --git a/contrib/restricted/aws/aws-c-auth/include/aws/auth/auth.h b/contrib/restricted/aws/aws-c-auth/include/aws/auth/auth.h index 4411d8ff253..b00928372fc 100644 --- a/contrib/restricted/aws/aws-c-auth/include/aws/auth/auth.h +++ b/contrib/restricted/aws/aws-c-auth/include/aws/auth/auth.h @@ -43,6 +43,10 @@ enum aws_auth_errors { AWS_AUTH_SIGV4A_SIGNATURE_VALIDATION_FAILURE, AWS_AUTH_CREDENTIALS_PROVIDER_COGNITO_SOURCE_FAILURE, AWS_AUTH_CREDENTIALS_PROVIDER_DELEGATE_FAILURE, + AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE, + AWS_AUTH_SSO_TOKEN_INVALID, + AWS_AUTH_SSO_TOKEN_EXPIRED, + AWS_AUTH_CREDENTIALS_PROVIDER_SSO_SOURCE_FAILURE, AWS_AUTH_ERROR_END_RANGE = AWS_ERROR_ENUM_END_RANGE(AWS_C_AUTH_PACKAGE_ID) }; diff --git a/contrib/restricted/aws/aws-c-auth/include/aws/auth/credentials.h b/contrib/restricted/aws/aws-c-auth/include/aws/auth/credentials.h index 3fa13911f63..2a92f42caba 100644 --- a/contrib/restricted/aws/aws-c-auth/include/aws/auth/credentials.h +++ b/contrib/restricted/aws/aws-c-auth/include/aws/auth/credentials.h @@ -90,8 +90,8 @@ struct aws_credentials_provider_environment_options { }; /** - * Configuration options for a provider that sources credentials from the aws profile and credentials files - * (by default ~/.aws/profile and ~/.aws/credentials) + * Configuration options for a provider that sources credentials from the aws config and credentials files + * (by default ~/.aws/config and ~/.aws/credentials) */ struct aws_credentials_provider_profile_options { struct aws_credentials_provider_shutdown_options shutdown_options; @@ -114,7 +114,7 @@ struct aws_credentials_provider_profile_options { /** * (Optional) * Use a cached merged profile collection. A merge collection has both config file - * (~/.aws/profile) and credentials file based profile collection (~/.aws/credentials) using + * (~/.aws/config) and credentials file based profile collection (~/.aws/credentials) using * `aws_profile_collection_new_from_merge`. * If this option is provided, `config_file_name_override` and `credentials_file_name_override` will be ignored. */ @@ -355,6 +355,49 @@ struct aws_credentials_provider_sts_web_identity_options { struct aws_auth_http_system_vtable *function_table; }; +/* + * Configuration for the SSOCredentialsProvider that sends a GetRoleCredentialsRequest to the AWS Single + * Sign-On Service to maintain short-lived sessions to use for authentication. + * + * https://docs.aws.amazon.com/sdkref/latest/guide/feature-sso-credentials.html + */ +struct aws_credentials_provider_sso_options { + struct aws_credentials_provider_shutdown_options shutdown_options; + + /* + * Override of what profile to use to source credentials from ('default' by default) + */ + struct aws_byte_cursor profile_name_override; + + /* + * Override path to the profile config file (~/.aws/config by default) + */ + struct aws_byte_cursor config_file_name_override; + + /** + * (Optional) + * Use a cached config profile collection. You can also pass a merged collection. + * config_file_name_override will be ignored if this option is provided. + */ + struct aws_profile_collection *config_file_cached; + + /* + * Connection bootstrap to use for any network connections made while sourcing credentials + * Required. + */ + struct aws_client_bootstrap *bootstrap; + + /* + * Client TLS context to use when querying SSO provider. + * Required. + */ + struct aws_tls_ctx *tls_ctx; + + /* For mocking, leave NULL otherwise */ + struct aws_auth_http_system_vtable *function_table; + aws_io_clock_fn *system_clock_fn; +}; + /** * Configuration options for the STS credentials provider */ @@ -457,7 +500,7 @@ struct aws_credentials_provider_chain_default_options { /** * (Optional) * Use a cached merged profile collection. A merge collection has both config file - * (~/.aws/profile) and credentials file based profile collection (~/.aws/credentials) using + * (~/.aws/config) and credentials file based profile collection (~/.aws/credentials) using * `aws_profile_collection_new_from_merge`. * If this option is provided, `config_file_name_override` and `credentials_file_name_override` will be ignored. */ @@ -733,7 +776,7 @@ struct aws_ecc_key_pair *aws_ecc_key_pair_new_ecdsa_p256_key_from_aws_credential /** * Release a reference to a credentials provider * - * @param provider provider to increment the ref count on + * @param provider provider to decrement the ref count on */ AWS_AUTH_API struct aws_credentials_provider *aws_credentials_provider_release(struct aws_credentials_provider *provider); @@ -741,7 +784,7 @@ struct aws_credentials_provider *aws_credentials_provider_release(struct aws_cre /* * Add a reference to a credentials provider * - * @param provider provider to decrement the ref count on + * @param provider provider to increment the ref count on */ AWS_AUTH_API struct aws_credentials_provider *aws_credentials_provider_acquire(struct aws_credentials_provider *provider); @@ -927,6 +970,19 @@ struct aws_credentials_provider *aws_credentials_provider_new_sts_web_identity( struct aws_allocator *allocator, const struct aws_credentials_provider_sts_web_identity_options *options); +/** + * Creates a provider that sources credentials from SSO using a SSOToken. + * + * @param allocator memory allocator to use for all memory allocation + * @param options provider-specific configuration options + * + * @return the newly-constructed credentials provider, or NULL if an error occurred. + */ +AWS_AUTH_API +struct aws_credentials_provider *aws_credentials_provider_new_sso( + struct aws_allocator *allocator, + const struct aws_credentials_provider_sso_options *options); + /* * Creates a provider that sources credentials from running an external command or process * diff --git a/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/credentials_utils.h b/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/credentials_utils.h index 7bba24331ef..598c3ba0626 100644 --- a/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/credentials_utils.h +++ b/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/credentials_utils.h @@ -73,6 +73,7 @@ struct aws_auth_http_system_vtable { enum aws_parse_credentials_expiration_format { AWS_PCEF_STRING_ISO_8601_DATE, AWS_PCEF_NUMBER_UNIX_EPOCH, + AWS_PCEF_NUMBER_UNIX_EPOCH_MS, }; struct aws_parse_credentials_from_json_doc_options { @@ -80,6 +81,7 @@ struct aws_parse_credentials_from_json_doc_options { const char *secret_access_key_name; const char *token_name; const char *expiration_name; + const char *top_level_object_name; enum aws_parse_credentials_expiration_format expiration_format; bool token_required; bool expiration_required; @@ -154,12 +156,20 @@ struct aws_credentials *aws_parse_credentials_from_aws_json_object( AWS_AUTH_API struct aws_credentials *aws_parse_credentials_from_json_document( struct aws_allocator *allocator, - const char *json_document, + struct aws_byte_cursor json_document, const struct aws_parse_credentials_from_json_doc_options *options); AWS_AUTH_API enum aws_retry_error_type aws_credentials_provider_compute_retry_error_type(int response_code, int error_code); +/* + * Loads an aws config profile collection + */ +AWS_AUTH_API +struct aws_profile_collection *aws_load_profile_collection_from_config_file( + struct aws_allocator *allocator, + struct aws_byte_cursor config_file_name_override); + AWS_EXTERN_C_END #endif /* AWS_AUTH_CREDENTIALS_PRIVATE_H */ diff --git a/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/sso_token_providers.h b/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/sso_token_providers.h new file mode 100644 index 00000000000..a9f93079426 --- /dev/null +++ b/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/sso_token_providers.h @@ -0,0 +1,112 @@ +#ifndef AWS_AUTH_TOKEN_PROVIDERS_PRIVATE_H +#define AWS_AUTH_TOKEN_PROVIDERS_PRIVATE_H + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/auth/auth.h> +#include <aws/auth/credentials.h> + +/** + * Configuration options for a provider that sources sso token information from the aws profile (by default + * ~/.aws/config) and token from ~/.aws/sso/cache/<sha1 of start url>.json. + */ +struct aws_token_provider_sso_profile_options { + struct aws_credentials_provider_shutdown_options shutdown_options; + + /* + * Override of what profile to use to source credentials from ('default' by default) + */ + struct aws_byte_cursor profile_name_override; + + /* + * Override path to the profile config file (~/.aws/config by default) + */ + struct aws_byte_cursor config_file_name_override; + + /** + * (Optional) + * Use a cached config profile collection. You can also pass a merged collection. + * config_file_name_override will be ignored if this option is provided. + */ + struct aws_profile_collection *config_file_cached; + + /* For mocking, leave NULL otherwise */ + aws_io_clock_fn *system_clock_fn; +}; + +/** + * Configuration options for a provider that sources sso token information from the aws profile (by default + * ~/.aws/config) and token from ~/.aws/sso/cache/<sha1 of session name>.json. + */ +struct aws_token_provider_sso_session_options { + struct aws_credentials_provider_shutdown_options shutdown_options; + + /* + * Override of what profile to use to source credentials from ('default' by default) + */ + struct aws_byte_cursor profile_name_override; + + /* + * Override path to the profile config file (~/.aws/config by default) + */ + struct aws_byte_cursor config_file_name_override; + + /** + * (Optional) + * Use a cached config profile collection. You can also pass a merged collection. + * config_file_name_override will be ignored if this option is provided. + */ + struct aws_profile_collection *config_file_cached; + + /* + * Connection bootstrap to use for any network connections made + */ + struct aws_client_bootstrap *bootstrap; + + /* + * Client TLS context to use for any network connections made. + */ + struct aws_tls_ctx *tls_ctx; + + /* For mocking, leave NULL otherwise */ + aws_io_clock_fn *system_clock_fn; +}; + +AWS_EXTERN_C_BEGIN + +/** + * Creates a provider that sources sso token based credentials from key-value profiles loaded from the aws + * config("~/.aws/config" by default) and ~/.aws/sso/cache/<sha1 of start url>.json + * This is the legacy way which doesn't support refreshing credentials. + * + * @param allocator memory allocator to use for all memory allocation + * @param options provider-specific configuration options + * + * @return the newly-constructed credentials provider, or NULL if an error occurred. + */ +AWS_AUTH_API +struct aws_credentials_provider *aws_token_provider_new_sso_profile( + struct aws_allocator *allocator, + const struct aws_token_provider_sso_profile_options *options); + +/** + * Creates a provider that sources sso token based credentials from key-value profiles loaded from the aws + * config("~/.aws/config" by default) and ~/.aws/sso/cache/<sha1 of session name>.json + * Note: Token refresh is not currently supported + * + * @param allocator memory allocator to use for all memory allocation + * @param options provider-specific configuration options + * + * @return the newly-constructed credentials provider, or NULL if an error occurred. + */ +AWS_AUTH_API +struct aws_credentials_provider *aws_token_provider_new_sso_session( + struct aws_allocator *allocator, + const struct aws_token_provider_sso_session_options *options); + +AWS_EXTERN_C_END + +#endif /* AWS_AUTH_TOKEN_PROVIDERS_PRIVATE_H */ diff --git a/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/sso_token_utils.h b/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/sso_token_utils.h new file mode 100644 index 00000000000..42c5c2bfe48 --- /dev/null +++ b/contrib/restricted/aws/aws-c-auth/include/aws/auth/private/sso_token_utils.h @@ -0,0 +1,58 @@ +#ifndef AWS_AUTH_TOKEN_PRIVATE_H +#define AWS_AUTH_TOKEN_PRIVATE_H + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/auth/auth.h> +#include <aws/common/date_time.h> + +/* structure to represent a parsed sso token */ +struct aws_sso_token { + struct aws_allocator *allocator; + + struct aws_string *access_token; + struct aws_date_time expiration; +}; + +AWS_EXTERN_C_BEGIN + +/* Construct token path which is ~/.aws/sso/cache/<hex encoded sha1 of input>.json */ +AWS_AUTH_API +struct aws_string *aws_construct_sso_token_path(struct aws_allocator *allocator, const struct aws_string *input); + +AWS_AUTH_API +void aws_sso_token_destroy(struct aws_sso_token *token); + +/* Parse `aws_sso_token` from the give file path */ +AWS_AUTH_API +struct aws_sso_token *aws_sso_token_new_from_file(struct aws_allocator *allocator, const struct aws_string *file_path); + +/** + * Creates a set of AWS credentials based on a token with expiration. + * + * @param allocator memory allocator to use for all memory allocation + * @param token token for the credentials + * @param expiration_timepoint_in_seconds time at which these credentials expire + * @return a new pair of AWS credentials, or NULL + */ +AWS_AUTH_API +struct aws_credentials *aws_credentials_new_token( + struct aws_allocator *allocator, + struct aws_byte_cursor token, + uint64_t expiration_timepoint_in_seconds); + +/** + * Get the token from a set of AWS credentials + * + * @param credentials credentials to get the token from + * @return a byte cursor to the token or an empty byte cursor if there is no token + */ +AWS_AUTH_API +struct aws_byte_cursor aws_credentials_get_token(const struct aws_credentials *credentials); + +AWS_EXTERN_C_END + +#endif /* AWS_AUTH_TOKEN_PRIVATE_H */ diff --git a/contrib/restricted/aws/aws-c-auth/source/auth.c b/contrib/restricted/aws/aws-c-auth/source/auth.c index b3fb4d3f5c1..5a0fbc8ca6d 100644 --- a/contrib/restricted/aws/aws-c-auth/source/auth.c +++ b/contrib/restricted/aws/aws-c-auth/source/auth.c @@ -91,6 +91,18 @@ static struct aws_error_info s_errors[] = { AWS_DEFINE_ERROR_INFO_AUTH( AWS_AUTH_CREDENTIALS_PROVIDER_DELEGATE_FAILURE, "Valid credentials could not be sourced by the delegate provider"), + AWS_DEFINE_ERROR_INFO_AUTH( + AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE, + "Valid token could not be sourced by the sso token provider"), + AWS_DEFINE_ERROR_INFO_AUTH( + AWS_AUTH_SSO_TOKEN_INVALID, + "Token sourced by the sso token provider is invalid."), + AWS_DEFINE_ERROR_INFO_AUTH( + AWS_AUTH_SSO_TOKEN_EXPIRED, + "Token sourced by the sso token provider is expired."), + AWS_DEFINE_ERROR_INFO_AUTH( + AWS_AUTH_CREDENTIALS_PROVIDER_SSO_SOURCE_FAILURE, + "Valid credentials could not be sourced by the sso credentials provider"), }; /* clang-format on */ diff --git a/contrib/restricted/aws/aws-c-auth/source/aws_imds_client.c b/contrib/restricted/aws/aws-c-auth/source/aws_imds_client.c index d5e7352dd00..5ef16bc408d 100644 --- a/contrib/restricted/aws/aws-c-auth/source/aws_imds_client.c +++ b/contrib/restricted/aws/aws-c-auth/source/aws_imds_client.c @@ -1039,7 +1039,7 @@ static void s_process_credentials_resource(const struct aws_byte_buf *resource, }; credentials = aws_parse_credentials_from_json_document( - wrapped_user_data->allocator, (const char *)json_data.buffer, &parse_options); + wrapped_user_data->allocator, aws_byte_cursor_from_buf(&json_data), &parse_options); on_finish: wrapped_user_data->callback(credentials, error_code, wrapped_user_data->user_data); diff --git a/contrib/restricted/aws/aws-c-auth/source/credentials.c b/contrib/restricted/aws/aws-c-auth/source/credentials.c index f838c3e17ee..3340663dc51 100644 --- a/contrib/restricted/aws/aws-c-auth/source/credentials.c +++ b/contrib/restricted/aws/aws-c-auth/source/credentials.c @@ -5,22 +5,45 @@ #include <aws/auth/credentials.h> +#include <aws/auth/private/sso_token_utils.h> #include <aws/cal/ecc.h> #include <aws/common/environment.h> #include <aws/common/string.h> +/* aws ecc identity which contains the data needed to sign a Sigv4a AWS request */ +struct aws_ecc_identity { + struct aws_string *access_key_id; + struct aws_string *session_token; + struct aws_ecc_key_pair *ecc_key; +}; + +/* aws credentials identity which contains the data needed to sign an authenticated AWS request */ +struct aws_credentials_identity { + struct aws_string *access_key_id; + struct aws_string *secret_access_key; + struct aws_string *session_token; +}; + +/* aws_token identity contains only a token to represent token only identities like a bearer token. */ +struct aws_token_identity { + struct aws_string *token; +}; + +enum aws_identity_type { + AWS_CREDENTIALS_IDENTITY, + TOKEN_IDENTITY, + ANONYMOUS_IDENTITY, + ECC_IDENTITY, +}; + /* - * A structure that wraps the public/private data needed to sign an authenticated AWS request + * A structure that wraps the different types of credentials that the customer can provider to establish their + * identity. */ struct aws_credentials { struct aws_allocator *allocator; struct aws_atomic_var ref_count; - - struct aws_string *access_key_id; - struct aws_string *secret_access_key; - struct aws_string *session_token; - /* * A timepoint, in seconds since epoch, at which the credentials should no longer be used because they * will have expired. @@ -51,7 +74,12 @@ struct aws_credentials { */ uint64_t expiration_timepoint_seconds; - struct aws_ecc_key_pair *ecc_key; + enum aws_identity_type identity_type; + union { + struct aws_credentials_identity credentials_identity; + struct aws_token_identity token_identity; + struct aws_ecc_identity ecc_identity; + } identity; }; /* @@ -83,23 +111,24 @@ struct aws_credentials *aws_credentials_new( credentials->allocator = allocator; aws_atomic_init_int(&credentials->ref_count, 1); - - credentials->access_key_id = + credentials->identity_type = AWS_CREDENTIALS_IDENTITY; + struct aws_credentials_identity *credentials_identity = &credentials->identity.credentials_identity; + credentials_identity->access_key_id = aws_string_new_from_array(allocator, access_key_id_cursor.ptr, access_key_id_cursor.len); - if (credentials->access_key_id == NULL) { + if (credentials_identity->access_key_id == NULL) { goto error; } - credentials->secret_access_key = + credentials_identity->secret_access_key = aws_string_new_from_array(allocator, secret_access_key_cursor.ptr, secret_access_key_cursor.len); - if (credentials->secret_access_key == NULL) { + if (credentials_identity->secret_access_key == NULL) { goto error; } if (session_token_cursor.ptr != NULL && session_token_cursor.len > 0) { - credentials->session_token = + credentials_identity->session_token = aws_string_new_from_array(allocator, session_token_cursor.ptr, session_token_cursor.len); - if (credentials->session_token == NULL) { + if (credentials_identity->session_token == NULL) { goto error; } } @@ -120,6 +149,7 @@ struct aws_credentials *aws_credentials_new_anonymous(struct aws_allocator *allo struct aws_credentials *credentials = aws_mem_calloc(allocator, 1, sizeof(struct aws_credentials)); credentials->allocator = allocator; + credentials->identity_type = ANONYMOUS_IDENTITY; aws_atomic_init_int(&credentials->ref_count, 1); credentials->expiration_timepoint_seconds = UINT64_MAX; @@ -131,21 +161,24 @@ static void s_aws_credentials_destroy(struct aws_credentials *credentials) { if (credentials == NULL) { return; } - - if (credentials->access_key_id != NULL) { - aws_string_destroy(credentials->access_key_id); - } - - if (credentials->secret_access_key != NULL) { - aws_string_destroy_secure(credentials->secret_access_key); + switch (credentials->identity_type) { + case AWS_CREDENTIALS_IDENTITY: + aws_string_destroy(credentials->identity.credentials_identity.access_key_id); + aws_string_destroy_secure(credentials->identity.credentials_identity.secret_access_key); + aws_string_destroy_secure(credentials->identity.credentials_identity.session_token); + break; + case ECC_IDENTITY: + aws_string_destroy(credentials->identity.ecc_identity.access_key_id); + aws_string_destroy_secure(credentials->identity.ecc_identity.session_token); + aws_ecc_key_pair_release(credentials->identity.ecc_identity.ecc_key); + break; + case TOKEN_IDENTITY: + aws_string_destroy_secure(credentials->identity.token_identity.token); + break; + case ANONYMOUS_IDENTITY: + break; } - if (credentials->session_token != NULL) { - aws_string_destroy_secure(credentials->session_token); - } - - aws_ecc_key_pair_release(credentials->ecc_key); - aws_mem_release(credentials->allocator, credentials); } @@ -174,26 +207,64 @@ static struct aws_byte_cursor s_empty_token_cursor = { }; struct aws_byte_cursor aws_credentials_get_access_key_id(const struct aws_credentials *credentials) { - if (credentials->access_key_id == NULL) { - return s_empty_token_cursor; + switch (credentials->identity_type) { + case AWS_CREDENTIALS_IDENTITY: + if (credentials->identity.credentials_identity.access_key_id != NULL) { + return aws_byte_cursor_from_string(credentials->identity.credentials_identity.access_key_id); + } + break; + case ECC_IDENTITY: + if (credentials->identity.ecc_identity.access_key_id != NULL) { + return aws_byte_cursor_from_string(credentials->identity.ecc_identity.access_key_id); + } + break; + default: + break; } - - return aws_byte_cursor_from_string(credentials->access_key_id); + return s_empty_token_cursor; } struct aws_byte_cursor aws_credentials_get_secret_access_key(const struct aws_credentials *credentials) { - if (credentials->secret_access_key == NULL) { - return s_empty_token_cursor; + switch (credentials->identity_type) { + case AWS_CREDENTIALS_IDENTITY: + if (credentials->identity.credentials_identity.secret_access_key != NULL) { + return aws_byte_cursor_from_string(credentials->identity.credentials_identity.secret_access_key); + } + break; + default: + break; } - - return aws_byte_cursor_from_string(credentials->secret_access_key); + return s_empty_token_cursor; } struct aws_byte_cursor aws_credentials_get_session_token(const struct aws_credentials *credentials) { - if (credentials->session_token != NULL) { - return aws_byte_cursor_from_string(credentials->session_token); + switch (credentials->identity_type) { + case AWS_CREDENTIALS_IDENTITY: + if (credentials->identity.credentials_identity.session_token != NULL) { + return aws_byte_cursor_from_string(credentials->identity.credentials_identity.session_token); + } + break; + case ECC_IDENTITY: + if (credentials->identity.ecc_identity.session_token != NULL) { + return aws_byte_cursor_from_string(credentials->identity.ecc_identity.session_token); + } + break; + default: + break; } + return s_empty_token_cursor; +} +struct aws_byte_cursor aws_credentials_get_token(const struct aws_credentials *credentials) { + switch (credentials->identity_type) { + case TOKEN_IDENTITY: + if (credentials->identity.token_identity.token != NULL) { + return aws_byte_cursor_from_string(credentials->identity.token_identity.token); + } + break; + default: + break; + } return s_empty_token_cursor; } @@ -202,12 +273,15 @@ uint64_t aws_credentials_get_expiration_timepoint_seconds(const struct aws_crede } struct aws_ecc_key_pair *aws_credentials_get_ecc_key_pair(const struct aws_credentials *credentials) { - return credentials->ecc_key; + if (credentials->identity_type == ECC_IDENTITY) { + return credentials->identity.ecc_identity.ecc_key; + } + return NULL; } bool aws_credentials_is_anonymous(const struct aws_credentials *credentials) { AWS_PRECONDITION(credentials); - return credentials->access_key_id == NULL && credentials->secret_access_key == NULL; + return credentials->identity_type == ANONYMOUS_IDENTITY; } struct aws_credentials *aws_credentials_new_from_string( @@ -250,16 +324,19 @@ struct aws_credentials *aws_credentials_new_ecc( credentials->expiration_timepoint_seconds = expiration_timepoint_in_seconds; aws_atomic_init_int(&credentials->ref_count, 1); aws_ecc_key_pair_acquire(ecc_key); - credentials->ecc_key = ecc_key; + credentials->identity_type = ECC_IDENTITY; + credentials->identity.ecc_identity.ecc_key = ecc_key; - credentials->access_key_id = aws_string_new_from_array(allocator, access_key_id.ptr, access_key_id.len); - if (credentials->access_key_id == NULL) { + credentials->identity.ecc_identity.access_key_id = + aws_string_new_from_array(allocator, access_key_id.ptr, access_key_id.len); + if (credentials->identity.ecc_identity.access_key_id == NULL) { goto on_error; } if (session_token.ptr != NULL && session_token.len > 0) { - credentials->session_token = aws_string_new_from_array(allocator, session_token.ptr, session_token.len); - if (credentials->session_token == NULL) { + credentials->identity.ecc_identity.session_token = + aws_string_new_from_array(allocator, session_token.ptr, session_token.len); + if (credentials->identity.ecc_identity.session_token == NULL) { goto on_error; } } @@ -295,6 +372,25 @@ struct aws_credentials *aws_credentials_new_ecc_from_aws_credentials( return ecc_credentials; } +struct aws_credentials *aws_credentials_new_token( + struct aws_allocator *allocator, + struct aws_byte_cursor token, + uint64_t expiration_timepoint_in_seconds) { + if (token.ptr == NULL || token.len == 0) { + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + return NULL; + } + struct aws_credentials *credentials = aws_mem_calloc(allocator, 1, sizeof(struct aws_credentials)); + + credentials->allocator = allocator; + aws_atomic_init_int(&credentials->ref_count, 1); + credentials->identity_type = TOKEN_IDENTITY; + struct aws_token_identity *token_identity = &credentials->identity.token_identity; + token_identity->token = aws_string_new_from_array(allocator, token.ptr, token.len); + credentials->expiration_timepoint_seconds = expiration_timepoint_in_seconds; + return credentials; +} + /* * global credentials provider APIs */ diff --git a/contrib/restricted/aws/aws-c-auth/source/credentials_provider_ecs.c b/contrib/restricted/aws/aws-c-auth/source/credentials_provider_ecs.c index 91c74f0852e..7d96cf3a243 100644 --- a/contrib/restricted/aws/aws-c-auth/source/credentials_provider_ecs.c +++ b/contrib/restricted/aws/aws-c-auth/source/credentials_provider_ecs.c @@ -145,7 +145,7 @@ static void s_ecs_finalize_get_credentials_query(struct aws_credentials_provider }; if (aws_byte_buf_append_null_terminator(&ecs_user_data->current_result) == AWS_OP_SUCCESS) { credentials = aws_parse_credentials_from_json_document( - ecs_user_data->allocator, (const char *)ecs_user_data->current_result.buffer, &parse_options); + ecs_user_data->allocator, aws_byte_cursor_from_buf(&ecs_user_data->current_result), &parse_options); } else { AWS_LOGF_ERROR( AWS_LS_AUTH_CREDENTIALS_PROVIDER, diff --git a/contrib/restricted/aws/aws-c-auth/source/credentials_provider_process.c b/contrib/restricted/aws/aws-c-auth/source/credentials_provider_process.c index 29f99d09280..e1c0bfbf00a 100644 --- a/contrib/restricted/aws/aws-c-auth/source/credentials_provider_process.c +++ b/contrib/restricted/aws/aws-c-auth/source/credentials_provider_process.c @@ -56,8 +56,8 @@ static int s_get_credentials_from_process( .expiration_required = false, }; - credentials = - aws_parse_credentials_from_json_document(provider->allocator, aws_string_c_str(result.std_out), &parse_options); + credentials = aws_parse_credentials_from_json_document( + provider->allocator, aws_byte_cursor_from_string(result.std_out), &parse_options); if (!credentials) { AWS_LOGF_INFO( AWS_LS_AUTH_CREDENTIALS_PROVIDER, diff --git a/contrib/restricted/aws/aws-c-auth/source/credentials_provider_sso.c b/contrib/restricted/aws/aws-c-auth/source/credentials_provider_sso.c new file mode 100644 index 00000000000..e7c39e75d5a --- /dev/null +++ b/contrib/restricted/aws/aws-c-auth/source/credentials_provider_sso.c @@ -0,0 +1,851 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/auth/credentials.h> + +#include <aws/auth/private/aws_profile.h> +#include <aws/auth/private/credentials_utils.h> +#include <aws/auth/private/sso_token_providers.h> +#include <aws/auth/private/sso_token_utils.h> + +#include <aws/common/clock.h> +#include <aws/http/connection_manager.h> +#include <aws/http/request_response.h> +#include <aws/http/status_code.h> +#include <aws/io/channel_bootstrap.h> +#include <aws/io/socket.h> +#include <aws/io/tls_channel_handler.h> +#include <aws/io/uri.h> + +#if defined(_MSC_VER) +# pragma warning(disable : 4204) +#endif /* _MSC_VER */ + +#define SSO_RESPONSE_SIZE_INITIAL 2048 +#define SSO_RESPONSE_SIZE_LIMIT 10000 +#define SSO_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS 2 +#define SSO_MAX_ATTEMPTS 3 +#define SSO_RETRY_TIMEOUT_MS 100 + +struct aws_credentials_provider_sso_impl { + struct aws_http_connection_manager *connection_manager; + const struct aws_auth_http_system_vtable *function_table; + struct aws_string *endpoint; + struct aws_string *sso_account_id; + struct aws_string *sso_role_name; + struct aws_credentials_provider *token_provider; + struct aws_retry_strategy *retry_strategy; +}; + +/** + * aws_sso_query_context - context for each outstanding SSO query. + */ +struct aws_sso_query_context { + /* immutable post-creation */ + struct aws_allocator *allocator; + struct aws_credentials_provider *provider; + aws_on_get_credentials_callback_fn *original_callback; + void *original_user_data; + + /* mutable */ + struct aws_http_connection *connection; + struct aws_http_message *request; + struct aws_byte_buf payload; + struct aws_retry_token *retry_token; + struct aws_byte_buf path_and_query; + struct aws_string *token; + + int status_code; + int error_code; +}; + +/* called in between retries. */ +static void s_sso_query_context_reset_request_specific_data(struct aws_sso_query_context *sso_query_context) { + if (sso_query_context->request) { + aws_http_message_release(sso_query_context->request); + sso_query_context->request = NULL; + } + if (sso_query_context->connection) { + struct aws_credentials_provider_sso_impl *provider_impl = sso_query_context->provider->impl; + int result = provider_impl->function_table->aws_http_connection_manager_release_connection( + provider_impl->connection_manager, sso_query_context->connection); + (void)result; + AWS_ASSERT(result == AWS_OP_SUCCESS); + sso_query_context->connection = NULL; + } + if (sso_query_context->token) { + aws_string_destroy_secure(sso_query_context->token); + sso_query_context->token = NULL; + } + sso_query_context->status_code = 0; + sso_query_context->error_code = 0; +} + +static void s_sso_query_context_destroy(struct aws_sso_query_context *sso_query_context) { + if (sso_query_context == NULL) { + return; + } + + s_sso_query_context_reset_request_specific_data(sso_query_context); + aws_byte_buf_clean_up(&sso_query_context->payload); + aws_byte_buf_clean_up(&sso_query_context->path_and_query); + aws_credentials_provider_release(sso_query_context->provider); + aws_retry_token_release(sso_query_context->retry_token); + aws_mem_release(sso_query_context->allocator, sso_query_context); +} + +static struct aws_sso_query_context *s_sso_query_context_new( + struct aws_credentials_provider *provider, + aws_on_get_credentials_callback_fn callback, + void *user_data) { + struct aws_credentials_provider_sso_impl *impl = provider->impl; + + struct aws_sso_query_context *sso_query_context = + aws_mem_calloc(provider->allocator, 1, sizeof(struct aws_sso_query_context)); + sso_query_context->allocator = provider->allocator; + sso_query_context->provider = aws_credentials_provider_acquire(provider); + sso_query_context->original_user_data = user_data; + sso_query_context->original_callback = callback; + + /* construct path and query */ + struct aws_byte_cursor account_id_cursor = aws_byte_cursor_from_string(impl->sso_account_id); + struct aws_byte_cursor role_name_cursor = aws_byte_cursor_from_string(impl->sso_role_name); + struct aws_byte_cursor path_cursor = aws_byte_cursor_from_c_str("/federation/credentials?account_id="); + struct aws_byte_cursor role_name_param_cursor = aws_byte_cursor_from_c_str("&role_name="); + + if (aws_byte_buf_init_copy_from_cursor(&sso_query_context->path_and_query, provider->allocator, path_cursor) || + aws_byte_buf_append_encoding_uri_param(&sso_query_context->path_and_query, &account_id_cursor) || + aws_byte_buf_append_dynamic(&sso_query_context->path_and_query, &role_name_param_cursor) || + aws_byte_buf_append_encoding_uri_param(&sso_query_context->path_and_query, &role_name_cursor)) { + goto on_error; + } + + if (aws_byte_buf_init(&sso_query_context->payload, provider->allocator, SSO_RESPONSE_SIZE_INITIAL)) { + goto on_error; + } + + return sso_query_context; + +on_error: + s_sso_query_context_destroy(sso_query_context); + + return NULL; +} + +/* + * No matter the result, this always gets called assuming that sso_query_context is successfully allocated + */ +static void s_finalize_get_credentials_query(struct aws_sso_query_context *sso_query_context) { + struct aws_credentials *credentials = NULL; + + if (sso_query_context->error_code == AWS_ERROR_SUCCESS) { + /* parse credentials */ + struct aws_parse_credentials_from_json_doc_options parse_options = { + .access_key_id_name = "accessKeyId", + .secret_access_key_name = "secretAccessKey", + .token_name = "sessionToken", + .expiration_name = "expiration", + .top_level_object_name = "roleCredentials", + .token_required = true, + .expiration_required = true, + .expiration_format = AWS_PCEF_NUMBER_UNIX_EPOCH_MS, + }; + + credentials = aws_parse_credentials_from_json_document( + sso_query_context->allocator, aws_byte_cursor_from_buf(&sso_query_context->payload), &parse_options); + } + + if (credentials) { + AWS_LOGF_INFO( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) successfully queried credentials", + (void *)sso_query_context->provider); + } else { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) failed to query credentials", + (void *)sso_query_context->provider); + + if (sso_query_context->error_code == AWS_ERROR_SUCCESS) { + sso_query_context->error_code = AWS_AUTH_CREDENTIALS_PROVIDER_SSO_SOURCE_FAILURE; + } + } + + /* pass the credentials back */ + sso_query_context->original_callback( + credentials, sso_query_context->error_code, sso_query_context->original_user_data); + + /* clean up */ + s_sso_query_context_destroy(sso_query_context); + aws_credentials_release(credentials); +} +static void s_on_retry_ready(struct aws_retry_token *token, int error_code, void *user_data); + +static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_code, void *user_data) { + struct aws_sso_query_context *sso_query_context = user_data; + + struct aws_credentials_provider_sso_impl *impl = sso_query_context->provider->impl; + impl->function_table->aws_http_stream_release(stream); + + /* set error code */ + sso_query_context->error_code = error_code; + impl->function_table->aws_http_stream_get_incoming_response_status(stream, &sso_query_context->status_code); + if (error_code == AWS_OP_SUCCESS && sso_query_context->status_code != AWS_HTTP_STATUS_CODE_200_OK) { + sso_query_context->error_code = AWS_AUTH_CREDENTIALS_PROVIDER_HTTP_STATUS_FAILURE; + } + + /* + * If we can retry the request based on error response or http status code failure, retry it, otherwise, call the + * finalize function. + */ + if (error_code || sso_query_context->status_code != AWS_HTTP_STATUS_CODE_200_OK) { + enum aws_retry_error_type error_type = + aws_credentials_provider_compute_retry_error_type(sso_query_context->status_code, error_code); + + /* don't retry client errors at all. */ + if (error_type != AWS_RETRY_ERROR_TYPE_CLIENT_ERROR) { + if (aws_retry_strategy_schedule_retry( + sso_query_context->retry_token, error_type, s_on_retry_ready, sso_query_context) == + AWS_OP_SUCCESS) { + AWS_LOGF_INFO( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): successfully scheduled a retry", + (void *)sso_query_context->provider); + return; + } + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): failed to schedule retry: %s", + (void *)sso_query_context->provider, + aws_error_str(aws_last_error())); + sso_query_context->error_code = aws_last_error(); + } + } else { + int result = aws_retry_token_record_success(sso_query_context->retry_token); + (void)result; + AWS_ASSERT(result == AWS_ERROR_SUCCESS); + } + + s_finalize_get_credentials_query(sso_query_context); +} + +static int s_on_incoming_body_fn(struct aws_http_stream *stream, const struct aws_byte_cursor *body, void *user_data) { + + (void)stream; + + struct aws_sso_query_context *sso_query_context = user_data; + + AWS_LOGF_TRACE( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) received %zu response bytes", + (void *)sso_query_context->provider, + body->len); + + if (body->len + sso_query_context->payload.len > SSO_RESPONSE_SIZE_LIMIT) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) response exceeded maximum allowed length", + (void *)sso_query_context->provider); + + return aws_raise_error(AWS_ERROR_SHORT_BUFFER); + } + + if (aws_byte_buf_append_dynamic(&sso_query_context->payload, body)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) error appending response payload: %s", + (void *)sso_query_context->provider, + aws_error_str(aws_last_error())); + + return AWS_OP_ERR; + } + + return AWS_OP_SUCCESS; +} + +/* Request headers. */ +AWS_STATIC_STRING_FROM_LITERAL(s_sso_token_header, "x-amz-sso_bearer_token"); +AWS_STATIC_STRING_FROM_LITERAL(s_sso_user_agent_header, "User-Agent"); +AWS_STATIC_STRING_FROM_LITERAL(s_sso_user_agent_header_value, "aws-sdk-crt/sso-credentials-provider"); + +static void s_query_credentials(struct aws_sso_query_context *sso_query_context) { + AWS_FATAL_ASSERT(sso_query_context->connection); + struct aws_http_stream *stream = NULL; + struct aws_credentials_provider_sso_impl *impl = sso_query_context->provider->impl; + + sso_query_context->request = aws_http_message_new_request(sso_query_context->allocator); + if (sso_query_context->request == NULL) { + goto on_error; + } + + struct aws_http_header auth_header = { + .name = aws_byte_cursor_from_string(s_sso_token_header), + .value = aws_byte_cursor_from_string(sso_query_context->token), + }; + struct aws_http_header host_header = { + .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Host"), + .value = aws_byte_cursor_from_string(impl->endpoint), + }; + struct aws_http_header user_agent_header = { + .name = aws_byte_cursor_from_string(s_sso_user_agent_header), + .value = aws_byte_cursor_from_string(s_sso_user_agent_header_value), + }; + + if (aws_http_message_add_header(sso_query_context->request, auth_header) || + aws_http_message_add_header(sso_query_context->request, host_header) || + aws_http_message_add_header(sso_query_context->request, user_agent_header)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) failed to add http header with error: %s", + (void *)sso_query_context->provider, + aws_error_debug_str(aws_last_error())); + goto on_error; + } + + if (aws_http_message_set_request_method(sso_query_context->request, aws_http_method_get)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) failed to set request method with error: %s", + (void *)sso_query_context->provider, + aws_error_debug_str(aws_last_error())); + goto on_error; + } + + if (aws_http_message_set_request_path( + sso_query_context->request, aws_byte_cursor_from_buf(&sso_query_context->path_and_query))) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) failed to set request path with error: %s", + (void *)sso_query_context->provider, + aws_error_debug_str(aws_last_error())); + goto on_error; + } + + struct aws_http_make_request_options request_options = { + .self_size = sizeof(request_options), + .on_response_headers = NULL, + .on_response_header_block_done = NULL, + .on_response_body = s_on_incoming_body_fn, + .on_complete = s_on_stream_complete_fn, + .user_data = sso_query_context, + .request = sso_query_context->request, + }; + + stream = impl->function_table->aws_http_connection_make_request(sso_query_context->connection, &request_options); + if (!stream) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) failed to make request with error: %s", + (void *)sso_query_context->provider, + aws_error_debug_str(aws_last_error())); + goto on_error; + } + + if (impl->function_table->aws_http_stream_activate(stream)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p) failed to activate the stream with error: %s", + (void *)sso_query_context->provider, + aws_error_debug_str(aws_last_error())); + goto on_error; + } + + return; + +on_error: + sso_query_context->error_code = aws_last_error(); + impl->function_table->aws_http_stream_release(stream); + s_finalize_get_credentials_query(sso_query_context); +} + +static void s_on_get_token_callback(struct aws_credentials *credentials, int error_code, void *user_data) { + struct aws_sso_query_context *sso_query_context = user_data; + + if (error_code) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "id=%p: failed to acquire a token, error code %d(%s)", + (void *)sso_query_context->provider, + error_code, + aws_error_str(error_code)); + sso_query_context->error_code = error_code; + s_finalize_get_credentials_query(sso_query_context); + return; + } + + struct aws_byte_cursor token = aws_credentials_get_token(credentials); + AWS_LOGF_INFO( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): successfully accquired a token", + (void *)sso_query_context->provider); + + sso_query_context->token = aws_string_new_from_cursor(sso_query_context->allocator, &token); + s_query_credentials(sso_query_context); +} + +static void s_on_acquire_connection(struct aws_http_connection *connection, int error_code, void *user_data) { + struct aws_sso_query_context *sso_query_context = user_data; + + if (error_code) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "id=%p: failed to acquire a connection, error code %d(%s)", + (void *)sso_query_context->provider, + error_code, + aws_error_str(error_code)); + sso_query_context->error_code = error_code; + s_finalize_get_credentials_query(sso_query_context); + return; + } + AWS_LOGF_INFO( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): successfully accquired a connection", + (void *)sso_query_context->provider); + sso_query_context->connection = connection; + + struct aws_credentials_provider_sso_impl *impl = sso_query_context->provider->impl; + if (aws_credentials_provider_get_credentials(impl->token_provider, s_on_get_token_callback, user_data)) { + int last_error_code = aws_last_error(); + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "id=%p: failed to get a token, error code %d(%s)", + (void *)sso_query_context->provider, + last_error_code, + aws_error_str(last_error_code)); + + sso_query_context->error_code = last_error_code; + s_finalize_get_credentials_query(sso_query_context); + } +} + +/* called for each retry. */ +static void s_on_retry_ready(struct aws_retry_token *token, int error_code, void *user_data) { + (void)token; + struct aws_sso_query_context *sso_query_context = user_data; + struct aws_credentials_provider_sso_impl *impl = sso_query_context->provider->impl; + + if (error_code) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): failed to schedule retry with error: %s", + (void *)sso_query_context->provider, + aws_error_debug_str(error_code)); + sso_query_context->error_code = error_code; + s_finalize_get_credentials_query(sso_query_context); + return; + } + + /* clear the result from previous attempt */ + s_sso_query_context_reset_request_specific_data(sso_query_context); + + impl->function_table->aws_http_connection_manager_acquire_connection( + impl->connection_manager, s_on_acquire_connection, sso_query_context); +} + +static void s_on_retry_token_acquired( + struct aws_retry_strategy *strategy, + int error_code, + struct aws_retry_token *token, + void *user_data) { + struct aws_sso_query_context *sso_query_context = user_data; + (void)strategy; + + if (error_code) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): failed to acquire retry token: %s", + (void *)sso_query_context->provider, + aws_error_debug_str(error_code)); + sso_query_context->error_code = error_code; + s_finalize_get_credentials_query(sso_query_context); + return; + } + + sso_query_context->retry_token = token; + struct aws_credentials_provider_sso_impl *impl = sso_query_context->provider->impl; + impl->function_table->aws_http_connection_manager_acquire_connection( + impl->connection_manager, s_on_acquire_connection, user_data); +} + +static int s_credentials_provider_sso_get_credentials( + struct aws_credentials_provider *provider, + aws_on_get_credentials_callback_fn callback, + void *user_data) { + + struct aws_credentials_provider_sso_impl *impl = provider->impl; + + struct aws_sso_query_context *sso_query_context = s_sso_query_context_new(provider, callback, user_data); + if (sso_query_context == NULL) { + return AWS_OP_ERR; + } + + if (aws_retry_strategy_acquire_retry_token( + impl->retry_strategy, NULL, s_on_retry_token_acquired, sso_query_context, SSO_RETRY_TIMEOUT_MS)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): failed to acquire retry token: %s", + (void *)provider, + aws_error_debug_str(aws_last_error())); + goto on_error; + } + + return AWS_OP_SUCCESS; + +on_error: + s_sso_query_context_destroy(sso_query_context); + return AWS_OP_ERR; +} + +static void s_on_connection_manager_shutdown(void *user_data) { + struct aws_credentials_provider *provider = user_data; + + aws_credentials_provider_invoke_shutdown_callback(provider); + aws_mem_release(provider->allocator, provider); +} + +static void s_credentials_provider_sso_destroy(struct aws_credentials_provider *provider) { + + struct aws_credentials_provider_sso_impl *impl = provider->impl; + if (impl == NULL) { + return; + } + aws_string_destroy(impl->endpoint); + aws_string_destroy(impl->sso_account_id); + aws_string_destroy(impl->sso_role_name); + aws_retry_strategy_release(impl->retry_strategy); + aws_credentials_provider_release(impl->token_provider); + + /* aws_http_connection_manager_release will eventually leads to call of s_on_connection_manager_shutdown, + * which will do memory release for provider and impl. So We should be freeing impl + * related memory first, then call aws_http_connection_manager_release. + */ + if (impl->connection_manager) { + impl->function_table->aws_http_connection_manager_release(impl->connection_manager); + } else { + /* If provider setup failed halfway through, connection_manager might not exist. + * In this case invoke shutdown completion callback directly to finish cleanup */ + s_on_connection_manager_shutdown(provider); + } +} + +static struct aws_credentials_provider_vtable s_aws_credentials_provider_sso_vtable = { + .get_credentials = s_credentials_provider_sso_get_credentials, + .destroy = s_credentials_provider_sso_destroy, +}; + +static int s_construct_sso_portal_endpoint( + struct aws_allocator *allocator, + struct aws_byte_buf *out_endpoint, + const struct aws_string *region) { + AWS_PRECONDITION(allocator); + AWS_PRECONDITION(out_endpoint); + + if (!region) { + return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + } + aws_byte_buf_clean_up(out_endpoint); + struct aws_byte_cursor sso_prefix = aws_byte_cursor_from_c_str("portal.sso."); + struct aws_byte_cursor region_cursor = aws_byte_cursor_from_string(region); + struct aws_byte_cursor amazonaws_cursor = aws_byte_cursor_from_c_str(".amazonaws.com"); + struct aws_byte_cursor cn_cursor = aws_byte_cursor_from_c_str(".cn"); + + if (aws_byte_buf_init_copy_from_cursor(out_endpoint, allocator, sso_prefix) || + aws_byte_buf_append_dynamic(out_endpoint, ®ion_cursor) || + aws_byte_buf_append_dynamic(out_endpoint, &amazonaws_cursor)) { + goto on_error; + } + + if (aws_string_eq_c_str_ignore_case(region, "cn-north-1") || + aws_string_eq_c_str_ignore_case(region, "cn-northwest-1")) { + if (aws_byte_buf_append_dynamic(out_endpoint, &cn_cursor)) { + goto on_error; + } + } + return AWS_OP_SUCCESS; + +on_error: + aws_byte_buf_clean_up(out_endpoint); + return AWS_OP_ERR; +} + +AWS_STATIC_STRING_FROM_LITERAL(s_sso_account_id, "sso_account_id"); +AWS_STATIC_STRING_FROM_LITERAL(s_sso_region, "sso_region"); +AWS_STATIC_STRING_FROM_LITERAL(s_sso_role_name, "sso_role_name"); +AWS_STATIC_STRING_FROM_LITERAL(s_sso_session, "sso_session"); + +struct sso_parameters { + struct aws_allocator *allocator; + struct aws_byte_buf endpoint; + struct aws_string *sso_account_id; + struct aws_string *sso_role_name; + struct aws_credentials_provider *token_provider; +}; + +static void s_parameters_destroy(struct sso_parameters *parameters) { + if (!parameters) { + return; + } + aws_byte_buf_clean_up(¶meters->endpoint); + aws_string_destroy(parameters->sso_account_id); + aws_string_destroy(parameters->sso_role_name); + aws_credentials_provider_release(parameters->token_provider); + aws_mem_release(parameters->allocator, parameters); +} + +/** + * Read the config file and construct profile or sso_session token provider based on sso_session property. + * + * If the profile contains sso_session property, a valid config example is as follow. + * [profile sso-profile] + * sso_session = dev + * sso_account_id = 012345678901 + * sso_role_name = SampleRole + * + * [sso-session dev] + * sso_region = us-east-1 + * sso_start_url = https://d-abc123.awsapps.com/start + * + * If the profile does't contains sso_session, the legacy valid config example is as follow. + * [profile sso-profile] + * sso_account_id = 012345678901 + * sso_region = us-east-1 + * sso_role_name = SampleRole + * sso_start_url = https://d-abc123.awsapps.com/start-beta + */ +static struct sso_parameters *s_parameters_new( + struct aws_allocator *allocator, + const struct aws_credentials_provider_sso_options *options) { + + struct sso_parameters *parameters = aws_mem_calloc(allocator, 1, sizeof(struct sso_parameters)); + parameters->allocator = allocator; + + struct aws_profile_collection *config_profile_collection = NULL; + struct aws_string *profile_name = NULL; + bool success = false; + + profile_name = aws_get_profile_name(allocator, &options->profile_name_override); + if (!profile_name) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso: failed to resolve profile name"); + goto on_finish; + } + if (options->config_file_cached) { + /* Use cached config file */ + config_profile_collection = aws_profile_collection_acquire(options->config_file_cached); + } else { + /* load config file */ + config_profile_collection = + aws_load_profile_collection_from_config_file(allocator, options->config_file_name_override); + } + + if (!config_profile_collection) { + goto on_finish; + } + + const struct aws_profile *profile = aws_profile_collection_get_profile(config_profile_collection, profile_name); + if (!profile) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso: failed to load \"%s\" profile", aws_string_c_str(profile_name)); + goto on_finish; + } + + const struct aws_profile_property *sso_account_id = aws_profile_get_property(profile, s_sso_account_id); + const struct aws_profile_property *sso_role_name = aws_profile_get_property(profile, s_sso_role_name); + const struct aws_profile_property *sso_region = NULL; + + if (!sso_account_id) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso: sso_account_id is missing"); + aws_raise_error(AWS_AUTH_CREDENTIALS_PROVIDER_SSO_SOURCE_FAILURE); + goto on_finish; + } + if (!sso_role_name) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso: sso_role_name is missing"); + aws_raise_error(AWS_AUTH_CREDENTIALS_PROVIDER_SSO_SOURCE_FAILURE); + goto on_finish; + } + + const struct aws_profile_property *sso_session_property = aws_profile_get_property(profile, s_sso_session); + /* create the appropriate token provider based on sso_session property is available or not */ + if (sso_session_property) { + /* construct sso_session token provider */ + struct aws_token_provider_sso_session_options token_provider_options = { + .config_file_name_override = options->config_file_name_override, + .config_file_cached = config_profile_collection, + .profile_name_override = options->profile_name_override, + .bootstrap = options->bootstrap, + .tls_ctx = options->tls_ctx, + .system_clock_fn = options->system_clock_fn, + }; + parameters->token_provider = aws_token_provider_new_sso_session(allocator, &token_provider_options); + if (!parameters->token_provider) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso: unable to create a sso token provider"); + aws_raise_error(AWS_AUTH_CREDENTIALS_PROVIDER_SSO_SOURCE_FAILURE); + goto on_finish; + } + sso_region = aws_profile_get_property( + aws_profile_collection_get_section( + config_profile_collection, + AWS_PROFILE_SECTION_TYPE_SSO_SESSION, + aws_profile_property_get_value(sso_session_property)), + s_sso_region); + } else { + /* construct profile token provider */ + struct aws_token_provider_sso_profile_options token_provider_options = { + .config_file_name_override = options->config_file_name_override, + .config_file_cached = config_profile_collection, + .profile_name_override = options->profile_name_override, + .system_clock_fn = options->system_clock_fn, + }; + + parameters->token_provider = aws_token_provider_new_sso_profile(allocator, &token_provider_options); + if (!parameters->token_provider) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso: unable to create a profile token provider"); + aws_raise_error(AWS_AUTH_CREDENTIALS_PROVIDER_SSO_SOURCE_FAILURE); + goto on_finish; + } + sso_region = aws_profile_get_property(profile, s_sso_region); + } + + if (!sso_region) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso: sso_region is missing"); + aws_raise_error(AWS_AUTH_CREDENTIALS_PROVIDER_SSO_SOURCE_FAILURE); + goto on_finish; + } + + parameters->sso_account_id = aws_string_new_from_string(allocator, aws_profile_property_get_value(sso_account_id)); + parameters->sso_role_name = aws_string_new_from_string(allocator, aws_profile_property_get_value(sso_role_name)); + /* determine endpoint */ + if (s_construct_sso_portal_endpoint(allocator, ¶meters->endpoint, aws_profile_property_get_value(sso_region))) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to construct sso endpoint"); + goto on_finish; + } + AWS_LOGF_DEBUG( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Successfully loaded all required parameters for sso credentials provider."); + success = true; + +on_finish: + if (!success) { + s_parameters_destroy(parameters); + parameters = NULL; + } + aws_string_destroy(profile_name); + aws_profile_collection_release(config_profile_collection); + + return parameters; +} + +struct aws_credentials_provider *aws_credentials_provider_new_sso( + struct aws_allocator *allocator, + const struct aws_credentials_provider_sso_options *options) { + + struct sso_parameters *parameters = s_parameters_new(allocator, options); + if (!parameters) { + return NULL; + } + + struct aws_credentials_provider *provider = NULL; + struct aws_credentials_provider_sso_impl *impl = NULL; + struct aws_tls_connection_options tls_connection_options; + + aws_mem_acquire_many( + allocator, + 2, + &provider, + sizeof(struct aws_credentials_provider), + &impl, + sizeof(struct aws_credentials_provider_sso_impl)); + + AWS_ZERO_STRUCT(*provider); + AWS_ZERO_STRUCT(*impl); + AWS_ZERO_STRUCT(tls_connection_options); + + aws_credentials_provider_init_base(provider, allocator, &s_aws_credentials_provider_sso_vtable, impl); + + if (!options->tls_ctx) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p): a TLS context must be provided", (void *)provider); + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + goto on_error; + } + + if (!options->bootstrap) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p): a bootstrap instance must be provided", (void *)provider); + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + goto on_error; + } + + aws_tls_connection_options_init_from_ctx(&tls_connection_options, options->tls_ctx); + struct aws_byte_cursor host = aws_byte_cursor_from_buf(¶meters->endpoint); + if (aws_tls_connection_options_set_server_name(&tls_connection_options, allocator, &host)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): failed to create a tls connection options with error %s", + (void *)provider, + aws_error_str(aws_last_error())); + goto on_error; + } + + struct aws_socket_options socket_options; + AWS_ZERO_STRUCT(socket_options); + socket_options.type = AWS_SOCKET_STREAM; + socket_options.domain = AWS_SOCKET_IPV4; + socket_options.connect_timeout_ms = (uint32_t)aws_timestamp_convert( + SSO_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL); + + struct aws_http_connection_manager_options manager_options; + AWS_ZERO_STRUCT(manager_options); + manager_options.bootstrap = options->bootstrap; + manager_options.initial_window_size = SSO_RESPONSE_SIZE_LIMIT; + manager_options.socket_options = &socket_options; + manager_options.host = host; + manager_options.port = 443; + manager_options.max_connections = 2; + manager_options.shutdown_complete_callback = s_on_connection_manager_shutdown; + manager_options.shutdown_complete_user_data = provider; + manager_options.tls_connection_options = &tls_connection_options; + + impl->function_table = options->function_table; + if (impl->function_table == NULL) { + impl->function_table = g_aws_credentials_provider_http_function_table; + } + + impl->connection_manager = impl->function_table->aws_http_connection_manager_new(allocator, &manager_options); + if (impl->connection_manager == NULL) { + goto on_error; + } + + impl->token_provider = aws_credentials_provider_acquire(parameters->token_provider); + impl->endpoint = aws_string_new_from_buf(allocator, ¶meters->endpoint); + impl->sso_account_id = aws_string_new_from_string(allocator, parameters->sso_account_id); + impl->sso_role_name = aws_string_new_from_string(allocator, parameters->sso_role_name); + + provider->shutdown_options = options->shutdown_options; + + struct aws_standard_retry_options retry_options = { + .backoff_retry_options = + { + .el_group = options->bootstrap->event_loop_group, + .max_retries = SSO_MAX_ATTEMPTS, + }, + }; + impl->retry_strategy = aws_retry_strategy_new_standard(allocator, &retry_options); + if (!impl->retry_strategy) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "(id=%p): failed to create a retry strategy with error %s", + (void *)provider, + aws_error_debug_str(aws_last_error())); + goto on_error; + } + + s_parameters_destroy(parameters); + aws_tls_connection_options_clean_up(&tls_connection_options); + return provider; + +on_error: + aws_credentials_provider_destroy(provider); + s_parameters_destroy(parameters); + aws_tls_connection_options_clean_up(&tls_connection_options); + return NULL; +} diff --git a/contrib/restricted/aws/aws-c-auth/source/credentials_utils.c b/contrib/restricted/aws/aws-c-auth/source/credentials_utils.c index 2cb61d65473..a1ee268c379 100644 --- a/contrib/restricted/aws/aws-c-auth/source/credentials_utils.c +++ b/contrib/restricted/aws/aws-c-auth/source/credentials_utils.c @@ -5,6 +5,7 @@ #include <aws/auth/private/credentials_utils.h> +#include <aws/common/clock.h> #include <aws/common/date_time.h> #include <aws/common/json.h> #include <aws/common/string.h> @@ -12,6 +13,7 @@ #include <aws/http/connection.h> #include <aws/http/request_response.h> #include <aws/http/status_code.h> +#include <aws/sdkutils/aws_profile.h> #if defined(_MSC_VER) # pragma warning(disable : 4232) @@ -127,6 +129,20 @@ static bool s_parse_expiration_value_from_json_object( return true; } + case AWS_PCEF_NUMBER_UNIX_EPOCH_MS: { + double expiration_value_ms = 0; + if (aws_json_value_get_number(value, &expiration_value_ms)) { + AWS_LOGF_INFO( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "Unabled to extract credentials Expiration field from Json document."); + return false; + } + + *expiration_timepoint_in_seconds = + aws_timestamp_convert((uint64_t)expiration_value_ms, AWS_TIMESTAMP_MILLIS, AWS_TIMESTAMP_SECS, NULL); + return true; + } + default: return false; } @@ -251,16 +267,29 @@ done: struct aws_credentials *aws_parse_credentials_from_json_document( struct aws_allocator *allocator, - const char *document, + struct aws_byte_cursor document, const struct aws_parse_credentials_from_json_doc_options *options) { + struct aws_credentials *credentials = NULL; - struct aws_json_value *document_root = - aws_json_value_new_from_string(allocator, aws_byte_cursor_from_c_str(document)); + struct aws_json_value *document_root = aws_json_value_new_from_string(allocator, document); if (document_root == NULL) { AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to parse document as Json document."); return NULL; } - struct aws_credentials *credentials = aws_parse_credentials_from_aws_json_object(allocator, document_root, options); + + struct aws_json_value *top_level_object = NULL; + if (options->top_level_object_name) { + top_level_object = + aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str(options->top_level_object_name)); + if (!top_level_object) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "failed to parse top level object in json document."); + goto done; + } + } + + credentials = aws_parse_credentials_from_aws_json_object( + allocator, top_level_object ? top_level_object : document_root, options); +done: aws_json_value_destroy(document_root); return credentials; } @@ -292,3 +321,37 @@ enum aws_retry_error_type aws_credentials_provider_compute_retry_error_type(int return error_type; } + +struct aws_profile_collection *aws_load_profile_collection_from_config_file( + struct aws_allocator *allocator, + struct aws_byte_cursor config_file_name_override) { + + struct aws_profile_collection *config_profiles = NULL; + struct aws_string *config_file_path = NULL; + + config_file_path = aws_get_config_file_path(allocator, &config_file_name_override); + if (!config_file_path) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "Failed to resolve config file path: %s", + aws_error_str(aws_last_error())); + return NULL; + } + + config_profiles = aws_profile_collection_new_from_file(allocator, config_file_path, AWS_PST_CONFIG); + if (config_profiles != NULL) { + AWS_LOGF_DEBUG( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "Successfully built config profile collection from file at (%s)", + aws_string_c_str(config_file_path)); + } else { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "Failed to build config profile collection from file at (%s) : %s", + aws_string_c_str(config_file_path), + aws_error_str(aws_last_error())); + } + + aws_string_destroy(config_file_path); + return config_profiles; +} diff --git a/contrib/restricted/aws/aws-c-auth/source/sso_token_utils.c b/contrib/restricted/aws/aws-c-auth/source/sso_token_utils.c new file mode 100644 index 00000000000..7b90ef43ed2 --- /dev/null +++ b/contrib/restricted/aws/aws-c-auth/source/sso_token_utils.c @@ -0,0 +1,160 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/auth/private/sso_token_utils.h> +#include <aws/cal/hash.h> +#include <aws/common/encoding.h> +#include <aws/common/file.h> +#include <aws/common/json.h> + +#if defined(_MSC_VER) +# pragma warning(disable : 4232) +#endif /* _MSC_VER */ + +struct aws_string *aws_construct_sso_token_path(struct aws_allocator *allocator, const struct aws_string *input) { + AWS_PRECONDITION(input); + + struct aws_string *sso_token_path_str = NULL; + + struct aws_string *home_directory = aws_get_home_directory(allocator); + if (!home_directory) { + return NULL; + } + + struct aws_byte_cursor home_dir_cursor = aws_byte_cursor_from_string(home_directory); + struct aws_byte_cursor input_cursor = aws_byte_cursor_from_string(input); + struct aws_byte_cursor json_cursor = aws_byte_cursor_from_c_str(".json"); + + struct aws_byte_buf sso_token_path_buf; + AWS_ZERO_STRUCT(sso_token_path_buf); + struct aws_byte_buf sha1_buf; + AWS_ZERO_STRUCT(sha1_buf); + + /* append home directory */ + if (aws_byte_buf_init_copy_from_cursor(&sso_token_path_buf, allocator, home_dir_cursor)) { + goto cleanup; + } + + /* append sso cache directory */ + struct aws_byte_cursor sso_cache_dir_cursor = aws_byte_cursor_from_c_str("/.aws/sso/cache/"); + if (aws_byte_buf_append_dynamic(&sso_token_path_buf, &sso_cache_dir_cursor)) { + goto cleanup; + } + + /* append hex encoded sha1 of input */ + if (aws_byte_buf_init(&sha1_buf, allocator, AWS_SHA1_LEN) || + aws_sha1_compute(allocator, &input_cursor, &sha1_buf, 0)) { + goto cleanup; + } + struct aws_byte_cursor sha1_cursor = aws_byte_cursor_from_buf(&sha1_buf); + if (aws_hex_encode_append_dynamic(&sha1_cursor, &sso_token_path_buf)) { + goto cleanup; + } + + /* append .json */ + if (aws_byte_buf_append_dynamic(&sso_token_path_buf, &json_cursor)) { + goto cleanup; + } + + /* use platform-specific directory separator. */ + aws_normalize_directory_separator(&sso_token_path_buf); + + sso_token_path_str = aws_string_new_from_buf(allocator, &sso_token_path_buf); + AWS_LOGF_INFO( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "successfully constructed token path: %s", + aws_string_c_str(sso_token_path_str)); +cleanup: + aws_byte_buf_clean_up(&sso_token_path_buf); + aws_byte_buf_clean_up(&sha1_buf); + aws_string_destroy(home_directory); + return sso_token_path_str; +} + +void aws_sso_token_destroy(struct aws_sso_token *sso_token) { + if (sso_token == NULL) { + return; + } + + aws_string_destroy(sso_token->access_token); + aws_mem_release(sso_token->allocator, sso_token); +} + +struct aws_sso_token *aws_sso_token_new_from_file(struct aws_allocator *allocator, const struct aws_string *file_path) { + AWS_PRECONDITION(allocator); + AWS_PRECONDITION(file_path); + + bool success = false; + + struct aws_sso_token *token = aws_mem_calloc(allocator, 1, sizeof(struct aws_sso_token)); + token->allocator = allocator; + struct aws_byte_buf file_contents_buf; + AWS_ZERO_STRUCT(file_contents_buf); + struct aws_json_value *document_root = NULL; + + if (aws_byte_buf_init_from_file(&file_contents_buf, allocator, aws_string_c_str(file_path))) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso token: failed to load token file %s", aws_string_c_str(file_path)); + goto cleanup; + } + + struct aws_byte_cursor document_cursor = aws_byte_cursor_from_buf(&file_contents_buf); + document_root = aws_json_value_new_from_string(allocator, document_cursor); + if (document_root == NULL) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "sso token: failed to parse sso token file %s", + aws_string_c_str(file_path)); + aws_raise_error(AWS_AUTH_SSO_TOKEN_INVALID); + goto cleanup; + } + + struct aws_byte_cursor access_token_cursor; + struct aws_json_value *access_token = + aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("accessToken")); + if (!aws_json_value_is_string(access_token) || aws_json_value_get_string(access_token, &access_token_cursor)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "sso token: failed to parse accessToken from %s", + aws_string_c_str(file_path)); + aws_raise_error(AWS_AUTH_SSO_TOKEN_INVALID); + goto cleanup; + } + + struct aws_byte_cursor expires_at_cursor; + struct aws_json_value *expires_at = + aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str("expiresAt")); + if (!aws_json_value_is_string(expires_at) || aws_json_value_get_string(expires_at, &expires_at_cursor)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "sso token: failed to parse expiresAt from %s", + aws_string_c_str(file_path)); + aws_raise_error(AWS_AUTH_SSO_TOKEN_INVALID); + goto cleanup; + } + struct aws_date_time expiration; + if (aws_date_time_init_from_str_cursor(&expiration, &expires_at_cursor, AWS_DATE_FORMAT_ISO_8601)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "sso token: expiresAt '" PRInSTR "' in %s is not a valid ISO-8601 date string", + AWS_BYTE_CURSOR_PRI(expires_at_cursor), + aws_string_c_str(file_path)); + aws_raise_error(AWS_AUTH_SSO_TOKEN_INVALID); + goto cleanup; + } + token->access_token = aws_string_new_from_cursor(allocator, &access_token_cursor); + token->expiration = expiration; + + success = true; + +cleanup: + aws_json_value_destroy(document_root); + aws_byte_buf_clean_up(&file_contents_buf); + if (!success) { + aws_sso_token_destroy(token); + token = NULL; + } + return token; +} diff --git a/contrib/restricted/aws/aws-c-auth/source/token_provider_sso_profile.c b/contrib/restricted/aws/aws-c-auth/source/token_provider_sso_profile.c new file mode 100644 index 00000000000..6e2a3521f72 --- /dev/null +++ b/contrib/restricted/aws/aws-c-auth/source/token_provider_sso_profile.c @@ -0,0 +1,186 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/auth/credentials.h> + +#include <aws/auth/private/aws_profile.h> +#include <aws/auth/private/credentials_utils.h> +#include <aws/auth/private/sso_token_providers.h> +#include <aws/auth/private/sso_token_utils.h> +#include <aws/common/clock.h> + +#ifdef _MSC_VER +/* allow non-constant declared initializers. */ +# pragma warning(disable : 4204) +#endif + +/* + * sso-token profile provider implementation + */ +struct aws_token_provider_profile_impl { + struct aws_string *sso_token_file_path; + + aws_io_clock_fn *system_clock_fn; +}; + +static int s_token_provider_profile_get_token( + struct aws_credentials_provider *provider, + aws_on_get_credentials_callback_fn callback, + void *user_data) { + struct aws_token_provider_profile_impl *impl = provider->impl; + + struct aws_sso_token *sso_token = NULL; + struct aws_credentials *credentials = NULL; + int result = AWS_OP_ERR; + sso_token = aws_sso_token_new_from_file(provider->allocator, impl->sso_token_file_path); + if (!sso_token) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) failed to get sso token from file", (void *)provider); + goto done; + } + + /* check token expiration. */ + uint64_t now_ns = UINT64_MAX; + if (impl->system_clock_fn(&now_ns) != AWS_OP_SUCCESS) { + goto done; + } + + if (aws_date_time_as_nanos(&sso_token->expiration) <= now_ns) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) cached sso token is expired.", (void *)provider); + aws_raise_error(AWS_AUTH_SSO_TOKEN_EXPIRED); + goto done; + } + + credentials = aws_credentials_new_token( + provider->allocator, + aws_byte_cursor_from_string(sso_token->access_token), + (uint64_t)aws_date_time_as_epoch_secs(&sso_token->expiration)); + if (!credentials) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) Unable to construct credentials.", (void *)provider); + goto done; + } + + callback(credentials, AWS_OP_SUCCESS, user_data); + result = AWS_OP_SUCCESS; + +done: + aws_sso_token_destroy(sso_token); + aws_credentials_release(credentials); + return result; +} + +static void s_token_provider_profile_destroy(struct aws_credentials_provider *provider) { + struct aws_token_provider_profile_impl *impl = provider->impl; + if (impl == NULL) { + return; + } + + aws_string_destroy(impl->sso_token_file_path); + + aws_credentials_provider_invoke_shutdown_callback(provider); + aws_mem_release(provider->allocator, provider); +} + +static struct aws_credentials_provider_vtable s_aws_token_provider_profile_vtable = { + .get_credentials = s_token_provider_profile_get_token, + .destroy = s_token_provider_profile_destroy, +}; + +AWS_STRING_FROM_LITERAL(s_profile_sso_start_url_name, "sso_start_url"); + +static struct aws_string *s_construct_profile_sso_token_path( + struct aws_allocator *allocator, + const struct aws_token_provider_sso_profile_options *options) { + + struct aws_profile_collection *config_collection = NULL; + struct aws_string *profile_name = NULL; + struct aws_string *sso_token_path = NULL; + + profile_name = aws_get_profile_name(allocator, &options->profile_name_override); + if (!profile_name) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "token-provider-sso-profile: failed to resolve profile name"); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + if (options->config_file_cached) { + /* Use cached config file */ + config_collection = aws_profile_collection_acquire(options->config_file_cached); + } else { + /* load config file */ + config_collection = aws_load_profile_collection_from_config_file(allocator, options->config_file_name_override); + } + + if (!config_collection) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "token-provider-sso-profile: could not load or parse" + " a config file."); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + + const struct aws_profile *profile = aws_profile_collection_get_profile(config_collection, profile_name); + + if (!profile) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "token-provider-sso-profile: could not load" + " a profile at %s.", + aws_string_c_str(profile_name)); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + + const struct aws_profile_property *sso_start_url_property = + aws_profile_get_property(profile, s_profile_sso_start_url_name); + + if (!sso_start_url_property) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "token-provider-sso-profile: failed to find sso_start_url"); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + + sso_token_path = aws_construct_sso_token_path(allocator, aws_profile_property_get_value(sso_start_url_property)); + if (!sso_token_path) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "token-provider-sso-profile: failed to construct token path"); + goto cleanup; + } + +cleanup: + aws_string_destroy(profile_name); + aws_profile_collection_release(config_collection); + return sso_token_path; +} + +struct aws_credentials_provider *aws_token_provider_new_sso_profile( + struct aws_allocator *allocator, + const struct aws_token_provider_sso_profile_options *options) { + struct aws_string *token_path = s_construct_profile_sso_token_path(allocator, options); + if (!token_path) { + return NULL; + } + struct aws_credentials_provider *provider = NULL; + struct aws_token_provider_profile_impl *impl = NULL; + + aws_mem_acquire_many( + allocator, + 2, + &provider, + sizeof(struct aws_credentials_provider), + &impl, + sizeof(struct aws_token_provider_profile_impl)); + AWS_ZERO_STRUCT(*provider); + AWS_ZERO_STRUCT(*impl); + aws_credentials_provider_init_base(provider, allocator, &s_aws_token_provider_profile_vtable, impl); + impl->sso_token_file_path = aws_string_new_from_string(allocator, token_path); + provider->shutdown_options = options->shutdown_options; + if (options->system_clock_fn) { + impl->system_clock_fn = options->system_clock_fn; + } else { + impl->system_clock_fn = aws_sys_clock_get_ticks; + } + + aws_string_destroy(token_path); + return provider; +} diff --git a/contrib/restricted/aws/aws-c-auth/source/token_provider_sso_session.c b/contrib/restricted/aws/aws-c-auth/source/token_provider_sso_session.c new file mode 100644 index 00000000000..e3a17b7f5bc --- /dev/null +++ b/contrib/restricted/aws/aws-c-auth/source/token_provider_sso_session.c @@ -0,0 +1,251 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/auth/credentials.h> + +#include <aws/auth/private/aws_profile.h> +#include <aws/auth/private/credentials_utils.h> +#include <aws/auth/private/sso_token_providers.h> +#include <aws/auth/private/sso_token_utils.h> +#include <aws/common/clock.h> + +#ifdef _MSC_VER +/* allow non-constant declared initializers. */ +# pragma warning(disable : 4204) +#endif + +/* + * sso-session token provider implementation + */ +struct aws_token_provider_sso_session_impl { + struct aws_string *sso_token_file_path; + aws_io_clock_fn *system_clock_fn; +}; + +static int s_token_provider_sso_session_get_token( + struct aws_credentials_provider *provider, + aws_on_get_credentials_callback_fn callback, + void *user_data) { + + struct aws_token_provider_sso_session_impl *impl = provider->impl; + struct aws_sso_token *sso_token = NULL; + struct aws_credentials *credentials = NULL; + int result = AWS_OP_ERR; + + sso_token = aws_sso_token_new_from_file(provider->allocator, impl->sso_token_file_path); + if (!sso_token) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) failed to get sso token from file.", (void *)provider); + goto done; + } + + /* check token expiration. */ + uint64_t now_ns = UINT64_MAX; + if (impl->system_clock_fn(&now_ns) != AWS_OP_SUCCESS) { + goto done; + } + + if (aws_date_time_as_nanos(&sso_token->expiration) <= now_ns) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) cached sso token is expired.", (void *)provider); + aws_raise_error(AWS_AUTH_SSO_TOKEN_EXPIRED); + goto done; + } + + /* TODO: Refresh token if it is within refresh window and refreshable */ + + credentials = aws_credentials_new_token( + provider->allocator, + aws_byte_cursor_from_string(sso_token->access_token), + (uint64_t)aws_date_time_as_epoch_secs(&sso_token->expiration)); + if (!credentials) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) Unable to construct credentials.", (void *)provider); + goto done; + } + callback(credentials, AWS_OP_SUCCESS, user_data); + result = AWS_OP_SUCCESS; + +done: + aws_sso_token_destroy(sso_token); + aws_credentials_release(credentials); + return result; +} + +static void s_token_provider_sso_session_destroy(struct aws_credentials_provider *provider) { + struct aws_token_provider_sso_session_impl *impl = provider->impl; + if (impl == NULL) { + return; + } + + aws_string_destroy(impl->sso_token_file_path); + + aws_credentials_provider_invoke_shutdown_callback(provider); + aws_mem_release(provider->allocator, provider); +} + +static struct aws_credentials_provider_vtable s_aws_token_provider_sso_session_vtable = { + .get_credentials = s_token_provider_sso_session_get_token, + .destroy = s_token_provider_sso_session_destroy, +}; + +AWS_STRING_FROM_LITERAL(s_sso_session_name, "sso_session"); +AWS_STRING_FROM_LITERAL(s_sso_region_name, "sso_region"); +AWS_STRING_FROM_LITERAL(s_sso_start_url_name, "sso_start_url"); + +/** + * Parses the config file to validate and construct a token path. A valid profile with sso session is as follow + * [profile sso-profile] + * sso_session = dev + * sso_account_id = 012345678901 + * sso_role_name = SampleRole + * + * [sso-session dev] + * sso_region = us-east-1 + * sso_start_url = https://d-abc123.awsapps.com/start + */ +static struct aws_string *s_verify_config_and_construct_sso_token_path( + struct aws_allocator *allocator, + const struct aws_token_provider_sso_session_options *options) { + struct aws_profile_collection *config_collection = NULL; + struct aws_string *profile_name = NULL; + struct aws_string *sso_token_path = NULL; + + profile_name = aws_get_profile_name(allocator, &options->profile_name_override); + if (!profile_name) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "sso-session: token provider failed to resolve profile name"); + goto cleanup; + } + if (options->config_file_cached) { + /* Use cached config file */ + config_collection = aws_profile_collection_acquire(options->config_file_cached); + } else { + /* load config file */ + config_collection = aws_load_profile_collection_from_config_file(allocator, options->config_file_name_override); + } + if (!config_collection) { + goto cleanup; + } + + const struct aws_profile *profile = aws_profile_collection_get_profile(config_collection, profile_name); + + if (!profile) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "sso-session: token provider could not load" + " a profile at %s.", + aws_string_c_str(profile_name)); + goto cleanup; + } + + const struct aws_profile_property *sso_session_property = aws_profile_get_property(profile, s_sso_session_name); + if (!sso_session_property) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "token-provider-sso-session: token provider could not find an sso-session at profile %s", + aws_string_c_str(profile_name)); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + const struct aws_string *sso_session_name = aws_profile_property_get_value(sso_session_property); + + /* parse sso_session */ + const struct aws_profile *session_profile = + aws_profile_collection_get_section(config_collection, AWS_PROFILE_SECTION_TYPE_SSO_SESSION, sso_session_name); + if (!session_profile) { + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "token-provider-sso-session: failed to find an sso-session"); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + + const struct aws_profile_property *sso_region_property = + aws_profile_get_property(session_profile, s_sso_region_name); + const struct aws_profile_property *sso_start_url_property = + aws_profile_get_property(session_profile, s_sso_start_url_name); + + if (!sso_region_property) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, "token-provider-sso-session: failed to find sso_region in sso-session"); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + + if (!sso_start_url_property) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "token-provider-sso-session: failed to find sso_start_url in sso-session"); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + + /* Verify sso_region & start_url are the same in profile section if they exist */ + const struct aws_string *sso_region = aws_profile_property_get_value(sso_region_property); + const struct aws_string *sso_start_url = aws_profile_property_get_value(sso_start_url_property); + + const struct aws_profile_property *profile_sso_region_property = + aws_profile_get_property(profile, s_sso_region_name); + const struct aws_profile_property *profile_sso_start_url_property = + aws_profile_get_property(profile, s_sso_start_url_name); + + if (profile_sso_region_property && + !aws_string_eq(sso_region, aws_profile_property_get_value(profile_sso_region_property))) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "token-provider-sso-session: profile & sso-session have different value for sso_region"); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + + if (profile_sso_start_url_property && + !aws_string_eq(sso_start_url, aws_profile_property_get_value(profile_sso_start_url_property))) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "token-provider-sso-session: profile & sso-session have different value for sso_start_url"); + aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE); + goto cleanup; + } + + sso_token_path = aws_construct_sso_token_path(allocator, sso_session_name); + +cleanup: + aws_string_destroy(profile_name); + aws_profile_collection_release(config_collection); + return sso_token_path; +} + +struct aws_credentials_provider *aws_token_provider_new_sso_session( + struct aws_allocator *allocator, + const struct aws_token_provider_sso_session_options *options) { + + /* Currently, they are not used but they will be required when we implement the refresh token functionality. */ + AWS_ASSERT(options->bootstrap); + AWS_ASSERT(options->tls_ctx); + + struct aws_string *token_path = s_verify_config_and_construct_sso_token_path(allocator, options); + if (!token_path) { + return NULL; + } + struct aws_credentials_provider *provider = NULL; + struct aws_token_provider_sso_session_impl *impl = NULL; + + aws_mem_acquire_many( + allocator, + 2, + &provider, + sizeof(struct aws_credentials_provider), + &impl, + sizeof(struct aws_token_provider_sso_session_impl)); + AWS_ZERO_STRUCT(*provider); + AWS_ZERO_STRUCT(*impl); + aws_credentials_provider_init_base(provider, allocator, &s_aws_token_provider_sso_session_vtable, impl); + impl->sso_token_file_path = aws_string_new_from_string(allocator, token_path); + provider->shutdown_options = options->shutdown_options; + if (options->system_clock_fn) { + impl->system_clock_fn = options->system_clock_fn; + } else { + impl->system_clock_fn = aws_sys_clock_get_ticks; + } + + aws_string_destroy(token_path); + return provider; +} diff --git a/contrib/restricted/aws/aws-c-auth/ya.make b/contrib/restricted/aws/aws-c-auth/ya.make index a0f2151cee7..ef7a8fc1530 100644 --- a/contrib/restricted/aws/aws-c-auth/ya.make +++ b/contrib/restricted/aws/aws-c-auth/ya.make @@ -6,9 +6,9 @@ LICENSE(Apache-2.0) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(0.6.26) +VERSION(0.6.27) -ORIGINAL_SOURCE(https://github.com/awslabs/aws-c-auth/archive/v0.6.26.tar.gz) +ORIGINAL_SOURCE(https://github.com/awslabs/aws-c-auth/archive/v0.6.27.tar.gz) PEERDIR( contrib/restricted/aws/aws-c-cal @@ -51,6 +51,12 @@ CFLAGS( -DS2N___RESTRICT__SUPPORTED ) +IF (OS_WINDOWS) + CFLAGS( + -DAWS_AUTH_EXPORTS + ) +ENDIF() + SRCS( source/auth.c source/aws_imds_client.c @@ -68,6 +74,7 @@ SRCS( source/credentials_provider_imds.c source/credentials_provider_process.c source/credentials_provider_profile.c + source/credentials_provider_sso.c source/credentials_provider_static.c source/credentials_provider_sts.c source/credentials_provider_sts_web_identity.c @@ -82,6 +89,9 @@ SRCS( source/signing_config.c source/signing_result.c source/sigv4_http_request.c + source/sso_token_utils.c + source/token_provider_sso_profile.c + source/token_provider_sso_session.c ) END() diff --git a/library/cpp/netliba/socket/creators.cpp b/library/cpp/netliba/socket/creators.cpp index 3821bf55b96..f9a3b9830c4 100644 --- a/library/cpp/netliba/socket/creators.cpp +++ b/library/cpp/netliba/socket/creators.cpp @@ -61,7 +61,7 @@ namespace NNetlibaSocket { *(ui8*)CMSG_DATA(cmsgTos) = tos; #endif - if (*(ui64*)myAddr.sin6_addr.s6_addr != 0u) { + if (((ui64*)myAddr.sin6_addr.s6_addr)[0] != 0u || ((ui64*)myAddr.sin6_addr.s6_addr)[1] != 0u) { in6_pktinfo* pktInfo; #ifdef _cygwin_ cmsghdr* cmsgAddr = CMSG_FIRSTHDR(header); diff --git a/library/cpp/sanitizer/address/static/ya.make b/library/cpp/sanitizer/address/static/ya.make index d8cf24a8487..7210cbced90 100644 --- a/library/cpp/sanitizer/address/static/ya.make +++ b/library/cpp/sanitizer/address/static/ya.make @@ -1,7 +1,5 @@ LIBRARY() -SUBSCRIBER(g:devtools-contrib) - NO_UTIL() PEERDIR( diff --git a/library/cpp/sanitizer/memory/static/ya.make b/library/cpp/sanitizer/memory/static/ya.make index ab10fb9c88d..0955ec62d8c 100644 --- a/library/cpp/sanitizer/memory/static/ya.make +++ b/library/cpp/sanitizer/memory/static/ya.make @@ -1,7 +1,5 @@ LIBRARY() -SUBSCRIBER(g:devtools-contrib) - NO_UTIL() PEERDIR( diff --git a/library/cpp/sanitizer/thread/static/ya.make b/library/cpp/sanitizer/thread/static/ya.make index 0a09b0098cc..7cbd7b9fd5e 100644 --- a/library/cpp/sanitizer/thread/static/ya.make +++ b/library/cpp/sanitizer/thread/static/ya.make @@ -1,7 +1,5 @@ LIBRARY() -SUBSCRIBER(g:devtools-contrib) - NO_UTIL() PEERDIR( diff --git a/library/cpp/testing/dump_clang_coverage/write_profile_data.cpp b/library/cpp/testing/dump_clang_coverage/write_profile_data.cpp new file mode 100644 index 00000000000..8b13474cc8f --- /dev/null +++ b/library/cpp/testing/dump_clang_coverage/write_profile_data.cpp @@ -0,0 +1,125 @@ +#include <dlfcn.h> +#include <linux/limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +extern "C" { + void __llvm_profile_initialize_file(void); + int __llvm_profile_write_file(void); + void __llvm_profile_set_filename(const char* filename_pattern); + + // there might no llmv rt, for example for the targets from contrib + __attribute__((weak)) int __llvm_profile_write_file(void) { + return 0; + } + __attribute__((weak)) void __llvm_profile_initialize_file(void) { + } + __attribute__((weak)) void __llvm_profile_set_filename(const char*) { + } +} + +namespace { + void dummy() { + } +} + +bool getSoName(char* buff, size_t size) { + // returns so name for shared objects and exe_name for binaries + Dl_info dl_info = {0, 0, 0, 0}; + if (dladdr((void*)(intptr_t)dummy, &dl_info) != 0) { + if (dl_info.dli_fname) { + const char* name = dl_info.dli_fname; + char real_path[PATH_MAX]; + const char* resolved = realpath(name, real_path); + if (resolved != NULL) + name = real_path; + const char* lastSlash = strrchr(name, '/'); + if (!!lastSlash) { + name = lastSlash + 1; + } + strncpy(buff, name, size); + return true; + } + } + return false; +} + +bool getExeName(char* buff, size_t size) { + ssize_t len = readlink("/proc/self/exe", buff, size); + if (len <= 0) { + return false; + } + + buff[len] = '\0'; + char* lastSlash = strrchr(buff, '/'); + if (!!lastSlash) { + strncpy(buff, lastSlash + 1, size); + buff[(buff + len) - lastSlash] = '\0'; + } + return true; +} + +bool getSelfName(char* buff, size_t size) { +#if defined(_musl_) + return getExeName(buff, size); +#else + return getSoName(buff, size); +#endif +} + +void replaceFirst(char* data, size_t dsize, const char* pat, size_t psize, const char* repl, size_t rsize) { + char* patPtr = strstr(data, pat); + if (!patPtr) { + return; + } + + char tmp[PATH_MAX] = {0}; + char* tmpPtr = &tmp[0]; + + strcpy(tmpPtr, patPtr + psize); + strcpy(patPtr, repl); + strcpy(patPtr + rsize, tmpPtr); + data[dsize - psize + rsize] = '\0'; +} + +// Adds support of the specifier '%e' (executable filename (without path prefix)) to the LLVM_PROFILE_FILE +void parseAndSetFilename() { + const char* profile_file = getenv("LLVM_PROFILE_FILE"); + if (!profile_file) + return; + + // __llvm_profile_set_filename doesn't copy name, so it must remain valid + static char pattern[PATH_MAX] = {0}; + char* patternPtr = &pattern[0]; + + strncpy(patternPtr, profile_file, PATH_MAX - 1); + + if (!!strstr(patternPtr, "%e")) { + char buff[PATH_MAX] = {0}; + char* buffPtr = &buff[0]; + + if (getSelfName(buffPtr, PATH_MAX)) { + size_t patternSize = strlen(patternPtr); + size_t buffSize = strlen(buffPtr); + + if (patternSize + buffSize >= PATH_MAX) { + abort(); + } + replaceFirst(patternPtr, patternSize, "%e", 2, buffPtr, buffSize); + } + } + + __llvm_profile_set_filename(patternPtr); +} + +void __attribute__((constructor)) premain() { + parseAndSetFilename(); + if (getenv("YA_COVERAGE_DUMP_PROFILE_AND_EXIT")) { + __llvm_profile_initialize_file(); + int rc = __llvm_profile_write_file(); + if (!rc && getenv("YA_COVERAGE_DUMP_PROFILE_EXIT_CODE")) + rc = atoi(getenv("YA_COVERAGE_DUMP_PROFILE_EXIT_CODE")); + exit(rc); + } +} diff --git a/library/cpp/testing/dump_clang_coverage/ya.make b/library/cpp/testing/dump_clang_coverage/ya.make new file mode 100644 index 00000000000..26eb36048c2 --- /dev/null +++ b/library/cpp/testing/dump_clang_coverage/ya.make @@ -0,0 +1,13 @@ +LIBRARY() + +NO_CLANG_COVERAGE() + +NO_RUNTIME() + +IF (OS_LINUX) + SRCS( + GLOBAL write_profile_data.cpp + ) +ENDIF() + +END() diff --git a/ydb/ci/rightlib.txt b/ydb/ci/rightlib.txt index 51edbdc360c..fda17fed09c 100644 --- a/ydb/ci/rightlib.txt +++ b/ydb/ci/rightlib.txt @@ -1 +1 @@ -24211947581091f2f54c8e50e3427e6621dfec3d +b0c2229a8d320931b2a986503a39f0f805956f11 diff --git a/yql/essentials/tests/sql/sql2yql/canondata/result.json b/yql/essentials/tests/sql/sql2yql/canondata/result.json index dac11c7bd37..ad1c6773945 100644 --- a/yql/essentials/tests/sql/sql2yql/canondata/result.json +++ b/yql/essentials/tests/sql/sql2yql/canondata/result.json @@ -7559,6 +7559,13 @@ "uri": "https://{canondata_backend}/1936273/4a1b39013e1bae40e722cff8ccef8829784964e2/resource.tar.gz#test_sql2yql.test_hor_join-yql-6477_table_path_/sql.yql" } ], + "test_sql2yql.test[hor_join-yql19332_aux_cols]": [ + { + "checksum": "195e1068ca8926582b211c2b2eb5bfbf", + "size": 3144, + "uri": "https://{canondata_backend}/1784117/39173fc32d12059e969bfcf094e71dd92d4acaeb/resource.tar.gz#test_sql2yql.test_hor_join-yql19332_aux_cols_/sql.yql" + } + ], "test_sql2yql.test[in-basic_in]": [ { "checksum": "d65b144596eb506f4cc5f1f191a89832", @@ -25272,6 +25279,11 @@ "uri": "file://test_sql_format.test_hor_join-yql-6477_table_path_/formatted.sql" } ], + "test_sql_format.test[hor_join-yql19332_aux_cols]": [ + { + "uri": "file://test_sql_format.test_hor_join-yql19332_aux_cols_/formatted.sql" + } + ], "test_sql_format.test[in-basic_in]": [ { "uri": "file://test_sql_format.test_in-basic_in_/formatted.sql" diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_hor_join-yql19332_aux_cols_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_hor_join-yql19332_aux_cols_/formatted.sql new file mode 100644 index 00000000000..e5628f6d894 --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_hor_join-yql19332_aux_cols_/formatted.sql @@ -0,0 +1,20 @@ +-- ignore runonopt plan diff +USE plato; +PRAGMA DisableSimpleColumns; +PRAGMA yt.JoinMergeTablesLimit = "10"; + +$i = + SELECT + * + FROM concat(Input2, Input3) + WHERE value != "1"; + +SELECT + b.key, + b.subkey, + a.value +FROM Input1 + AS a +JOIN $i + AS b +ON (a.key, a.subkey) == (b.key, b.subkey); diff --git a/yql/essentials/tests/sql/suites/hor_join/yql19332_aux_cols.cfg b/yql/essentials/tests/sql/suites/hor_join/yql19332_aux_cols.cfg new file mode 100644 index 00000000000..3eb7660ec93 --- /dev/null +++ b/yql/essentials/tests/sql/suites/hor_join/yql19332_aux_cols.cfg @@ -0,0 +1,3 @@ +in Input1 sorted.txt +in Input2 sorted.txt +in Input3 sorted.txt diff --git a/yql/essentials/tests/sql/suites/hor_join/yql19332_aux_cols.sql b/yql/essentials/tests/sql/suites/hor_join/yql19332_aux_cols.sql new file mode 100644 index 00000000000..c84769777c1 --- /dev/null +++ b/yql/essentials/tests/sql/suites/hor_join/yql19332_aux_cols.sql @@ -0,0 +1,9 @@ +-- ignore runonopt plan diff +USE plato; +pragma DisableSimpleColumns; +pragma yt.JoinMergeTablesLimit="10"; + +$i = select * from concat(Input2, Input3) where value != "1"; + +select b.key, b.subkey, a.value from Input1 as a +join $i as b on (a.key, a.subkey) == (b.key, b.subkey) diff --git a/yt/yql/providers/yt/provider/yql_yt_horizontal_join.cpp b/yt/yql/providers/yt/provider/yql_yt_horizontal_join.cpp index b35f82aca04..f680d995686 100644 --- a/yt/yql/providers/yt/provider/yql_yt_horizontal_join.cpp +++ b/yt/yql/providers/yt/provider/yql_yt_horizontal_join.cpp @@ -999,7 +999,7 @@ bool THorizontalJoinOptimizer::MakeJoinedMap(TPositionHandle pos, TExprContext& else if (nextNewOutIndex < outRemap.size()) { TVector<TExprBase> tupleTypes; for (auto out: joinedMapOuts) { - auto itemType = out.Ref().GetTypeAnn()->Cast<TListExprType>()->GetItemType(); + auto itemType = TYqlRowSpecInfo(out.RowSpec()).GetExtendedType(ctx); tupleTypes.push_back(TExprBase(ExpandType(pos, *itemType, ctx))); } TExprBase varType = Build<TCoVariantType>(ctx, pos) diff --git a/yt/yql/providers/yt/provider/yql_yt_physical_finalizing.cpp b/yt/yql/providers/yt/provider/yql_yt_physical_finalizing.cpp index 01cf4708e7f..1ebcfcc1e12 100644 --- a/yt/yql/providers/yt/provider/yql_yt_physical_finalizing.cpp +++ b/yt/yql/providers/yt/provider/yql_yt_physical_finalizing.cpp @@ -1026,10 +1026,12 @@ private: bool changedOutSort = false; TVector<TYtOutTable> outTables; TExprNode::TListType filterColumns(op.Output().Size()); + TTypeAnnotationNode::TListType varItemTypes(op.Output().Size()); for (size_t i = 0; i < op.Output().Size(); ++i) { auto out = op.Output().Item(i); + auto rowSpec = TYtTableBaseInfo::GetRowSpec(out); + varItemTypes[i] = rowSpec->GetExtendedType(ctx); if (unorderedOuts.Test(i)) { - auto rowSpec = TYtTableBaseInfo::GetRowSpec(out); YQL_ENSURE(rowSpec); if (rowSpec->IsSorted()) { if (rowSpec->HasAuxColumns()) { @@ -1038,6 +1040,7 @@ private: columns.emplace_back(item->GetName()); } filterColumns[i] = ToAtomList(columns, node.Pos(), ctx); + varItemTypes[i] = rowSpec->GetType(); } rowSpec->ClearSortness(ctx); outTables.push_back(TYtOutTable(ctx.ChangeChild(out.Ref(), TYtOutTable::idx_RowSpec, rowSpec->ToExprNode(ctx, out.Pos()).Ptr()))); @@ -1156,7 +1159,7 @@ private: .Build() .Done().Ptr(); } else { - auto varType = ExpandType(lambda->Pos(), *GetSeqItemType(node.Child(lambdaIdx)->GetTypeAnn()), ctx); + auto varType = ExpandType(lambda->Pos(), *ctx.MakeType<TVariantExprType>(ctx.MakeType<TTupleExprType>(varItemTypes)), ctx); TVector<TExprBase> visitArgs; for (size_t i = 0; i < op.Output().Size(); ++i) { visitArgs.push_back(Build<TCoAtom>(ctx, lambda->Pos()).Value(ToString(i)).Done()); diff --git a/yt/yt/core/misc/proc.cpp b/yt/yt/core/misc/proc.cpp index 363549b4bf9..e25dd22cc08 100644 --- a/yt/yt/core/misc/proc.cpp +++ b/yt/yt/core/misc/proc.cpp @@ -42,6 +42,7 @@ #include <unistd.h> #endif #ifdef _linux_ + #include <fcntl.h> #include <pty.h> #include <pwd.h> #include <grp.h> @@ -951,6 +952,36 @@ void SafeSetPipeCapacity(int fd, int capacity) } } +bool TryEnableEmptyPipeEpollEvent(TFileDescriptor fd) +{ +// TODO(arkady-e1ppa): To not waste gpu we swallow an error +// resulting in a potentially broken behavior. +// if F_SET_PIPE_WAKE_WRITER is not defined and/or properly +// implemented we should return false. +#if defined(_linux_) && defined(F_SET_PIPE_WAKE_WRITER) + int res = ::fcntl(fd, F_SET_PIPE_WAKE_WRITER, 1); + + // TODO(arkady-e1ppa): Once kernel version is fresh enough + // remove this branch altogether. + if (res == -1) { + return errno == EINVAL; + } + + return res != -1; +#else + Y_UNUSED(fd); + return true; +#endif +} + +void SafeEnableEmptyPipeEpollEvent(TFileDescriptor fd) +{ + if (!TryEnableEmptyPipeEpollEvent(fd)) { + THROW_ERROR_EXCEPTION("Failed to enable empty pipe epoll event for descriptor %v", fd) + << TError::FromSystem(); + } +} + bool TrySetUid(int uid) { #ifdef _linux_ diff --git a/yt/yt/core/misc/proc.h b/yt/yt/core/misc/proc.h index 36d9ce8bc6a..86d8ad42232 100644 --- a/yt/yt/core/misc/proc.h +++ b/yt/yt/core/misc/proc.h @@ -166,6 +166,9 @@ void SafeMakeNonblocking(TFileDescriptor fd); bool TrySetPipeCapacity(TFileDescriptor fd, int capacity); void SafeSetPipeCapacity(TFileDescriptor fd, int capacity); +bool TryEnableEmptyPipeEpollEvent(TFileDescriptor fd); +void SafeEnableEmptyPipeEpollEvent(TFileDescriptor fd); + bool TrySetUid(int uid); void SafeSetUid(int uid); diff --git a/yt/yt/core/net/connection.cpp b/yt/yt/core/net/connection.cpp index a8435fbf5a0..458d4e6b1a4 100644 --- a/yt/yt/core/net/connection.cpp +++ b/yt/yt/core/net/connection.cpp @@ -1305,7 +1305,8 @@ namespace { TFileDescriptor CreateWriteFDForConnection( const TString& pipePath, - std::optional<int> capacity) + std::optional<int> capacity, + bool useDeliveryFence) { #ifdef _unix_ int flags = O_WRONLY | O_CLOEXEC; @@ -1321,6 +1322,10 @@ TFileDescriptor CreateWriteFDForConnection( SafeSetPipeCapacity(fd, *capacity); } + if (useDeliveryFence) { + SafeEnableEmptyPipeEpollEvent(fd); + } + SafeMakeNonblocking(fd); } catch (...) { SafeClose(fd, false); @@ -1421,7 +1426,7 @@ IConnectionWriterPtr CreateOutputConnectionFromPath( bool useDeliveryFence) { return New<TFDConnection>( - CreateWriteFDForConnection(pipePath, capacity), + CreateWriteFDForConnection(pipePath, capacity, useDeliveryFence), std::move(pipePath), std::move(poller), pipeHolder, diff --git a/yt/yt/core/ytree/unittests/yson_struct_ut.cpp b/yt/yt/core/ytree/unittests/yson_struct_ut.cpp index 615fef5a325..614810de56b 100644 --- a/yt/yt/core/ytree/unittests/yson_struct_ut.cpp +++ b/yt/yt/core/ytree/unittests/yson_struct_ut.cpp @@ -3645,5 +3645,75 @@ TEST(TYsonStructTest, OverrideWithComparisonFromTemplatedFunction) //////////////////////////////////////////////////////////////////////////////// +struct THasFieldWithDefaultedStrategy + : public TYsonStructLite +{ + TIntrusivePtr<TConfigWithOneLevelNesting> Field; + + REGISTER_YSON_STRUCT_LITE(THasFieldWithDefaultedStrategy); + + static void Register(TRegistrar registrar) + { + registrar.Parameter("field", &TThis::Field) + .Default() + .DefaultUnrecognizedStrategy(EUnrecognizedStrategy::Throw); + } +}; + +struct THasFieldWithDefaultedStrategyAndOwnRecursiveStrategy + : public TYsonStructLite +{ + TIntrusivePtr<TConfigWithOneLevelNesting> Field; + + REGISTER_YSON_STRUCT_LITE(THasFieldWithDefaultedStrategyAndOwnRecursiveStrategy); + + static void Register(TRegistrar registrar) + { + registrar.UnrecognizedStrategy(EUnrecognizedStrategy::KeepRecursive); + + registrar.Parameter("field", &TThis::Field) + .Default() + .DefaultUnrecognizedStrategy(EUnrecognizedStrategy::Throw) + .EnforceDefaultUnrecognizedStrategy(); + } +}; + +TEST(TYsonStructTest, DefaultUnrecognizedStrategy1) +{ + auto source = BuildYsonNodeFluently().BeginMap() + .Item("field").BeginMap() + .Item("unrecognized").Value(42) + .EndMap() + .EndMap(); + + THasFieldWithDefaultedStrategy yson = {}; + EXPECT_ANY_THROW(Deserialize(yson, source->AsMap())); +} + +TEST(TYsonStructTest, DefaultUnrecognizedStrategy2) +{ + auto source = BuildYsonNodeFluently().BeginMap() + .Item("field").BeginMap() + .Item("sub").BeginMap() + .EndMap() + .EndMap() + .EndMap(); + + THasFieldWithDefaultedStrategy yson = {}; + Deserialize(yson, source->AsMap()); +} + +TEST(TYsonStructTest, DefaultUnrecognizedStrategy3) +{ + auto source = BuildYsonNodeFluently().BeginMap() + .Item("field").BeginMap() + .Item("unrecognized").Value(42) + .EndMap() + .EndMap(); + + THasFieldWithDefaultedStrategyAndOwnRecursiveStrategy yson = {}; + EXPECT_ANY_THROW(Deserialize(yson, source->AsMap())); +} + } // namespace } // namespace NYT::NYTree diff --git a/yt/yt/core/ytree/yson_struct-inl.h b/yt/yt/core/ytree/yson_struct-inl.h index 6e9bdb2d961..34103976daf 100644 --- a/yt/yt/core/ytree/yson_struct-inl.h +++ b/yt/yt/core/ytree/yson_struct-inl.h @@ -288,11 +288,14 @@ void Serialize(const T& value, NYson::IYsonConsumer* consumer) } template <CExternallySerializable T, CYsonStructSource TSource> -void Deserialize(T& value, TSource source, bool postprocess, bool setDefaults) +void Deserialize(T& value, TSource source, bool postprocess, bool setDefaults, std::optional<EUnrecognizedStrategy> strategy) { using TTraits = TGetExternalizedYsonStructTraits<T>; using TSerializer = typename TTraits::TExternalSerializer; auto serializer = TSerializer::template CreateWritable<T, TSerializer>(value, setDefaults); + if (strategy) { + serializer.SetUnrecognizedStrategy(*strategy); + } serializer.Load(std::move(source), postprocess, setDefaults); } diff --git a/yt/yt/core/ytree/yson_struct.h b/yt/yt/core/ytree/yson_struct.h index 4fd373e49c8..24eb811a88b 100644 --- a/yt/yt/core/ytree/yson_struct.h +++ b/yt/yt/core/ytree/yson_struct.h @@ -393,7 +393,7 @@ void Deserialize(TYsonStructBase& value, NYson::TYsonPullParserCursor* cursor); template <CExternallySerializable T> void Serialize(const T& value, NYson::IYsonConsumer* consumer); template <CExternallySerializable T, CYsonStructSource TSource> -void Deserialize(T& value, TSource source, bool postprocess = true, bool setDefaults = true); +void Deserialize(T& value, TSource source, bool postprocess = true, bool setDefaults = true, std::optional<EUnrecognizedStrategy> strategy = {}); template <class T> TIntrusivePtr<T> UpdateYsonStruct( diff --git a/yt/yt/core/ytree/yson_struct_detail-inl.h b/yt/yt/core/ytree/yson_struct_detail-inl.h index bc7dbdb1300..3a4cdea34fa 100644 --- a/yt/yt/core/ytree/yson_struct_detail-inl.h +++ b/yt/yt/core/ytree/yson_struct_detail-inl.h @@ -189,7 +189,7 @@ void LoadFromSource( std::optional<T>& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> recursiveUnrecognizedStrategy); + std::optional<EUnrecognizedStrategy> unrecognizedStrategy); // std::vector template <CYsonStructSource TSource, CStdVector TVector> @@ -197,7 +197,7 @@ void LoadFromSource( TVector& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> recursiveUnrecognizedStrategy); + std::optional<EUnrecognizedStrategy> unrecognizedStrategy); // any map. template <CYsonStructSource TSource, CAnyMap TMap> @@ -205,7 +205,7 @@ void LoadFromSource( TMap& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> recursiveUnrecognizedStrategy); + std::optional<EUnrecognizedStrategy> unrecognizedStrategy); //////////////////////////////////////////////////////////////////////////////// @@ -274,14 +274,14 @@ void LoadFromSource( TIntrusivePtr<T>& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> recursiveUnrecognizedStrategy) + std::optional<EUnrecognizedStrategy> unrecognizedStrategy) { if (!parameter) { parameter = New<T>(); } - if (recursiveUnrecognizedStrategy) { - parameter->SetUnrecognizedStrategy(*recursiveUnrecognizedStrategy); + if (unrecognizedStrategy) { + parameter->SetUnrecognizedStrategy(*unrecognizedStrategy); } parameter->Load(std::move(source), /*postprocess*/ false, /*setDefaults*/ false, path); @@ -293,9 +293,12 @@ void LoadFromSource( T& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> /*ignored*/) + std::optional<EUnrecognizedStrategy> unrecognizedStrategy) { try { + if (unrecognizedStrategy) { + parameter.SetUnrecognizedStrategy(*unrecognizedStrategy); + } parameter.Load(std::move(source), /*postprocess*/ false, /*setDefaults*/ false, path); } catch (const std::exception& ex) { THROW_ERROR_EXCEPTION("Error reading parameter %v", path) @@ -309,10 +312,10 @@ void LoadFromSource( T& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> /*ignored*/) + std::optional<EUnrecognizedStrategy> unrecognizedStrategy) { try { - Deserialize(parameter, std::move(source), /*postprocess*/ false, /*setDefaults*/ false); + Deserialize(parameter, std::move(source), /*postprocess*/ false, /*setDefaults*/ false, unrecognizedStrategy); } catch (const std::exception& ex) { THROW_ERROR_EXCEPTION("Error reading parameter %v", path) << ex; @@ -328,7 +331,7 @@ void LoadFromSource( TExtension& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> recursiveUnrecognizedStrategy) + std::optional<EUnrecognizedStrategy> unrecognizedStrategy) { static_assert(CYsonStructFieldFor<TExtension, TSource>, "You must add alias TImplementsYsonStructField"); @@ -338,7 +341,7 @@ void LoadFromSource( /*postprocess*/ false, /*setDefaults*/ false, path, - recursiveUnrecognizedStrategy); + unrecognizedStrategy); } catch (const std::exception& ex) { THROW_ERROR_EXCEPTION("Error loading parameter %v", path) << ex; @@ -351,7 +354,7 @@ void LoadFromSource( std::optional<T>& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> recursiveUnrecognizedStrategy) + std::optional<EUnrecognizedStrategy> unrecognizedStrategy) { using TTraits = TYsonSourceTraits<TSource>; @@ -363,12 +366,12 @@ void LoadFromSource( } if (parameter.has_value()) { - LoadFromSource(*parameter, std::move(source), path, recursiveUnrecognizedStrategy); + LoadFromSource(*parameter, std::move(source), path, unrecognizedStrategy); return; } T value; - LoadFromSource(value, std::move(source), path, recursiveUnrecognizedStrategy); + LoadFromSource(value, std::move(source), path, unrecognizedStrategy); parameter = std::move(value); } catch (const std::exception& ex) { @@ -383,7 +386,7 @@ void LoadFromSource( TVector& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> recursiveUnrecognizedStrategy) + std::optional<EUnrecognizedStrategy> unrecognizedStrategy) { using TTraits = TYsonSourceTraits<TSource>; @@ -396,7 +399,7 @@ void LoadFromSource( vector.emplace_back(), elementSource, path + "/" + NYPath::ToYPathLiteral(index), - recursiveUnrecognizedStrategy); + unrecognizedStrategy); ++index; }); } catch (const std::exception& ex) { @@ -411,7 +414,7 @@ void LoadFromSource( TMap& parameter, TSource source, const NYPath::TYPath& path, - std::optional<EUnrecognizedStrategy> recursiveUnrecognizedStrategy) + std::optional<EUnrecognizedStrategy> unrecognizedStrategy) { using TTraits = TYsonSourceTraits<TSource>; // TODO(arkady-e1ppa): Remove "typename" when clang-14 is abolished. @@ -425,7 +428,7 @@ void LoadFromSource( value, childSource, path + "/" + NYPath::ToYPathLiteral(key), - recursiveUnrecognizedStrategy); + unrecognizedStrategy); map[DeserializeMapKey<TKey>(key)] = std::move(value); }); } catch (const std::exception& ex) { @@ -751,6 +754,13 @@ void TYsonStructParameter<TValue>::Load( const TLoadParameterOptions& options) { if (node) { + auto unrecognizedStrategy = options.RecursiveUnrecognizedRecursively; + if (EnforceDefaultUnrecognizedStrategy_) { + unrecognizedStrategy.reset(); + } + if (!unrecognizedStrategy) { + unrecognizedStrategy = DefaultUnrecognizedStrategy_; + } if (ResetOnLoad_) { NPrivate::ResetOnLoad(FieldAccessor_->GetValue(self)); } @@ -758,7 +768,7 @@ void TYsonStructParameter<TValue>::Load( FieldAccessor_->GetValue(self), std::move(node), options.Path, - options.RecursiveUnrecognizedRecursively); + unrecognizedStrategy); if (auto* bitmap = self->GetSetFieldsBitmap()) { bitmap->Set(FieldIndex_); @@ -776,6 +786,13 @@ void TYsonStructParameter<TValue>::Load( const TLoadParameterOptions& options) { if (cursor) { + auto unrecognizedStrategy = options.RecursiveUnrecognizedRecursively; + if (EnforceDefaultUnrecognizedStrategy_) { + unrecognizedStrategy.reset(); + } + if (!unrecognizedStrategy) { + unrecognizedStrategy = DefaultUnrecognizedStrategy_; + } if (ResetOnLoad_) { NPrivate::ResetOnLoad(FieldAccessor_->GetValue(self)); } @@ -783,7 +800,7 @@ void TYsonStructParameter<TValue>::Load( FieldAccessor_->GetValue(self), cursor, options.Path, - options.RecursiveUnrecognizedRecursively); + unrecognizedStrategy); if (auto* bitmap = self->GetSetFieldsBitmap()) { bitmap->Set(FieldIndex_); @@ -893,6 +910,20 @@ TYsonStructParameter<TValue>& TYsonStructParameter<TValue>::ResetOnLoad() } template <class TValue> +TYsonStructParameter<TValue>& TYsonStructParameter<TValue>::DefaultUnrecognizedStrategy(EUnrecognizedStrategy strategy) +{ + DefaultUnrecognizedStrategy_.emplace(strategy); + return *this; +} + +template <class TValue> +TYsonStructParameter<TValue>& TYsonStructParameter<TValue>::EnforceDefaultUnrecognizedStrategy() +{ + EnforceDefaultUnrecognizedStrategy_ = true; + return *this; +} + +template <class TValue> const std::vector<TString>& TYsonStructParameter<TValue>::GetAliases() const { return Aliases_; diff --git a/yt/yt/core/ytree/yson_struct_detail.h b/yt/yt/core/ytree/yson_struct_detail.h index bd9f3b1917e..3ed99df7ec2 100644 --- a/yt/yt/core/ytree/yson_struct_detail.h +++ b/yt/yt/core/ytree/yson_struct_detail.h @@ -317,6 +317,12 @@ public: TYsonStructParameter& Alias(const TString& name); // Set field to T() (or suitable analogue) before deserializations. TYsonStructParameter& ResetOnLoad(); + // Uses given unrecognized strategy in |Load| if there was no strategy supplied. + TYsonStructParameter& DefaultUnrecognizedStrategy(EUnrecognizedStrategy strategy); + // Forces given parameter to ignore unrecognized strategy even if it set to + // some recursive version. Combination with |DefaultUnrecognizedStrategy| enables + // behavior which ensures selected default strategy for all fields below. + TYsonStructParameter& EnforceDefaultUnrecognizedStrategy(); // Register constructor with parameters as initializer of default value for ref-counted class. template <class... TArgs> @@ -333,6 +339,8 @@ private: bool TriviallyInitializedIntrusivePtr_ = false; bool Optional_ = false; bool ResetOnLoad_ = false; + std::optional<EUnrecognizedStrategy> DefaultUnrecognizedStrategy_; + bool EnforceDefaultUnrecognizedStrategy_ = false; const int FieldIndex_ = -1; }; diff --git a/yt/yt/library/process/unittests/pipes_ut.cpp b/yt/yt/library/process/unittests/pipes_ut.cpp index b41b7fc5957..6d088d3e3ad 100644 --- a/yt/yt/library/process/unittests/pipes_ut.cpp +++ b/yt/yt/library/process/unittests/pipes_ut.cpp @@ -350,9 +350,9 @@ TEST_F(TNamedPipeReadWriteTest, CapacityDontDiscardSurplus) EXPECT_TRUE(writeFuture.Get().IsOK()); } -#ifdef _linux_ +#if defined(_linux_) && defined(F_SET_PIPE_WAKE_WRITER) -TEST_F(TNamedPipeReadWriteTest, SyncWriteJustWorks) +TEST_F(TNamedPipeReadWriteTest, DeliveryFencedWriteJustWorks) { SetUpWithDeliveryFence(); @@ -374,22 +374,6 @@ TEST_F(TNamedPipeReadWriteTest, SyncWriteJustWorks) EXPECT_TRUE(writeFuture.Get().IsOK()); } -#else - -TEST_F(TNamedPipeReadWriteTest, SyncWriteUnsupportedPlatform) -{ - SetUpWithDeliveryFence(); - - TString text("aabbb"); - auto writeBuffer = TSharedRef::FromString(text); - auto writeFuture = Writer->Write(writeBuffer); - - // Future is set with error because platform is not supported - auto error = writeFuture.Get(); - EXPECT_FALSE(error.IsOK()); - EXPECT_TRUE(error.GetMessage().Contains("Delivery fenced write failed: FIONDREAD is not supported on your platform")); -} - #endif //////////////////////////////////////////////////////////////////////////////// |
