diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ada3096751ee4fd48b5bccda743f3bd01ff423fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**/__pycache__ +out diff --git a/.gn b/.gn index 10d86795bea852279c227ea3a02a8c8f586bb48b..191b1f088d90e07f0010d61fa8e8d62d809708c3 100644 --- a/.gn +++ b/.gn @@ -1 +1 @@ -buildconfig = "//build/BUILDCONFIG.gn" +buildconfig = "//build/gn/BUILDCONFIG.gn" diff --git a/build/build.sh b/build/build.sh index 48c0777a563e1cc82dfe2c98123b6b0d914b1106..8b9587d2a0f871f5cb688a1e3f1b3b4427392111 100755 --- a/build/build.sh +++ b/build/build.sh @@ -37,6 +37,7 @@ if [[ "${PROJECT_DIR}x" == "x" ]]; then fi # Exec builder +python3 ${PROJECT_DIR}/build/builder.py --project-dir ${PROJECT_DIR} build $* # Check builder result if [[ "$?" -ne 0 ]]; then diff --git a/build/builder.py b/build/builder.py new file mode 100755 index 0000000000000000000000000000000000000000..7c53018e6413099ecd82370f07185e8ee0129394 --- /dev/null +++ b/build/builder.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This is an entry file: parse subcommand and call releated python script. + +import sys +import argparse +import os +from rich.console import Console + +from builder.commands.build import Builder +from builder.commands.format import Formatter +from builder.commands.package import Packager +from builder.common.env_checker import checker +from builder.common.logger import logger, LoggerManager + +VERSION="0.1.0-rc1" + +class FtBuilder: + def __init__(self): + self.default_project_dir = os.path.abspath(os.path.dirname(os.path.split(os.path.realpath(__file__))[0])) + + def banner(self) -> str: + return rf""" _,---. ,--.--------. .=-.-. ,----. + .-`.' , \/==/, - , -\ _..---. .--.-. .-.-./==/_ / _.-. _,..---._ ,-.--` , \ .-.,.---. + /==/_ _.-'\==\.-. - ,_./ .' .'.-. \/==/ -|/=/ |==|, |.-,.'| /==/, - \ |==|- _.-` /==/ ` \ +/==/- '..-. `--`|==\- \ /==/- '=' /|==| ,||=| -|==| |==|, | |==| _ _\|==| `.-.|==|-, .=., | +|==|_ , / |==|_ | |==|-, ' |==|- | =/ |==|- |==|- | |==| .=. /==/_ , /|==| '=' / +|==| .--' |==|- | |==| .=. \|==|, \/ - |==| ,|==|, | |==|,| | -|==| .-' |==|- , .' +|==|- | |==|, | /==/- '=' ,|==|- , /==|- |==|- `-._|==| '=' /==|_ ,`-._|==|_ . ,'. +/==/ \ /==/ -/ |==| - //==/ , _ .'/==/. /==/ - , ,/==|-, _`//==/ , //==/ /\ , ) +`--`---' `--`--` `-._`.___,' `--`..---' `--`-``--`-----'`-.`.____.' `--`-----`` `--`-`--`--' + version: {VERSION} +""" + + def parse_args(self): + parser = argparse.ArgumentParser( + prog='builder.py', + description="Fangtian builder for OpenEuler OS.", + epilog='Please submit building issues to https://gitee.com/openeuler-graphics/fangtian_build.') + + parser.add_argument('--project-dir', type=str, help="Specify the project root dir.") + # parser.add_argument('--enable-logfile', action='store_true', help="Enable saving log to file.") + parser.add_argument('--version', action='version', version='%(prog)s ' + VERSION) + + subparsers = parser.add_subparsers(dest='subcommand', required=True, help="builder subcommands") + # Subcommand: build + build_parser = subparsers.add_parser('build', help='Build the project') + build_parser.add_argument('-t', '--target-cpu', + type=str, + choices=['x64', 'x86'], + default='x64', + help='Specify the target CPU type.') + build_parser.add_argument('-b', '--build-type', + choices=['debug', 'release'], + default='debug', + help='Specify the build type') + build_parser.add_argument('-j', '--jobs', + type=int, + default=4, + help='Specify the number of jobs to run simultaneously during building.') + build_parser.add_argument('--enable-musl', + action='store_true', + help='Enable musl C lib. if musl is disabled, you\'ll use system C lib.') + build_parser.add_argument('-cc', '--export-compile-commands', + action='store_true', + help='Export "compile_commands.json" file.') + build_parser.add_argument('-v', '--verbose', + action='store_true', + help='Show all logs.') + build_parser.add_argument('--escape-build', + action='store_true', + help='Only do "prebuild" operations.') + build_parser.add_argument('-l', '--log-level', + type=str, + choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'FATAL', 'CRITICAL'], + default='NOTSET', + help='Set log level of builder.') + + # Subcommand: format + format_parser = subparsers.add_parser('format', help='Format C/C++ & GN files') + format_parser.add_argument('--code-path', + type=str, + help='Specify target code path to format.') + format_parser.add_argument('--gn-path', + type=str, + default=os.path.join(self.default_project_dir, 'prebuilts/build-tools/linux-x64/bin/gn'), + help='Show all format lines.') + format_parser.add_argument('-v', '--verbose', + action='store_true', + help='Show all format lines.') + + # Subcommand: check + check_parser = subparsers.add_parser('check', help='System or project checking') + check_parser.add_argument('--install-packages', + action='store_true', + help='Install missing packages.') + + # Subcommand: package + package_parser = subparsers.add_parser('package', help='Tools for packaging RPM') + package_subparsers = package_parser.add_subparsers(dest='package_subcommand', required=True, help="builder subcommands") + + package_prepare_parser = package_subparsers.add_parser('prepare', help='Prepare toml file for packaging.') + package_prepare_parser.add_argument('-o', '--output', + type=str, + required=True, + help='Specify the output dir of toml file.') + package_prepare_parser.add_argument('-n', '--name', + type=str, + required=True, + help='Specify the package name.') + build_parser.add_argument('--use-musl', + action='store_true', + help='Add musl k-v to toml file.') + + package_prepare_parser = package_subparsers.add_parser('generate', help='Setup rpm tree & Generate spec file & Build the RPM package.') + package_prepare_parser.add_argument('--target-dir', + type=str, + required=True, + help='Specify the dir which includes files to be installed.') + package_prepare_parser.add_argument('--config-file', + type=str, + required=True, + help='Specify the path of toml config file.') + + # Parse args + self.args = parser.parse_args() + + def _setup_logger(self): + lm = LoggerManager() + if self.args.__contains__("log_level") and self.args.log_level: + lm.setup_level(self.args.log_level) + else: + lm.setup_level("NOTSET") + + # if self.args.enable_logfile: + # logger.error("Enable log file is not supported yet.") + # lm.add_file_logger(os.path.join(self.args.project_dir, "out", "log", "build", "builder.log")) + + def prepare(self): + if self.args is None: + Console().print("FtBuiler Inner Error: args is None", style="bold red") + + self._setup_logger() + + if self.args.project_dir is None: + self.args.project_dir = os.path.abspath(os.path.dirname(os.path.split(os.path.realpath(__file__))[0])) + + def do_subcommand(self) -> bool: + print(self.banner()) + + logger.debug(f"Project dir: {self.args.project_dir}") + + if self.args is None or self.args.subcommand is None: + return False + + subcommand = self.args.subcommand + self.args.subcommand = None + + # Do acual subcommand + rst = False + if (subcommand == "build"): + builder = Builder(self.args) + rst = builder.exec_command() + elif (subcommand == "format"): + formatter = Formatter(self.args) + rst = formatter.exec_command() + elif (subcommand == "check"): + rst = checker.check_system_env(self.args.project_dir, install_missing_pkg=self.args.install_packages) + elif (subcommand == "package"): + packager = Packager(self.args) + rst = packager.exec_command() + else: + logger.error(f"Unknow subcommand: {subcommand}") + sys.exit(1) + + # Check subcommand result + if rst: + logger.debug(f"{subcommand} done.") + else: + logger.error(f"{subcommand} failed!") + + return rst + +def main() -> int: + builder = FtBuilder() + builder.parse_args() + + console = Console() + try: + builder.prepare() + + return 0 if builder.do_subcommand() else 1 + except: + console.print_exception(show_locals=True) + return 1 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/build/builder/__init__.py b/build/builder/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8858d320ebb984d33d15583e8c87ced57f470729 --- /dev/null +++ b/build/builder/__init__.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/build/builder/commands/build.py b/build/builder/commands/build.py new file mode 100755 index 0000000000000000000000000000000000000000..2e7e4d3bd54eb3384490bd241e6df5f8979f296c --- /dev/null +++ b/build/builder/commands/build.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from builder.common.logger import logger +from builder.common.utils import exec_sys_command +from builder.common.env_checker import checker + +class Builder: + def __init__(self, args): + self.args = args + + self.project_dir = args.project_dir + self.build_output_dir = os.path.join(args.project_dir, "out", args.build_type.title(), args.target_cpu) + self._build_tools_dir = os.path.join(args.project_dir, "prebuilts", "build-tools", f"linux-{args.target_cpu}", "bin") + self.gn_path = os.path.join(self._build_tools_dir, "gn") + self.ninja_path = os.path.join(self._build_tools_dir, "ninja") + + self._args_list = [] + + if args.escape_build is True: + logger.warning(f"Escaping build procedure.") + self.should_do_build = False + self.should_do_postbuild = False + else: + self.should_do_build = True + self.should_do_postbuild = True + + def pre_build(self) -> bool: + return checker.check_system_env(self.project_dir) + + def post_build(self) -> bool: + if self.args.export_compile_commands is True: + # return exec_sys_command(['ln', '-sf', os.path.join(self.build_output_dir, 'compile_commands.json'), self.project_dir])[0] + exec_sys_command(['rm', '-f', os.path.join(self.project_dir, 'compile_commands.json')]) + return exec_sys_command(['cp', os.path.join(self.build_output_dir, 'compile_commands.json'), self.project_dir])[0] + + return True + + def launch_gn(self) -> bool: + """This function executes the gn command, which generate ninja files""" + # Generate GN build cmd + gn_subargs = [ + f'project_root_dir="{self.project_dir}"', + ] + + if self.args.build_type.lower() == "debug": + gn_subargs.append(f'is_debug=true') + else: + gn_subargs.append(f'is_debug=false') + + if self.args.enable_musl is True: + gn_subargs.append(f'use_musl=true') + else: + gn_subargs.append(f'use_musl=false') + + gn_args = [ + self.gn_path, + 'gen', + self.build_output_dir, + '--args={}'.format(" ".join(gn_subargs)) + ] + + if self.args.export_compile_commands is True: + gn_args.append('--export-compile-commands') + + if self.args.verbose is True: + gn_args.append('-v') + + # Execute GN build cmd + logger.info(f"Launch \"gn\" with: `{' '.join(gn_args)}`") + return exec_sys_command(gn_args)[0] + + def launch_ninja(self) -> bool: + """This function executes the ninja command, which compiles the project""" + ninja_args = [ + self.ninja_path, + '-C', + self.build_output_dir, + f'-j {self.args.jobs}', + ] + + if self.args.verbose is True: + ninja_args.append('-v') + + logger.info(f"Launch \"ninja\" with: `{' '.join(ninja_args)}`") + return exec_sys_command(ninja_args)[0] + + def get_cmds(self) -> list: + command_chain = [ self.pre_build ] + + if self.should_do_build: + command_chain.append(self.launch_gn) + command_chain.append(self.launch_ninja) + if self.should_do_postbuild: + command_chain.append(self.post_build) + + return command_chain + + def exec_command(self) -> bool: + logger.info(f'Exec "build" command...') + + cmds = self.get_cmds() + + for cmd in cmds: + if cmd() is False: + return False + + return True diff --git a/build/builder/commands/format.py b/build/builder/commands/format.py new file mode 100755 index 0000000000000000000000000000000000000000..4cc8f4838089345433f640c090ee507e0b83b6b4 --- /dev/null +++ b/build/builder/commands/format.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from builder.common.logger import logger +from builder.common.utils import exec_sys_command + +_EXCLUDE_DIRS = ["out", "prebuilts", "third_party"] +_C_CPP_EXTS = [".c", ".cc", ".cxx", ".cpp", ".h", ".hpp"] +_GN_EXTS = [".gn", ".gni"] + +class Formatter: + def __init__(self, args): + self.args = args + + self.clang_format_cmds = ['clang-format', '-i', '-style=file', '-fallback-style=none'] + self.gn_format_cmds = [self.args.gn_path, 'format'] + + # Init exclude dirs + self.exclude_dirs = [] + for dir in _EXCLUDE_DIRS: + self.exclude_dirs.append(os.path.join(self.args.project_dir, dir)) + + # Init target code path + if self.args.code_path is None: + self.code_path = self.args.project_dir + else: + self.code_path = os.path.abspath(self.code_path) + + def _is_subpath(self, path, parent_paths) -> bool: + path = os.path.abspath(path) + + return any(os.path.commonpath([path, p]) == p for p in parent_paths) + + def pre_format(self) -> bool: + if self.args.verbose: + self.clang_format_cmds.append("-verbose") + + return True + + def _do_format(self, abs_file_name: str, exts: list, format_cmds: list) -> bool: + should_format = False + for ext in exts: + if abs_file_name.endswith(ext): + should_format = True + break + + if should_format: + cmds = format_cmds + [abs_file_name] + rst, _ = exec_sys_command(cmds) # do format + if not rst: + return False + + return True + + + def do_format(self) -> bool: + logger.info(f"Start format files in {self.code_path}...") + + for [dirpath, _, filenames] in os.walk(self.code_path): + # Escape some dirs + if self._is_subpath(dirpath, self.exclude_dirs): + logger.debug(f"Escape dir: {dirpath}") + continue + + # Find all files and try to format them + for filename in filenames: + abs_file_name = os.path.join(dirpath, filename) + # try to do clang format + if not self._do_format(abs_file_name, _C_CPP_EXTS, self.clang_format_cmds): + logger.error(f"Failed to format C/C++ file: {abs_file_name}") + return False + # try to do gn format + if not self._do_format(abs_file_name, _GN_EXTS, self.gn_format_cmds): + logger.error(f"Failed to format GN file: {abs_file_name}") + return False + + return True + + def exec_command(self) -> bool: + logger.info(f'Exec "format" command...') + + if not self.pre_format(): + return False + + return self.do_format() + diff --git a/build/builder/commands/package.py b/build/builder/commands/package.py new file mode 100755 index 0000000000000000000000000000000000000000..9fbde03e8dd7342fee575af6d66dcee58abb43ef --- /dev/null +++ b/build/builder/commands/package.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os +import toml +import re +from typing import Any + +from builder.common.logger import logger +from builder.common.utils import exec_sys_command + +class Packager: + def __init__(self, args): + self.args = args + self.configs_dir = os.path.join(self.args.project_dir, "build/configs") + + def prepare(self) -> bool: + # Try to make output dir + if not os.path.exists(self.args.output): + exec_sys_command(['mkdir', '-p', self.args.output], True) + + # Generate Toml file + with open(os.path.join(self.configs_dir, "rpm_config_template.toml"), 'r') as template_file: + template_data = template_file.read() + + new_toml_data = template_data.replace('', self.args.name) + + new_toml_path = os.path.join(self.args.output, f"{self.args.name}_rpm_config.toml") + with open(new_toml_path, 'w') as new_toml_file: + new_toml_file.write(new_toml_data) + + logger.info(f"Output toml file: {new_toml_path}") + + return True + + def _gen_spec_file(self, rpm_configs: dict[str, Any]) -> bool: + # Check args + if not os.path.exists(self.args.config_file): + logger.error(f"Config file {self.args.config_file} not found.") + return False + + if not os.path.exists(self.args.target_dir): + logger.error(f"Target dir {self.args.config_file} is not exist.") + return False + + # Generate spec file + with open(os.path.join(self.configs_dir, "rpm_template.spec"), 'r') as template_file: + template_data = template_file.read() + + new_spec_data = template_data.replace('', rpm_configs['name']) + new_spec_data = new_spec_data.replace('', rpm_configs['version']) + new_spec_data = new_spec_data.replace('', rpm_configs['release']) + new_spec_data = new_spec_data.replace('', rpm_configs['summary']) + new_spec_data = new_spec_data.replace('', rpm_configs['license']) + new_spec_data = new_spec_data.replace('', rpm_configs['url']) + new_spec_data = new_spec_data.replace('', rpm_configs['build_arch']) + new_spec_data = new_spec_data.replace('', rpm_configs['description']) + + paths_set = set() + mkdir_commands = "" + copy_commands = "" + files_scriptlet = "" + + for file, install_path in rpm_configs['install_paths'].items(): + paths_set.add(install_path) + + file_path = os.path.join(self.args.target_dir, file) + if not os.path.exists(file_path): + logger.error(f"File {file_path} is not exist.") + return False + copy_commands += "cp -pdf %s %%{buildroot}%s\n" % (file_path, install_path) + + files_scriptlet += os.path.join(install_path, os.path.basename(file_path)) + "\n" + + for path in paths_set: + mkdir_commands += "mkdir -p %%{buildroot}%s\n" % (path) + + new_spec_data = new_spec_data.replace('', mkdir_commands) + new_spec_data = new_spec_data.replace('', copy_commands) + new_spec_data = new_spec_data.replace('', files_scriptlet) + + with open(os.path.join(self.args.target_dir, f"{rpm_configs['name']}.spec"), 'w') as spec_file: + spec_file.write(new_spec_data) + + return True + + def generate(self) -> bool: + logger.info(f"Do package generate with {self.args.target_dir} {self.args.config_file}") + + # Read config file (TOML) + with open(self.args.config_file, 'r') as f: + rpm_configs = toml.load(f) + + # Setup RPM tree + exec_sys_command("rpmdev-setuptree", False) + + # Generate spec file`` + self._gen_spec_file(rpm_configs) + + # Build rpm package + rst, output = exec_sys_command(["rpmbuild", "-bb", os.path.join(self.args.target_dir, f"{rpm_configs['name']}.spec")]) + if rst == True: + output_rpm_file = re.search(r'^Wrote:\s+(.*)$', output, flags=re.MULTILINE) + if output_rpm_file: + logger.info(f"RPM package has been generated to : {output_rpm_file.group(1)}") + else: + logger.error(f"Failed to exec rpmbuild.") + return False + + return True + + def exec_command(self) -> bool: + logger.info(f'Exec "package" command...') + + subcommand = self.args.package_subcommand + + if (subcommand == "prepare"): + return self.prepare() + elif (subcommand == "generate"): + return self.generate() + else: + logger.error("Unknow subcommand.") + sys.exit(1) diff --git a/build/builder/common/__init__.py b/build/builder/common/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/build/builder/common/env_checker.py b/build/builder/common/env_checker.py new file mode 100755 index 0000000000000000000000000000000000000000..0094390bda234d146105ef073fd3cdbe35571307 --- /dev/null +++ b/build/builder/common/env_checker.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import toml + +from builder.common.logger import logger +from builder.common.utils import exec_sys_command + +class Checker: + """ + Checker is a singleton. + """ + _instance = None + + def __new__(cls): + if cls._instance is None: + cls._instance = super().__new__(cls) + return cls._instance + + def __init__(self): + with open('/etc/os-release', 'r') as f: + for line in f: + if line.startswith('ID='): + self.os_id = line.split('=')[1].strip().strip('"').lower() + elif line.startswith('VERSION_ID='): + self.os_version = line.split('=')[1].strip().strip('"') + + def _is_package_installed(self, pkg: str) -> bool: + is_success, output = exec_sys_command(['rpm', '-q', pkg], is_show_output=False) + + if output: + return is_success + else: + return False + + def _install_packages(self, pkgs: list) -> bool: + logger.info('Try install system packages: {} ...'.format(', '.join(pkgs))) + is_success, _output = exec_sys_command(['sudo', 'yum', 'install', '-y', ' '.join(pkgs)]) + return is_success + + def check_system_env(self, project_dir: str, install_missing_pkg: bool = False) -> bool: + import os + + logger.info('Checking system environment...') + + # Open config file + config_path = os.path.join(project_dir, 'build', 'configs', 'system_deps.toml') + with open(config_path, 'r') as f: + configs = toml.load(f) + + # Check os version + if self.os_id in configs['dependencies']['supported_os'] and self.os_version in configs['dependencies'][self.os_id]['supported_version']: + logger.debug(f'Current OS: {self.os_id} {self.os_version}') + else: + logger.error(f'Unsupported OS: {self.os_id} {self.os_version}') + return False + + # Check packages + package_deps = configs.get(self.os_id, {}).get(self.os_version, {}).get('package_deps', []) + if package_deps is None: + logger.error(f'No package_deps config for {self.os_id} {self.os_version} in {config_path}') + return False + + missing_packages = [] + for pkg in package_deps: + if not self._is_package_installed(pkg): + missing_packages.append(pkg) + + if missing_packages == []: + return True + elif install_missing_pkg: + return self._install_packages(missing_packages) + else: + logger.error('System package "{}" is not installed. Please install them by using `yum install` or `dnf install`'.format(', '.join(missing_packages))) + return False + +checker = Checker() diff --git a/build/builder/common/logger.py b/build/builder/common/logger.py new file mode 100755 index 0000000000000000000000000000000000000000..5811e5a0983fa10a0163c65737d2221119cf2944 --- /dev/null +++ b/build/builder/common/logger.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import logging +from rich.style import Style +from rich.text import Text +from rich.highlighter import Highlighter +from rich.logging import RichHandler + +def _combine_regex(*regexes: str) -> str: + """Combine a number of regexes in to a single regex. + Returns: + str: New regex with all regexes ORed together. + """ + return "|".join(regexes) + +class AdvancedHighlighter(Highlighter): + """Highlights the text typically produced from ``__repr__`` methods.""" + + base_style = "repr." + re_highlights = [ + r"(?P<)(?P[-\w.:|]*)(?P[\w\W]*)(?P>)", + # r'(?P\B-[\w_]{1,50})=(?P"?[\w_]+"?)?', + r"(?P[][{}()])", + r'(?P\B-{1,2}[\w_-]{1,50})=(?P"?[\w_+=-]+"?)?', + _combine_regex( + r"(?P[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})", + r"(?P([A-Fa-f0-9]{1,4}::?){7}[A-Fa-f0-9]{1,4})", + r"(?P(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})", + r"(?P(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})", + r"(?P[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})", + # r"(?P[\w.]*?)\(", + r"\b(?PTrue)\b|\b(?PFalse)\b|\b(?PNone)\b", + r"(?P\.\.\.)", + r"(?P(?(?((\.\.)?|\b[-\w_]+)(/[-\w._+]+)*\/)(?P[-\w._+]*)?", + r"(?b?'''.*?(?(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#]*)", + ), + ] + + def highlight(self, text: Text) -> None: + highlight_words = text.highlight_words + highlight_regex = text.highlight_regex + for re_highlight in self.re_highlights: + highlight_regex(re_highlight, style_prefix=self.base_style) + + # Highlight -Dxxx, -fxxx, -Wxxx + highlight_regex(r"\B(?P-(D|f|W)[\w+_-]{1,50})", style_prefix=self.base_style) + # Highlight "error" / "failed" / "invalid" + highlight_words(["error:", "warning:", "ERROR", "invalid"], style=Style(color="bright_red", bold=True), case_sensitive=True) + highlight_words(["failed:", "failed"], style=Style(color="bright_red", bold=True), case_sensitive=False) + # Highlight "success" / "done" + highlight_words(["successfully", "success", "done."], style=Style(color="bright_green", bold=True), case_sensitive=False) + # Highlight CC / CXX / ASM / AR / SOLINK / LINK / STAMP / COPY + highlight_words([" CC ", " CXX ", " ASM ", " AR ", " SOLINK ", " LINK ", " STAMP ", " COPY "], style=Style(color="yellow", bold=True), case_sensitive=True) + # Highlight GN print + highlight_words(["[GN INFO]"], style=Style(color="blue", bold=True), case_sensitive=False) + highlight_words(["[GN DEBUG]"], style=Style(color="dark_blue", bold=True), case_sensitive=False) + highlight_words(["[GN ERROR]", "[GN WARNING]"], style=Style(color="red", bold=True), case_sensitive=False) + # Highlight ^~~~~~~ & ^------ + highlight_regex(r"\B(\^~+)", style=Style(color="red", bold=True)) + highlight_regex(r"\B(\^-+)", style=Style(color="red", bold=True)) + +class LoggerManager: + """ + LoggerManager is a singleton. + """ + _instance = None + + def __new__(cls): + if cls._instance is None: + cls._instance = super().__new__(cls) + return cls._instance + + def __init__(self): + pass + + def setup_level(self, log_level: str): + log_level = log_level.upper() + + try: + handler = RichHandler(rich_tracebacks=True,highlighter=AdvancedHighlighter()) + logging.basicConfig( + level=log_level, + format="%(message)s", + datefmt="[%X]", + handlers=[handler] + ) + except: + self.get_logger().error("Invalid log level: '%s'", log_level) + sys.exit(1) + + self.log_level = log_level + + def add_file_logger(self, out_path, expire_time=2) -> None: + # self.file_logger_handler = loguru_logger.add( + # os.path.join(self.args.project_dir, "out", "log", "build", "builder.log"), + # level="DEBUG", + # format="[{level:<8}] {time:HH:mm:ss} | {file}:{line} {name}({module}) | {process}:{thread} | {message}", + # retention="1 day", + # rotation=datetime.timedelta(hours=2) + # ) + pass + + def get_logger(self) -> logging.Logger: + return logging.getLogger("rich") + +logger = LoggerManager().get_logger() diff --git a/build/builder/common/utils.py b/build/builder/common/utils.py new file mode 100755 index 0000000000000000000000000000000000000000..a9270b16a48a25144673a0503797839dca00b6b6 --- /dev/null +++ b/build/builder/common/utils.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import subprocess + +from builder.common.logger import logger + +def _handle_sys_output(line) -> str: + text = line.rstrip('').rstrip('\n') + + return text + +def exec_sys_command(cmd, is_show_output=True, **kwargs) -> tuple[bool, str]: + # Run this cmd + process = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + encoding='utf-8', + **kwargs) + + # Print output + stdout = [] + if process.stdout is not None: + for line in process.stdout: + text = _handle_sys_output(line) + stdout.append(text) + if is_show_output: + logger.debug(' || ' + text) + + stderr = [] + if process.stderr is not None: + for line in process.stderr: + text = _handle_sys_output(line) + logger.error(' !! ' + text) + if is_show_output: + stderr.append(text) + + ret_code = process.wait() + + # Check return code + if ret_code != 0: + logger.warning('Failed to exec shell cmd: `{}`'.format(' '.join(cmd))) + return (False, '\n'.join(stderr)) + else: + return (True, '\n'.join(stdout)) diff --git a/build/configs/requirements.txt b/build/configs/requirements.txt new file mode 100755 index 0000000000000000000000000000000000000000..d2c14202b81a2bb9118e4139ee3c5020b2363ff0 --- /dev/null +++ b/build/configs/requirements.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +rich==13.3.1 +toml==0.10.2 diff --git a/build/configs/system_deps.toml b/build/configs/system_deps.toml new file mode 100755 index 0000000000000000000000000000000000000000..c327cb5be4d8f9c021f5863511c56ab88725efb0 --- /dev/null +++ b/build/configs/system_deps.toml @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +title = "Fangtian System Dependencies" + +[dependencies] +supported_os = ["openeuler"] + +[dependencies.openeuler] +supported_version = ["22.03"] + +[openeuler."22.03"] +package_deps = [ + "clang", + "compiler-rt", + "llvm-devel", + "python3", + +] diff --git a/build/gn/BUILD.gn b/build/gn/BUILD.gn index c6e020f8fdde0fdda1fde9f09261a13af0005e75..90a6155c9773734a110575e68800094098b88d98 100644 --- a/build/gn/BUILD.gn +++ b/build/gn/BUILD.gn @@ -12,4 +12,7 @@ # limitations under the License. group("ft_engine") { + deps = [ + "//third_party/bounds_checking_function/ft_build:libsec_static", + ] } diff --git a/build/gn/BUILDCONFIG.gn b/build/gn/BUILDCONFIG.gn index 268a845a901f60c7e86161c0059b00d4625ba568..360a83ffc30184f1ddf082eaa72cb1248e4272af 100644 --- a/build/gn/BUILDCONFIG.gn +++ b/build/gn/BUILDCONFIG.gn @@ -46,6 +46,15 @@ declare_args() { # We add this parameter to speed up link process, enable_lto_O0 default is false. enable_lto_O0 = false + + is_official_build = false + # Component build. Setting to true compiles targets declared as "components" + # as shared libraries loaded dynamically. This speeds up development time. + # When false, components will be linked statically. + # + # For more information see + # https://chromium.googlesource.com/chromium/src/+/master/docs/component_build.md + is_component_build = true # Set to true when compiling with the Clang compiler is_clang = true @@ -94,6 +103,37 @@ if (_default_toolchain != "") { set_default_toolchain(_default_toolchain) } +# ============================================================================= +# OS DEFINITIONS +# ============================================================================= +# +# We set these various is_FOO booleans for convenience in writing OS-based +# conditions. +# +# - is_android, is_chromeos, is_ios, and is_win should be obvious. +# - is_mac is set only for desktop Mac. It is not set on iOS. +# - is_posix is true for mac and any Unix-like system (basically everything +# except Fuchsia and Windows). +# - is_linux is true for desktop Linux, but not for ChromeOS nor Android (which +# is generally too different despite being based on the Linux kernel). +# +# Do not add more is_* variants here for random lesser-used Unix systems like +# aix or one of the BSDs. If you need to check these, just check the +# current_os value directly. + +is_linux = current_os == "linux" +is_ft = current_os == "linux" +is_android = current_os == "android" +is_chromeos = current_os == "chromeos" +is_fuchsia = current_os == "fuchsia" +is_ios = current_os == "ios" +is_mac = current_os == "mac" +is_nacl = current_os == "nacl" +is_win = current_os == "win" || current_os == "winuwp" + +is_apple = is_ios || is_mac +is_posix = !is_win && !is_fuchsia +is_desktop_linux = current_os == "linux" # TARGET DEFAULTS CONFIGS default_compiler_configs = [ "//build/gn/configs/compiler:compiler", diff --git a/build/gn/configs/BUILD.gn b/build/gn/configs/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..afafc26d4d312b5808e98d12246581e36d94d5f2 --- /dev/null +++ b/build/gn/configs/BUILD.gn @@ -0,0 +1,184 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + + +import("//build/gn/configs/sanitizers/sanitizers.gni") + +# Debug/release ---------------------------------------------------------------- + +config("debug") { + defines = [ + "DYNAMIC_ANNOTATIONS_ENABLED=1", + "WTF_USE_DYNAMIC_ANNOTATIONS=1", + ] + cflags = [ + # generates debugging information during compilation. + "-g", + # compiler optimization option that attempts to improve the runtime speed of the code by performing more optimizations. + "-O0", + ] + cflags_cc = [] + + if (is_clang) { + # Allow comparing the address of references and 'this' against 0 + # in debug builds. Technically, these can never be null in + # well-defined C/C++ and Clang can optimize such checks away in + # release builds, but they may be used in asserts in debug builds. + cflags_cc += [ + "-Wno-undefined-bool-conversion", + "-Wno-tautological-undefined-compare", + ] + } + + # if (is_linux && current_cpu == "x64" && enable_iterator_debugging) { + # # Enable libstdc++ debugging facilities to help catch problems early, see + # # http://crbug.com/65151 . + # # defines += [ "_GLIBCXX_DEBUG=1" ] + # } +} + +config("release") { + defines = [ + "NDEBUG", + "LOG_HIDE_FILE_LINE" + ] + cflags = [ + # a compiler optimization option that attempts to improve the runtime speed of the code by performing more optimizations. + "-O3", + ] + + # Sanitizers. + if (is_tsan) { + defines += [ + "DYNAMIC_ANNOTATIONS_ENABLED=1", + "WTF_USE_DYNAMIC_ANNOTATIONS=1", + ] + } else { + defines += [ "NVALGRIND" ] + if (!is_nacl) { + # NaCl always enables dynamic annotations. Currently this value is set to + # 1 for all .nexes. + defines += [ "DYNAMIC_ANNOTATIONS_ENABLED=0" ] + } + } +} + +# Default libraries ------------------------------------------------------------ + +# This config defines the default libraries applied to all targets. +config("default_libs") { + if (is_linux) { + libs = [ + "dl", + "pthread", + "rt", + ] + } else { + assert(false, "[GN ERROR] Unsupport os for default libraries") + } +} + +# Common deps ----------------------------------------------------------- + +# Only //build/gn/configs/BUILDCONFIG.gn should reference this. +group("common_deps") { + public_deps = [] + + if (using_sanitizer) { + public_deps += [ "//build/config/sanitizers:deps" ] + } + + # if (use_custom_libcxx) { + # if (is_double_framework) { + # public_deps += [ "${asdk_libs_dir}/ndk/libcxx:libcxx" ] + # } else { + # public_deps += [ "//third_party/libcxx:libcxx" ] + # } + # } + + # if (use_afl) { + # public_deps += [ "//third_party/afl" ] + # } + + # if (use_musl_oh && current_toolchain != host_toolchain && !is_mingw) { + # public_deps += [ "//third_party/musl:soft_shared_libs" ] + # } + if (use_musl_oh) { + # TODO + # public_deps += [ "//third_party/musl:soft_shared_libs" ] + } +} + +group("executable_deps") { + public_deps = [ ":common_deps" ] +} + +group("loadable_module_deps") { + public_deps = [ ":common_deps" ] +} + +group("shared_library_deps") { + public_deps = [ ":common_deps" ] +} + +group("static_library_deps") { + # if (use_musl_oh && current_toolchain != host_toolchain && !is_mingw) { + # public_deps = [ "//third_party/musl:musl_headers" ] + # } + if (use_musl_oh) { + # TODO + # public_deps = [ "//third_party/musl:musl_headers" ] + } +} + +group("source_set_deps") { + # if (use_musl_oh && current_toolchain != host_toolchain && !is_mingw) { + # public_deps = [ "//third_party/musl:musl_headers" ] + # } + if (use_musl_oh) { + # TODO + # public_deps = [ "//third_party/musl:musl_headers" ] + } +} + +# Executable configs ----------------------------------------------------------- + +# This config defines the configs applied to all executables. +config("executable_config") { + configs = [] + + if (is_linux || is_ft || current_os == "aix") { + if (is_ft) { + configs += [ "//build/gn/configs/fangtian:executable_config" ] + } + } + + # # If we're using the prebuilt instrumented libraries with the sanitizers, we + # # need to add ldflags to every binary to make sure they are picked up. + # if (prebuilt_instrumented_libraries_available) { + # configs += [ "//third_party/instrumented_libraries:prebuilt_ldflags" ] + # } + # if (use_locally_built_instrumented_libraries) { + # configs += [ "//third_party/instrumented_libraries:locally_built_ldflags" ] + # } + # configs += [ "//build/config/sanitizers:link_executable" ] +} + +# Shared library configs ------------------------------------------------------- + +# This config defines the configs applied to all shared libraries. +config("shared_library_config") { + configs = [] + + # # If we're using the prebuilt instrumented libraries with the sanitizers, we + # # need to add ldflags to every binary to make sure they are picked up. + # if (prebuilt_instrumented_libraries_available) { + # configs += [ "//third_party/instrumented_libraries:prebuilt_ldflags" ] + # } + # if (use_locally_built_instrumented_libraries) { + # configs += [ "//third_party/instrumented_libraries:locally_built_ldflags" ] + # } + # configs += [ "//build/config/sanitizers:link_shared_library" ] +} diff --git a/build/gn/configs/compiler/BUILD.gn b/build/gn/configs/compiler/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..88e9c08358066b83515425f33965a50f1a83274d --- /dev/null +++ b/build/gn/configs/compiler/BUILD.gn @@ -0,0 +1,691 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/gn/configs/compiler/compiler.gni") +import("//build/gn/toolchain/toolchain.gni") + +if (current_cpu == "arm" || current_cpu == "arm64") { + import("//build/config/arm.gni") +} + +declare_args() { + # Default to warnings as errors for default workflow, where we catch + # warnings with known toolchains. Allow overriding this e.g. for Chromium + # builds on Linux that could use a different version of the compiler. + # With GCC, warnings in no-Chromium code are always not treated as errors. + treat_warnings_as_errors = true + + # Build with C++ RTTI enabled. Chromium builds without RTTI by default, + # but some sanitizers are known to require it, like CFI diagnostics + # and UBsan variants. + use_rtti = use_cfi_diag || is_ubsan_vptr || is_ubsan_security + + # Allow projects that wish to stay on C++11 to override Chromium's default. + use_cxx11 = false +} + +# Determine whether to enable or disable frame pointers, based on the platform +# and build arguments. +if (is_mac || is_linux) { + enable_frame_pointers = is_debug +} else { + # Explicitly ask for frame pointers, otherwise: + # * Stacks may be missing for sanitizer and profiling builds. + # * Debug tcmalloc can crash (crbug.com/636489). + # enable_frame_pointers = using_sanitizer || enable_profiling || is_debug + assert(false, "[GN ERROR] Unknow OS for frame pointer") +} + +# compiler ---------------------------------------------------------------- +# +# Base compiler configuration. +config("compiler") { + cflags = [] + cflags_cc = [] + ldflags = [] + configs = [] + defines = [] + + # System-specific flags. If your compiler flags apply to one of the + # categories here, add it to the associated file to keep this shared config + # smaller. + if (is_ft) { + configs += [ "//build/gn/configs/fangtian:compiler" ] + } + + if (is_linux) { + if (use_pic) { + cflags += [ "-fPIC" ] + ldflags += [ "-fPIC" ] + } + } + + # C11/C++11 compiler flags setup. + # --------------------------- + if (is_linux || is_ft || (is_nacl && is_clang) || current_os == "aix") { + if (is_clang) { + standard_prefix = "c" + + # Since we build with -std=c* and not -std=gnu*, _GNU_SOURCE will not be + # defined by the compiler. However, lots of code relies on the + # non-standard features that _GNU_SOURCE enables, so define it manually. + defines += [ "_GNU_SOURCE" ] + + if (is_nacl) { + # Undefine __STRICT_ANSI__ to get non-standard features which would + # otherwise not be enabled by NaCl's sysroots. + cflags += [ "-U__STRICT_ANSI__" ] + } + } else { + # Gcc does not support ##__VA_ARGS__ when in standards-conforming mode, + # but we use this feature in several places in Chromium. + standard_prefix = "gnu" + } + + # cflags_c += [ "-std=${standard_prefix}11" ] + if (use_cxx11) { + # Override Chromium's default for projects that wish to stay on C++11. + cflags_cc += [ "-std=${standard_prefix}++11" ] + } else { + cflags_cc += [ "-std=${standard_prefix}++17" ] + } + } else if (!is_win && !is_nacl && !is_mingw) { + if (use_cxx11) { + cflags_cc += [ "-std=c++11" ] + } else { + cflags_cc += [ "-std=c++17" ] + } + } +} + +# This provides the basic options to select the target CPU and ABI. +# It is factored out of "compiler" so that special cases can use this +# without using everything that "compiler" brings in. Options that +# tweak code generation for a particular CPU do not belong here! +# See "compiler_codegen", below. +config("compiler_cpu_abi") { + cflags = [] + ldflags = [] + defines = [] + + if (is_posix && !is_mac) { + # CPU architecture. We may or may not be doing a cross compile now, so for + # simplicity we always explicitly set the architecture. + if (current_cpu == "x64") { + cflags += [ + "-m64", + "-march=x86-64", + ] + ldflags += [ "-m64" ] + } else if (current_cpu == "x86") { + cflags += [ "-m32" ] + ldflags += [ "-m32" ] + if (!is_nacl) { + cflags += [ + "-msse2", + "-mfpmath=sse", + "-mmmx", + ] + } + } else if (current_cpu == "arm") { + if (is_clang && !is_ft && !is_nacl) { + cflags += [ "--target=arm-linux-gnueabihf" ] + ldflags += [ "--target=arm-linux-gnueabihf" ] + } + if (!is_nacl) { + cflags += [ + "-march=$arm_arch", + "-mfloat-abi=$arm_float_abi", + ] + } + if (arm_tune != "") { + cflags += [ "-mtune=$arm_tune" ] + } + } else if (current_cpu == "arm64") { + if (is_clang && !is_ft && !is_nacl) { + cflags += [ "--target=aarch64-linux-gnu" ] + ldflags += [ "--target=aarch64-linux-gnu" ] + } + if (is_clang && is_ft) { + ldflags += [ "-Wl,--hash-style=gnu" ] + } + cflags += [ + "-march=$arm_arch", + "-mfloat-abi=$arm_float_abi", + "-mfpu=$arm_fpu", + ] + ldflags += [ "-march=$arm_arch" ] + } + } + + asmflags = cflags + if (current_cpu == "arm64") { + asmflags += [ "-march=armv8.2-a+dotprod+fp16" ] + } +} + +# runtime_library ---------------------------------------------------------------- +# +# Sets the runtime library and associated options. +# +# How do you determine what should go in here vs. "compiler" above? Consider if +# a target might choose to use a different runtime library (ignore for a moment +# if this is possible or reasonable on your system). If such a target would want +# to change or remove your option, put it in the runtime_library config. If a +# target wants the option regardless, put it in the compiler config. + +config("runtime_library") { + defines = [] + configs = [] + + # # The order of this config is important: it must appear before + # # ohos:runtime_library. + # if (is_posix) { + # configs += [ "//build/gn/configs/posix:runtime_library" ] + # } + + # # System-specific flags. If your compiler flags apply to one of the + # # categories here, add it to the associated file to keep this shared config + # # smaller. + if (is_ft) { + configs += [ "//build/gn/configs/fangtian:runtime_library" ] + } + + if (is_component_build) { + defines += [ "COMPONENT_BUILD" ] + } +} + +# default_warnings ------------------------------------------------------------ +# +# Collects all warning flags that are used by default. This is used as a +# subconfig of both chromium_code and no_chromium_code. This way these +# flags are guaranteed to appear on the compile command line after -Wall. +config("default_warnings") { + cflags = [] + cflags_cc = [] + ldflags = [] + + # Suppress warnings about ABI changes on ARM (Clang doesn't give this + # warning). + if (current_cpu == "arm" && !is_clang) { + cflags += [ "-Wno-psabi" ] + } + + if (!is_clang) { + cflags_cc += [ + # See comment for -Wno-c++11-narrowing. + "-Wno-narrowing", + ] + + # -Wunused-local-typedefs is broken in gcc, + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63872 + cflags += [ "-Wno-unused-local-typedefs" ] + + # Don't warn about "maybe" uninitialized. Clang doesn't include this + # in -Wall but gcc does, and it gives false positives. + cflags += [ "-Wno-maybe-uninitialized" ] + cflags += [ "-Wno-deprecated-declarations" ] + + # GCC assumes 'this' is never nullptr and optimizes away code + # like "if (this == nullptr) ...": [1]. However, some Chromium + # code relies on these types of null pointer checks [2], so + # disable this optimization. + # [1] https://gcc.gnu.org/gcc-6/porting_to.html#this-cannot-be-null + # [2] https://crbug.com/784492#c13 + cflags += [ "-fno-delete-null-pointer-checks" ] + + # -Wcomment gives too many false positives in the case a + # backslash ended comment line is followed by a new line of + # comments + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61638 + cflags += [ "-Wno-comments" ] + } + + # Common Clang and GCC warning setup. + if (!is_win || is_clang) { + cflags += [ + # Disables. + "-Wno-missing-field-initializers", # "struct foo f = {0};" + "-Wno-unused-parameter", # Unused function parameters. + ] + } + + if (is_clang) { + cflags += [ + # This warns on using ints as initializers for floats in + # initializer lists (e.g. |int a = f(); CGSize s = { a, a };|), + # which happens in several places in chrome code. Not sure if + # this is worth fixing. + "-Wno-c++11-narrowing", + "-Wno-unneeded-internal-declaration", + ] + if (use_musl) { + cflags += [ + "-Wno-error=c99-designator", + "-Wno-error=anon-enum-enum-conversion", + "-Wno-error=implicit-fallthrough", + "-Wno-error=sizeof-array-div", + "-Wno-error=reorder-init-list", + "-Wno-error=range-loop-construct", + "-Wno-error=deprecated-copy", + "-Wno-error=implicit-int-float-conversion", + "-Wno-error=inconsistent-dllimport", + "-Wno-error=unknown-warning-option", + "-Wno-error=abstract-final-class", + "-Wno-error=sign-compare", + "-Wno-error=int-in-bool-context", + "-Wno-error=xor-used-as-pow", + "-Wno-error=return-stack-address", + "-Wno-error=dangling-gsl", + ] + } + + # use_xcode_clang only refers to the iOS toolchain, host binaries use + # chromium's clang always. + if (!is_nacl && current_toolchain == host_toolchain) { + # Flags NaCl (Clang 3.7) and Xcode 9.2 (Clang clang-900.0.39.2) do not + # recognize. + print("[GN DEBUG] current_toolchain: $current_toolchain") + print("[GN DEBUG] host_toolchain: $host_toolchain") + + cflags += [ "-Wno-enum-compare-switch" ] + } + } +} + +# chromium_code --------------------------------------------------------------- +# +# Toggles between higher and lower warnings for code that is (or isn't) +# part of Chromium. + +config("chromium_code_warnings") { + cflags = [ "-Wall" ] + if (treat_warnings_as_errors) { + cflags += [ "-Werror" ] + + # The compiler driver can sometimes (rarely) emit warnings before calling + # the actual linker. Make sure these warnings are treated as errors as + # well. + ldflags = [ "-Werror" ] + } + if (is_clang) { + # Enable extra warnings for chromium_code when we control the compiler. + cflags += [ "-Wextra" ] + } + + # In Chromium code, we define __STDC_foo_MACROS in order to get the + # C99 macros on Mac and Linux. + defines = [ + "__STDC_CONSTANT_MACROS", + "__STDC_FORMAT_MACROS", + ] + + if (!is_debug && !using_sanitizer && + (!is_linux || !is_clang || is_official_build)) { + # _FORTIFY_SOURCE isn't really supported by Clang now, see + # http://llvm.org/bugs/show_bug.cgi?id=16821. + # It seems to work fine with Ubuntu 12 headers though, so use it in + # official builds. + # + # Non-chromium code is not guaranteed to compile cleanly with + # _FORTIFY_SOURCE. Also, fortified build may fail when optimizations are + # disabled, so only do that for Release build. + defines += [ "_FORTIFY_SOURCE=2" ] + } + + if (is_clang) { + cflags += [ + # Warn on missing break statements at the end of switch cases. + # For intentional fallthrough, use FALLTHROUGH; from + # base/compiler_specific.h + # "-Wimplicit-fallthrough", + + # Thread safety analysis. See base/thread_annotations.h and + # https://clang.llvm.org/docs/ThreadSafetyAnalysis.html + "-Wthread-safety", + ] + } + + configs = [ ":default_warnings" ] +} + +config("no_chromium_code_warnings") { + cflags = [] + + # GCC may emit unsuppressible warnings so don't add -Werror for no chromium + # code. crbug.com/589724 + if (treat_warnings_as_errors && is_clang) { + cflags += [ "-Werror" ] + ldflags = [ "-Werror" ] + } + if (is_clang && !is_nacl) { + cflags += [ "-Wall" ] + } + + if (is_clang) { + cflags += [ + # Lots of third-party libraries have unused variables. Instead of + # suppressing them individually, we just blanket suppress them here. + "-Wno-unused-variable", + ] + } + + configs = [ ":default_warnings" ] +} + +# rtti ---------------------------------------------------------------- +# +# Allows turning Run-Time Type Identification on or off. + +config("rtti") { + cflags_cc = [ "-frtti" ] +} + +config("no_rtti") { + # Some sanitizer configs may require RTTI to be left enabled globally + if (!use_rtti) { + cflags_cc = [ "-fno-rtti" ] + cflags_objcc = cflags_cc + } +} + +# export_dynamic --------------------------------------------------------------- +# +# Ensures all exported symbols are added to the dynamic symbol table. This is +# necessary to expose Chrome's custom operator new() and operator delete() (and +# other memory-related symbols) to libraries. Otherwise, they might +# (de)allocate memory on a different heap, which would spell trouble if pointers +# to heap-allocated memory are passed over shared library boundaries. +config("export_dynamic") { + if (is_desktop_linux || export_libcxxabi_from_executables) { + ldflags = [ "-rdynamic" ] + } +} + +# thin_archive ----------------------------------------------------------------- +# +# Enables thin archives on posix. Regular archives directly include the object +# files used to generate it. Thin archives merely reference the object files. +# This makes building them faster since it requires less disk IO, but is +# inappropriate if you wish to redistribute your static library. +# This config is added to the global config, so thin archives should already be +# enabled. If you want to make a distributable static library, you need to do 2 +# things: +# 1. Set complete_static_lib so that all dependencies of the library make it +# into the library. See `gn help complete_static_lib` for details. +# 2. Remove the thin_archive config, so that the .a file actually contains all +# .o files, instead of just references to .o files in the build directory +config("thin_archive") { + # Mac and iOS use the mac-specific "libtool" command, not ar, which doesn't + # have a "thin archive" mode (it does accept -T, but it means truncating + # archive names to 16 characters, which is not what we want). + if (is_posix && !is_nacl && !is_mac) { + arflags = [ "-T" ] + } +} + +# exceptions ------------------------------------------------------------------- +# +# Allows turning Exceptions on or off. + +config("exceptions") { + cflags_cc = [ "-fexceptions" ] + cflags_objcc = cflags_cc +} + +config("no_exceptions") { + cflags_cc = [ "-fno-exceptions" ] + cflags_objcc = cflags_cc +} + +# Optimization ----------------------------------------------------------------- +# +# The BUILDCONFIG file sets the "default_optimization" config on targets by +# default. It will be equivalent to either "optimize" (release) or +# "no_optimize" (debug) optimization configs. +# +# You can override the optimization level on a per-target basis by removing the +# default config and then adding the named one you want: +# +# configs -= [ "//build/config/compiler:default_optimization" ] +# configs += [ "//build/config/compiler:optimize_max" ] + +# Shared settings for both "optimize" and "optimize_max" configs. +# IMPORTANT: On Windows "/O1" and "/O2" must go before the common flags. +common_optimize_on_cflags = [] +common_optimize_on_ldflags = [ + # Warn in case of text relocations. + "-Wl,--warn-shared-textrel", +] + +config("default_stack_frames") { + if (is_posix) { + if (enable_frame_pointers) { + cflags = [ "-fno-omit-frame-pointer" ] + } else { + cflags = [ "-fomit-frame-pointer" ] + } + } + # On Windows, the flag to enable framepointers "/Oy-" must always come after + # the optimization flag [e.g. "/O2"]. The optimization flag is set by one of + # the "optimize" configs, see rest of this file. The ordering that cflags are + # applied is well-defined by the GN spec, and there is no way to ensure that + # cflags set by "default_stack_frames" is applied after those set by an + # "optimize" config. Similarly, there is no way to propagate state from this + # config into the "optimize" config. We always apply the "/Oy-" config in the + # definition for common_optimize_on_cflags definition, even though this may + # not be correct. +} + +# Default "optimization on" config. +config("optimize") { + if (optimize_for_size && !is_nacl) { + # Favor size over speed. + if (is_clang) { + cflags = [ "-O2" ] + common_optimize_on_cflags + } else { + cflags = [ "-Os" ] + common_optimize_on_cflags + } + } else { + cflags = [ "-O2" ] + common_optimize_on_cflags + } + ldflags = common_optimize_on_ldflags +} + +# Same config as 'optimize' but without the WPO flag. +config("optimize_no_wpo") { + if (optimize_for_size && !is_nacl) { + # Favor size over speed. + if (is_clang) { + cflags = [ "-Oz" ] + common_optimize_on_cflags + } else { + cflags = [ "-Os" ] + common_optimize_on_cflags + } + } else if (optimize_for_fuzzing) { + cflags = [ "-O0" ] + common_optimize_on_cflags + } else { + cflags = [ "-O2" ] + common_optimize_on_cflags + } + ldflags = common_optimize_on_ldflags +} + +# Turn off optimizations. +config("no_optimize") { + if (!ft_full_debug) { + # On fangtian we kind of optimize some things that don't affect debugging + # much even when optimization is disabled to get the binary size down. + if (is_clang) { + cflags = [ "-Oz" ] + common_optimize_on_cflags + ldflags = common_optimize_on_ldflags + } else { + cflags = [ "-Os" ] + common_optimize_on_cflags + ldflags = common_optimize_on_ldflags + } + } else { + # On ft_full_debug mode, we close all optimization + cflags = [ "-O0" ] + ldflags = [] + } +} + +# Turns up the optimization level. On Windows, this implies whole program +# optimization and link-time code generation which is very expensive and should +# be used sparingly. +config("optimize_max") { + ldflags = common_optimize_on_ldflags + if (optimize_for_fuzzing) { + cflags = [ "-O0" ] + common_optimize_on_cflags + } else { + cflags = [ "-O2" ] + common_optimize_on_cflags + } +} + +# This config can be used to override the default settings for per-component +# and whole-program optimization, optimizing the particular target for speed +# instead of code size. This config is exactly the same as "optimize_max" +# except that we use -O3 instead of -O2 on non-win, non-IRT platforms. +config("optimize_speed") { + ldflags = common_optimize_on_ldflags + if (optimize_for_fuzzing) { + cflags = [ "-O0" ] + common_optimize_on_cflags + } else { + cflags = [ "-O3" ] + common_optimize_on_cflags + } +} + +config("optimize_fuzzing") { + cflags = [ "-O0" ] + common_optimize_on_cflags + ldflags = common_optimize_on_ldflags + visibility = [ ":default_optimization" ] +} + +# The default optimization applied to all targets. This will be equivalent to +# either "optimize" or "no_optimize", depending on the build flags. +config("default_optimization") { + if (is_debug) { + configs = [ ":no_optimize" ] + } else if (optimize_for_fuzzing) { + assert(!is_win, "Fuzzing optimize level not supported on Windows") + + # # Coverage build is quite slow. Using "optimize_for_fuzzing" makes it even + # # slower as it uses "-O1" instead of "-O3". Prevent that from happening. + # assert(!use_clang_coverage, + # "optimize_for_fuzzing=true should not be used with " + + # "use_clang_coverage=true.") + configs = [ ":optimize_fuzzing" ] + } else { + # configs = [ ":optimize" ] + configs = [ ":optimize_speed" ] + } +} + +# Symbols ---------------------------------------------------------------------- + +# The BUILDCONFIG file sets the "default_symbols" config on targets by +# default. It will be equivalent to one the three specific symbol levels. +# +# You can override the symbol level on a per-target basis by removing the +# default config and then adding the named one you want: +# +# configs -= [ "//build/config/compiler:default_symbols" ] +# configs += [ "//build/config/compiler:symbols" ] + +# Full symbols. +config("symbols") { + cflags = [] + if (current_cpu == "arm") { + # dump_syms has issues with dwarf4 on arm, https://crbug.com/744956 + # + # debug fission needs DWARF DIEs to be emitted at version 4. + # Chrome OS emits Debug Frame in DWARF1 to make breakpad happy. [1] + # Unless fangtian needs debug fission, DWARF3 is the simplest solution. + # + # [1] crrev.com/a81d5ade0b043208e06ad71a38bcf9c348a1a52f + cflags += [ "-gdwarf-3" ] + } + if (!ft_full_debug) { + cflags += [ "-g2" ] + } else { + # Set -g3 symbol level when ft_full_debug is true + cflags += [ "-g3" ] + } + + asmflags = cflags + ldflags = [] + + if (!is_mac && !is_nacl && current_cpu != "x86" && (use_gold || use_lld)) { + if (is_clang) { + # This flag enables the GNU-format pubnames and pubtypes sections, + # which lld needs in order to generate a correct GDB index. + cflags += [ "-ggnu-pubnames" ] + } + # FIXME + # ldflags += [ "-Wl,--gdb-index" ] + } +} + +# Minimal symbols. +# This config guarantees to hold symbol for stack trace which are shown to user +# when crash happens in unittests running on buildbot. +config("minimal_symbols") { + cflags = [] + if (current_cpu == "arm") { + # dump_syms has issues with dwarf4 on arm, https://crbug.com/744956 + cflags += [ "-gdwarf-3" ] + } + cflags += [ "-g1" ] + ldflags = [] + if (is_ft && is_clang) { + # fangtian defaults to symbol_level=1 builds in production builds + # (https://crbug.com/648948), but clang, unlike gcc, doesn't emit + # DW_AT_linkage_name in -g1 builds. -fdebug-info-for-profiling enables + # that (and a bunch of other things we don't need), so that we get + # qualified names in stacks. + cflags += [ "-fdebug-info-for-profiling" ] + } + + # Note: -gsplit-dwarf implicitly turns on -g2 with clang, so don't pass it. + asmflags = cflags +} + +# No symbols. +config("no_symbols") { + if (!is_win) { + cflags = [ "-g0" ] + asmflags = cflags + } +} + +# Default symbols. +config("default_symbols") { + if (symbol_level == 0) { + configs = [ ":no_symbols" ] + } else if (symbol_level == 1) { + configs = [ ":minimal_symbols" ] + } else if (symbol_level == 2) { + configs = [ ":symbols" ] + } else { + assert(false) + } + + # This config is removed by base unittests app. + if (is_ft && is_clang && strip_debug_info) { + configs += [ ":strip_debug" ] + } +} + +config("strip_debug") { + if (!defined(ldflags)) { + ldflags = [] + } + ldflags += [ "-Wl,--strip-debug" ] +} + +config("no_common") { + if (is_clang) { + cflags = [ "-fno-common" ] + asmflags = cflags + } +} diff --git a/build/gn/configs/compiler/compiler.gni b/build/gn/configs/compiler/compiler.gni new file mode 100755 index 0000000000000000000000000000000000000000..d8683ff6420b905c0a881f4efb6ebffe8fa05416 --- /dev/null +++ b/build/gn/configs/compiler/compiler.gni @@ -0,0 +1,71 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/gn/configs/sanitizers/sanitizers.gni") +import("//build/gn/configs/fangtian/abi.gni") + +declare_args() { + # How many symbols to include in the build. This affects the performance of + # the build since the symbols are large and dealing with them is slow. + # 2 means regular build with symbols. + # 1 means minimal symbols, usually enough for backtraces only. Symbols with + # internal linkage (static functions or those in anonymous namespaces) may not + # appear when using this level. + # 0 means no symbols. + # -1 means auto-set according to debug/release and platform. + symbol_level = -1 + + # ohos-only: Strip the debug info of libraries within lib.unstripped to + # reduce size. As long as symbol_level > 0, this will still allow stacks to be + # symbolized. + strip_debug_info = false + + # Whether or not we should use position independent code. + use_pic = true +} + +# If `symbol_level` wasn't manually set, set to an appropriate default. +assert(symbol_level >= -1 && symbol_level <= 2, "Invalid symbol_level") +if (symbol_level == -1) { + if (use_order_profiling) { + # With instrumentation enabled, debug info puts libchrome.so over 4gb, which + # causes the linker to produce an invalid ELF. http://crbug.com/574476 + symbol_level = 0 + } else if (!is_component_build && + !(ft_64bit_target_cpu && !build_app_secondary_abi)) { + # Reduce symbol level when it will cause invalid elf files to be created + # (due to file size). https://crbug.com/648948. + symbol_level = 1 + } else if ((!is_nacl && !is_linux) || is_debug || is_official_build) { + # Linux builds slower by having symbols as part of the target binary, + # whereas Mac and Windows have them separate, so in Release Linux, default + # them off, but keep them on for Official builds and Chromecast builds. + symbol_level = 2 + } else if (using_sanitizer) { + # Sanitizers need line table info for stack traces. They don't need type + # info or variable info, so we can leave that out to speed up the build. + # Sanitizers also require symbols for filename suppressions to work. + symbol_level = 1 + } else { + symbol_level = 0 + } +} + +# If true, optimize for size. Does not affect windows builds. +# Linux & Mac favor speed over size. +optimize_for_size = is_ft + +declare_args() { + # Set to true to use lld, the LLVM linker. This flag may be used on Windows, + # Linux. + use_lld = is_clang && + (is_linux && current_cpu == "x64") +} + +declare_args() { + # Whether to use the gold linker from binutils instead of lld or bfd. + use_gold = !use_lld && + (is_linux && (current_cpu == "x64" || current_cpu == "x86" || + current_cpu == "arm")) +} diff --git a/build/gn/configs/fangtian/BUILD.gn b/build/gn/configs/fangtian/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..f87245f363b6f3fcec7c548ee39b8ef554730cc9 --- /dev/null +++ b/build/gn/configs/fangtian/BUILD.gn @@ -0,0 +1,161 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("config.gni") + +import("//build/gn/configs/compiler/compiler.gni") + +# This is included by reference in the //build/gn/configs/compiler config that +# is applied to all targets. It is here to separate out the logic that is +# ohos-only. +config("compiler") { + cflags = [ + "-ffunction-sections", + "-fno-short-enums", + "-ferror-limit=10" + ] + defines = [ + # The NDK has these things, but doesn't define the constants to say that it + # does. Define them here instead. + "HAVE_SYS_UIO_H", + ] + + ldflags = [ + "-Wl,--no-undefined", + "-Wl,--exclude-libs=libunwind.a", + "-Wl,--exclude-libs=libc++.a", + + # Don't allow visible symbols from libraries that contain + # assembly code with symbols that aren't hidden properly. + # http://crbug.com/448386 + "-Wl,--exclude-libs=libvpx_assembly_arm.a", + ] + + if (use_musl_oh) { + # cflags += [ "--target=$abi_target" ] + # ldflags += [ "--target=$abi_target" ] + # include_dirs = [ "${musl_sysroot}/usr/include/${abi_target}" ] + } + + # Assign any flags set for the C compiler to asmflags so that they are sent + # to the assembler. + asmflags = cflags +} + +# This is included by reference in the //build/config/compiler:runtime_library +# config that is applied to all targets. It is here to separate out the logic +# that is ohos-only. Please see that target for advice on what should go in +# :runtime_library vs. :compiler. +config("runtime_library") { + defines = [ + "__GNU_SOURCE=1", # Necessary for clone(). + # "CHROMIUM_CXX_TWEAK_INLINES", # Saves binary size. + ] + + ldflags = [] + + # We add this parameter to speed up link process, enable_lto_O0 default is false. + if (!is_mac && !is_win && use_lld && enable_lto_O0) { + ldflags += [ "-Wl,--lto-O0" ] + } + + # Config musl runtime library + if (use_musl) { + prebuilt_libcxx_path = project_root_dir + "/prebuilts/llvm" + + # Ignore std libs + ldflags += [ + "-nostdlib", + "-nostdlib++" + ] + + # Add C preprocessor defines. + defines += [ + "__MUSL__", + # "_LIBCPP_HAS_MUSL_LIBC", + ] + if (is_clang) { + defines += ["__BUILD_LINUX_WITH_CLANG"] + } + + # Add libraries to link, because we have set `-nostdlib` ld flag + libs = [] + + if (current_cpu == "arm") { + # arm builds of libc++ starting in NDK r12 depend on unwind. + libs += [ "unwind" ] + } + + if (use_musl_oh) { + # ldflags += [ + # "-L" + rebase_path("${musl_sysroot}/usr/lib/${abi_target}", root_build_dir), + # "-L" + rebase_path("${clang_base_path}/lib/clang/12.0.1/lib/${abi_target}", + # root_build_dir), + # ] + # TODO: musl_oh + assert(false, "[GN ERROR] Unsupport musl_oh for toolchain currently.") + } else { + # same as `-L` + lib_dirs = [ + "/usr/musl/lib", # musl C lib dir + "/usr/lib64/clang/12.0.1/lib/linux", # clang_rt dir + "${prebuilt_libcxx_path}/lib", # llvm C++ lib + ] + + # Add libc++ search path + ldflags += [ + "-Wl,-rpath,/usr/lib64", + "-Wl,-rpath,/usr/local/lib64", + ] + + if (current_cpu == "x64") { + libs += [ + # rebase_path(libclang_rt_file), + "/usr/lib64/clang/12.0.1/lib/libclang_rt.builtins-x86_64.a", + ] + } else { + assert(false, "[GN ERROR] Unsupported CPU for clang_rt.") + } + } + + libs += [ + "c", + # "/usr/musl/lib/libc.a", + + "c++", + "c++abi", + ] + + cflags = [ + # using musl include dir + "-nostdinc", + "--sysroot", "/usr/musl", + "-isystem", "/usr/musl/include", + ] + + cflags_cc = [ + # using libc++ include dir + "-nostdinc++", + "-I${prebuilt_libcxx_path}/include/c++/v1", + "-I/usr/lib64/clang/12.0.1/include" + ] + + if (current_cpu == "arm" && arm_version == 6) { + libs += [ "atomic" ] + } + } +} + +config("executable_config") { + # Option: enable PIE(Position Independent Executable), for security. + cflags = [ "-fPIE" ] + asmflags = [ "-fPIE" ] + ldflags = [ "-pie" ] + + # Option: enable dynamic linking and disable copy relocation for shared lib. + ldflags += [ + "-Bdynamic", + "-Wl,-z,nocopyreloc", + ] +} diff --git a/build/gn/configs/fangtian/abi.gni b/build/gn/configs/fangtian/abi.gni new file mode 100755 index 0000000000000000000000000000000000000000..aa729f398d12a56130e8b5e31ec73ef2841b489b --- /dev/null +++ b/build/gn/configs/fangtian/abi.gni @@ -0,0 +1,70 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Logic separated out from config.gni so that it can be used by compiler.gni +# without introducing a circular dependency. + +assert(is_ft) + +declare_args() { + # Adds intrumentation to each function. Writes a file with the order that + # functions are called at startup. + use_order_profiling = false + + # Only effective if use_order_profiling = true. When this is true, + # instrumentation switches from startup profiling after a delay, and + # then waits for a devtools memory dump request to dump all + # profiling information. When false, the same delay is used to switch from + # startup, and then after a second delay all profiling information is dumped. + devtools_instrumentation_dumping = false + + # Builds secondary abi for APPs, supports build 32-bit arch as secondary + # abi in 64-bit Monochrome and WebView. + build_app_secondary_abi = true +} + +assert(!devtools_instrumentation_dumping || use_order_profiling, + "devtools_instrumentation_dumping requires use_order_profiling") + +if (current_cpu == "x86") { + ft_app_abi = "x86" +} else if (current_cpu == "arm") { + import("//build/config/arm.gni") + if (arm_version < 7) { + ft_app_abi = "armeabi" + } else { + ft_app_abi = "armeabi-v7a" + } +# } else if (current_cpu == "x86_64") { +} else if (current_cpu == "x64") { + ft_app_abi = "x64" +} else if (current_cpu == "arm64") { + ft_app_abi = "arm64-v8a" +} else { + assert(false, "Unknown ABI: " + current_cpu) +} + +# if (target_cpu == "arm64" || target_cpu == "x86_64") { +if (target_cpu == "arm64" || target_cpu == "x64") { + ft_64bit_target_cpu = true +} else if (target_cpu == "arm" || target_cpu == "x86") { + ft_64bit_target_cpu = false +} else { + assert(false, "Unknown target CPU: $target_cpu") +} + +# Intentionally do not define ft_app_secondary_abi_cpu and +# ft_app_secondary_abi for 32-bit target_cpu, since they are not used. +if (target_cpu == "arm64") { + ft_secondary_abi_cpu = "arm" + ft_app_secondary_abi = "armeabi-v7a" +} else if (target_cpu == "x64") { + ft_secondary_abi_cpu = "x86" + ft_app_secondary_abi = "x86" +} + +if (defined(ft_secondary_abi_cpu)) { + ft_secondary_abi_toolchain = + "//build/gn/toolchain/linux:clang_${ft_secondary_abi_cpu}" +} diff --git a/build/gn/configs/fangtian/config.gni b/build/gn/configs/fangtian/config.gni new file mode 100755 index 0000000000000000000000000000000000000000..583782e3498cd3235843abcf5cd3b1b3312bdf6c --- /dev/null +++ b/build/gn/configs/fangtian/config.gni @@ -0,0 +1,18 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +if (is_ft) { + import("abi.gni") + + # Tips: same as `musl_target_triple` in //third_party/musl/musl_config.gni + if (current_cpu == "arm") { + abi_target = "arm-linux-fangtian" + } else if (current_cpu == "arm64") { + abi_target = "arm64-linux-fangtian" + } else if (current_cpu == "x64" || current_cpu == "x86_64") { + abi_target = "x64-linux-fangtian" + } else { + assert(false, "[GN ERROR] Not support cpu architecture.") + } +} diff --git a/build/gn/configs/sanitizers/sanitizers.gni b/build/gn/configs/sanitizers/sanitizers.gni new file mode 100755 index 0000000000000000000000000000000000000000..257cabbd030215921f61b7d1f5cb175a27c27953 --- /dev/null +++ b/build/gn/configs/sanitizers/sanitizers.gni @@ -0,0 +1,133 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +declare_args() { + # Compile for Address Sanitizer to find memory bugs. + is_asan = false + + # Customize asan detection. + asan_detector = false + + # Compile for Leak Sanitizer to find leaks. + is_lsan = false + + # Compile for Memory Sanitizer to find uninitialized reads. + is_msan = false + + # Compile for Thread Sanitizer to find threading bugs. + is_tsan = false + + # Compile for Undefined Behavior Sanitizer to find various types of + # undefined behavior (excludes vptr checks). + is_ubsan = false + + # Halt the program if a problem is detected. + is_ubsan_no_recover = false + + # Compile for Undefined Behavior Sanitizer's null pointer checks. + is_ubsan_null = false + + # Compile for Undefined Behavior Sanitizer's vptr checks. + is_ubsan_vptr = false + + # Compile with SafeStack shadow stack support. + is_safestack = false + + # Track where uninitialized memory originates from. From fastest to slowest: + # 0 - no tracking, 1 - track only the initial allocation site, 2 - track the + # chain of stores leading from allocation site to use site. + msan_track_origins = 2 + + # Use dynamic libraries instrumented by one of the sanitizers instead of the + # standard system libraries. Set this flag to download prebuilt binaries from + # GCS. + use_prebuilt_instrumented_libraries = false + + # Use dynamic libraries instrumented by one of the sanitizers instead of the + # standard system libraries. Set this flag to build the libraries from source. + use_locally_built_instrumented_libraries = false + + # Compile with Control Flow Integrity to protect virtual calls and casts. + # See http://clang.llvm.org/docs/ControlFlowIntegrity.html + is_cfi = target_os == "linux" && !is_chromeos && target_cpu == "x64" && + is_official_build + + # Enable checks for bad casts: derived cast and unrelated cast. + use_cfi_cast = false + + # Enable checks for indirect function calls via a function pointer. + use_cfi_icall = target_os == "linux" && !is_chromeos && target_cpu == "x64" && + is_official_build + + # Print detailed diagnostics when Control Flow Integrity detects a violation. + use_cfi_diag = false + + # Let Control Flow Integrity continue execution instead of crashing when + # printing diagnostics (use_cfi_diag = true). + use_cfi_recover = false + + # Compile for fuzzing with LLVM LibFuzzer. + # See http://www.chromium.org/developers/testing/libfuzzer + use_libfuzzer = false + + # Compile for fuzzing with AFL. + use_afl = false + + # Enables core ubsan security features. Will later be removed once it matches + # is_ubsan. + is_ubsan_security = false + + # Compile for fuzzing with Dr. Fuzz + # See http://www.chromium.org/developers/testing/dr-fuzz + use_drfuzz = false + + # Helper variable for testing builds with disabled libfuzzer. + # Not for client use. + disable_libfuzzer = false + + # Optimize for coverage guided fuzzing (balance between speed and number of + # branches). Can be also used to remove non-determinism and other issues. + optimize_for_fuzzing = false + + # Value for -fsanitize-coverage flag. Setting this causes + # use_sanitizer_coverage to be enabled. + # This flag is not used for libFuzzer (use_libfuzzer=true) unless we are on + # Mac. Instead, we use: + # -fsanitize=fuzzer-no-link + # Default value when unset and use_fuzzing_engine=true: + # trace-pc-guard + # Default value when unset and use_sanitizer_coverage=true: + # trace-pc-guard,indirect-calls + sanitizer_coverage_flags = "" +} + +is_v8_host_toolchain = + current_toolchain == "//build/gn/toolchain/linux:clang_x64_v8_arm64" || + current_toolchain == "//build/gn/toolchain/linux:clang_x86_v8_arm" + +# Disable sanitizers for non-default toolchains. +if (current_toolchain == host_toolchain || is_v8_host_toolchain) { + is_asan = false + is_cfi = false + is_lsan = false + is_msan = false + is_tsan = false + is_ubsan = false + is_ubsan_null = false + is_ubsan_no_recover = false + is_ubsan_security = false + is_ubsan_vptr = false + msan_track_origins = 0 + sanitizer_coverage_flags = "" + use_afl = false + use_cfi_diag = false + use_cfi_recover = false + use_drfuzz = false + use_libfuzzer = false + use_prebuilt_instrumented_libraries = false + use_locally_built_instrumented_libraries = false + use_sanitizer_coverage = false +} + +using_sanitizer = false diff --git a/build/gn/fangtian.gni b/build/gn/fangtian.gni new file mode 100755 index 0000000000000000000000000000000000000000..f4b75d512ca369d8e48fbe772042745b7e6f0df9 --- /dev/null +++ b/build/gn/fangtian.gni @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/gn/templates/build_targets.gni") + +declare_args() { + is_fangtian_build = true + +} + diff --git a/build/gn/templates/build_targets.gni b/build/gn/templates/build_targets.gni new file mode 100755 index 0000000000000000000000000000000000000000..6e453a1b77d104adc891045b384272fda8de231b --- /dev/null +++ b/build/gn/templates/build_targets.gni @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/gn/templates/ft_executable.gni") +import("//build/gn/templates/ft_shared_library.gni") +import("//build/gn/templates/ft_source_set.gni") +import("//build/gn/templates/ft_static_library.gni") diff --git a/build/gn/templates/ft_executable.gni b/build/gn/templates/ft_executable.gni new file mode 100755 index 0000000000000000000000000000000000000000..37257f732e65a54850f1de16da1ae966bf7dfc4f --- /dev/null +++ b/build/gn/templates/ft_executable.gni @@ -0,0 +1,92 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# wrapper of target `executable()` +# +# parameters: +# - subsystem_name: subsystem name, default is "common" +# - part_name: part name, default is subsystem_name +# - configs: configs to add +# - remove_configs: configs to remove +# - use_exceptions: use exceptions, default is false +# - use_rtti: use rtti, default is false +template("ft_executable") { + if (defined(invoker.output_dir)) { + output_dir = invoker.output_dir + } else { + # Handle subsystem & part_name + if (defined(invoker.subsystem_name) && defined(invoker.part_name)) { + subsystem_name = invoker.subsystem_name + part_name = invoker.part_name + } else if (defined(invoker.part_name)) { + assert("false", "Please set 'subsystem_name' for 'part_name'") + } else if (defined(invoker.subsystem_name)) { + subsystem_name = invoker.subsystem_name + part_name = subsystem_name + } else { + subsystem_name = "common" + part_name = subsystem_name + } + assert(subsystem_name != "", + "[GN ERROR] Internal error, please contact maintainer.") + assert(part_name != "", + "[GN ERROR] Internal error, please contact maintainer.") + + # Change output dir + # TODO: handle ft_test + output_dir = "${root_out_dir}/${subsystem_name}/${part_name}" + } + + # Call `executable()` + executable("${target_name}") { + forward_variables_from(invoker, + "*", + [ + # variable_to_not_forward_list + "configs", + "remove_configs", + #"static_link", + #"external_deps", + #"install_images", + #"module_install_dir", + #"relative_install_dir", + #"symlink_target_name", + "output_dir", + #"install_enable", + #"version_script", + #"license_file", + #"license_as_sources", + "use_exceptions", + "use_rtti", + ]) + if (defined(invoker.configs)) { + configs += invoker.configs + } + + if (defined(invoker.remove_configs)) { + configs -= invoker.remove_configs + } + + if (defined(invoker.use_exceptions) && invoker.use_exceptions) { + configs += [ "//build/gn/configs/compiler:exceptions" ] + configs -= [ "//build/gn/configs/compiler:no_exceptions" ] + } + + if (defined(invoker.use_rtti) && invoker.use_rtti) { + configs += [ "//build/gn/configs/compiler:rtti" ] + configs -= [ "//build/gn/configs/compiler:no_rtti" ] + } + } + + output_dir = output_dir +} diff --git a/build/gn/templates/ft_shared_library.gni b/build/gn/templates/ft_shared_library.gni new file mode 100755 index 0000000000000000000000000000000000000000..b5b8977b2de7ec4e4cae3a907c54fe2ec5be30cf --- /dev/null +++ b/build/gn/templates/ft_shared_library.gni @@ -0,0 +1,85 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# wrapper of target `shared_library()` +# +# parameters: +# - subsystem_name: subsystem name, default is "common" +# - part_name: part name, default is subsystem_name +# - configs: configs to add +# - remove_configs: configs to remove +# - use_exceptions: use exceptions, default is false +# - use_rtti: use rtti, default is false +template("ft_shared_library") { + # Handle subsystem & part_name + if (defined(invoker.subsystem_name) && defined(invoker.part_name)) { + subsystem_name = invoker.subsystem_name + part_name = invoker.part_name + } else if (defined(invoker.part_name)) { + assert("false", "Please set 'subsystem_name' for 'part_name'") + } else if (defined(invoker.subsystem_name)) { + subsystem_name = invoker.subsystem_name + part_name = subsystem_name + } else { + subsystem_name = "common" + part_name = subsystem_name + } + assert(subsystem_name != "", + "[GN ERROR] Internal error, please contact maintainer.") + assert(part_name != "", + "[GN ERROR] Internal error, please contact maintainer.") + + # Change output dir + output_dir = "${root_out_dir}/${subsystem_name}/${part_name}" + + # Call `shared_library()` + shared_library("${target_name}") { + forward_variables_from(invoker, + "*", + [ + # variable_to_not_forward_list + "configs", + "remove_configs", + #"no_default_deps", + #"external_deps", + #"install_images", + #"module_install_dir", + #"relative_install_dir", + #"symlink_target_name", + "output_dir", + #"install_enable", + #"version_script", + #"license_file", + #"license_as_sources", + "use_exceptions", + "use_rtti", + #"stl", + ]) + if (defined(invoker.configs)) { + configs += invoker.configs + } + if (defined(invoker.remove_configs)) { + configs -= invoker.remove_configs + } + + if (defined(invoker.use_exceptions) && invoker.use_exceptions) { + configs += [ "//build/gn/configs/compiler:exceptions" ] + configs -= [ "//build/gn/configs/compiler:no_exceptions" ] + } + + if (defined(invoker.use_rtti) && invoker.use_rtti) { + configs += [ "//build/gn/configs/compiler:rtti" ] + configs -= [ "//build/gn/configs/compiler:no_rtti" ] + } + } +} diff --git a/build/gn/templates/ft_source_set.gni b/build/gn/templates/ft_source_set.gni new file mode 100755 index 0000000000000000000000000000000000000000..e97beabf2ef81af542458cc763debfa837d3aa9a --- /dev/null +++ b/build/gn/templates/ft_source_set.gni @@ -0,0 +1,70 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# wrapper of target `source_set()` +# +# parameters: +# - subsystem_name: subsystem name, default is "common" +# - part_name: part name, default is subsystem_name +# - configs: configs to add +# - remove_configs: configs to remove +# - use_exceptions: use exceptions, default is false +# - use_rtti: use rtti, default is false +template("ft_source_set") { + # Handle subsystem & part_name + if (defined(invoker.subsystem_name) && defined(invoker.part_name)) { + part_name = invoker.part_name + } else if (defined(invoker.part_name)) { + part_name = invoker.part_name + } else if (defined(invoker.subsystem_name)) { + part_name = invoker.subsystem_name + } else { + part_name = "common" + } + assert(part_name != "", + "[GN ERROR] Internal error, please contact maintainer.") + + # Call `source_set()` + source_set("${target_name}") { + forward_variables_from(invoker, + "*", + [ + # variable_to_not_forward_list + "configs", + "remove_configs", + #"no_default_deps", + #"external_deps", + #"license_file", + #"license_as_sources", + "use_exceptions", + "use_rtti", + "subsystem_name", + ]) + if (defined(invoker.configs)) { + configs += invoker.configs + } + if (defined(invoker.remove_configs)) { + configs -= invoker.remove_configs + } + + if (defined(invoker.use_exceptions) && invoker.use_exceptions) { + configs += [ "//build/gn/configs/compiler:exceptions" ] + configs -= [ "//build/gn/configs/compiler:no_exceptions" ] + } + + if (defined(invoker.use_rtti) && invoker.use_rtti) { + configs += [ "//build/gn/configs/compiler:rtti" ] + configs -= [ "//build/gn/configs/compiler:no_rtti" ] + } + } +} diff --git a/build/gn/templates/ft_static_library.gni b/build/gn/templates/ft_static_library.gni new file mode 100755 index 0000000000000000000000000000000000000000..2451ec6e7de18c6112042fdc5c87ed14b7a0a7a8 --- /dev/null +++ b/build/gn/templates/ft_static_library.gni @@ -0,0 +1,70 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# wrapper of target `static_library()` +# +# parameters: +# - subsystem_name: subsystem name, default is "common" +# - part_name: part name, default is subsystem_name +# - configs: configs to add +# - remove_configs: configs to remove +# - use_exceptions: use exceptions, default is false +# - use_rtti: use rtti, default is false +template("ft_static_library") { + # Handle subsystem & part_name + if (defined(invoker.subsystem_name) && defined(invoker.part_name)) { + part_name = invoker.part_name + } else if (defined(invoker.part_name)) { + part_name = invoker.part_name + } else if (defined(invoker.subsystem_name)) { + part_name = invoker.subsystem_name + } else { + part_name = "common" + } + assert(part_name != "", + "[GN ERROR] Internal error, please contact maintainer.") + + # Call `static_library()` + static_library("${target_name}") { + forward_variables_from(invoker, + "*", + [ + # variable_to_not_forward_list + "configs", + "remove_configs", + #"no_default_deps", + #"external_deps", + #"license_file", + #"license_as_sources", + "use_exceptions", + "use_rtti", + "subsystem_name", + ]) + if (defined(invoker.configs)) { + configs += invoker.configs + } + if (defined(invoker.remove_configs)) { + configs -= invoker.remove_configs + } + + if (defined(invoker.use_exceptions) && invoker.use_exceptions) { + configs += [ "//build/gn/configs/compiler:exceptions" ] + configs -= [ "//build/gn/configs/compiler:no_exceptions" ] + } + + if (defined(invoker.use_rtti) && invoker.use_rtti) { + configs += [ "//build/gn/configs/compiler:rtti" ] + configs -= [ "//build/gn/configs/compiler:no_rtti" ] + } + } +} diff --git a/build/gn/toolchain/cc_wrapper.gni b/build/gn/toolchain/cc_wrapper.gni new file mode 100755 index 0000000000000000000000000000000000000000..0c682700778df6302a05f6bdf1a7edc0a3ca5d69 --- /dev/null +++ b/build/gn/toolchain/cc_wrapper.gni @@ -0,0 +1,51 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Defines the configuration of cc wrapper +# ccache: a c/c++ compiler cache which can greatly reduce recompilation times. +# icecc, distcc: it takes compile jobs from a build and distributes them among +# remote machines allowing a parallel build. +# +# TIPS +# +# 1) ccache +# Set clang_use_chrome_plugins=false if using ccache 3.1.9 or earlier, since +# these versions don't support -Xclang. (3.1.10 and later will silently +# ignore -Xclang, so it doesn't matter if you disable clang_use_chrome_plugins +# or not). +# +# Use ccache 3.2 or later to avoid clang unused argument warnings: +# https://bugzilla.samba.org/show_bug.cgi?id=8118 +# +# To avoid -Wparentheses-equality clang warnings, at some cost in terms of +# speed, you can do: +# export CCACHE_CPP2=yes +# +# 2) icecc +# Set clang_use_chrome_plugins=false because icecc cannot distribute custom +# clang libraries. +# +# To use icecc and ccache together, set cc_wrapper = "ccache" with +# export CCACHE_PREFIX=icecc + +_cc_wrapper = "" +_ccache_exec = getenv("CCACHE_EXEC") +_use_ccache = getenv("USE_CCACHE") +if (_use_ccache == "1" && _ccache_exec != "") { + _cc_wrapper = rebase_path(_ccache_exec) +} + +declare_args() { + # Set to "ccache", "icecc" or "distcc". Probably doesn't work on windows. + cc_wrapper = _cc_wrapper +} diff --git a/build/gn/toolchain/linux/BUILD.gn b/build/gn/toolchain/linux/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..124a899e47a805b4b53d205443165ec7c00fd63f --- /dev/null +++ b/build/gn/toolchain/linux/BUILD.gn @@ -0,0 +1,54 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A toolchain is a set of commands and build flags used to compile the source +# code. The toolchain() function defines these commands. + +import("//build/gn/toolchain/toolchain.gni") + +clang_toolchain("clang_x64") { + toolchain_args = { + current_cpu = "x64" + current_os = "linux" + } + + if (use_musl) { + if (use_musl_oh) { + # TODO: musl_oh + assert(false, "[GN ERROR] Unsupport musl_oh for toolchain currently.") + } + + libc_dir = rebase_path("/usr/musl/lib", root_build_dir) + # gcc_dir = rebase_path("/usr/lib/gcc/x86_64-linux-gnu/10.3.1", root_build_dir) + clang_lib_dir = rebase_path("/usr/lib64/clang/12.0.1/lib", root_build_dir) + + # CRT files + common_prefix = "${libc_dir}/crti.o" # _init and _fini + common_prefix += " ${clang_lib_dir}/clang_rt.crtbegin-x86_64.o" # impl _init for C++ + # common_prefix += " ${gcc_dir}/crtbeginS.o" + + common_suffix = "${libc_dir}/crtn.o" # _init and _fini + common_suffix += " ${clang_lib_dir}/clang_rt.crtend-x86_64.o" # impl _fini for C++ + # common_suffix += " ${gcc_dir}/crtendS.o" + + link_libs_section_prefix = "${libc_dir}/Scrt1.o" # _start, for PIEs + link_libs_section_prefix += " " + common_prefix + + link_libs_section_suffix = common_suffix + link_libs_section_suffix += " -Wl,-dynamic-linker /lib/ld-musl.so.1" # dynamic linker + + solink_libs_section_prefix = common_prefix + + solink_libs_section_suffix = common_suffix + } +} diff --git a/build/gn/toolchain/toolchain.gni b/build/gn/toolchain/toolchain.gni new file mode 100755 index 0000000000000000000000000000000000000000..06148aef7f20518a4bb5b4504b0e6e17279617da --- /dev/null +++ b/build/gn/toolchain/toolchain.gni @@ -0,0 +1,328 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Toolchain-related configuration that may be needed outside the context of the +# toolchain() rules themselves. + +import("cc_wrapper.gni") + +declare_args() { + share_ccache = "" +} + +# This template defines a toolchain for something that works with clang +# +# Optional parameters that control the tools: +# +# - cc +# - cxx +# - ld +# - asm +# - ar +# +# - link_libs_section_prefix +# - link_libs_section_suffix +# The contents of these strings, if specified, will be placed around +# the libs section of the linker line. It allows one to inject libraries +# at the beginning and end for all targets in a toolchain. +# +# - solink_libs_section_prefix +# - solink_libs_section_suffix +# Same as libs_section_{pre,post}fix except used for solink instead of link. +# +# - extra_cflags +# Extra flags to be appended when compiling C files (but not C++ files). +# - extra_cxxflags +# Extra flags to be appended when compiling C++ files (but not C files). +# - extra_ccxxflags +# Extra flags to be appended when compiling both C and C++ files. +# - extra_asmflags +# Extra flags to be appended when compiling assembly. +# - extra_ldflags +# Extra flags to be appended when linking +# +# TODO: +# - readelf +# - nm +# - strip + +template("clang_toolchain") { + # Check args + toolchain(target_name) { + assert(defined(invoker.toolchain_args), + "[GN ERROR] Toolchains must declare toolchain_args") + + toolchain_args = { + forward_variables_from(invoker.toolchain_args, "*") + } + assert(defined(toolchain_args.current_cpu), + "[GN ERROR] toolchain_args must specify a current_cpu") + assert(defined(toolchain_args.current_os), + "[GN ERROR] toolchain_args must specify a current_os") + + # ccache + if (defined(toolchain_args.cc_wrapper)) { + toolchain_cc_wrapper = toolchain_args.cc_wrapper + } else { + toolchain_cc_wrapper = cc_wrapper + } + + if (share_ccache != "") { + compiler_prefix = "CCACHE_DIR=" + share_ccache + + " CCACHE_NOHASHDIR=1 ${toolchain_cc_wrapper} " + } else { + compiler_prefix = "${toolchain_cc_wrapper} " + } + + # Set compiling/linking tools and extra values. + if (defined(invoker.cc)) { + cc = compiler_prefix + invoker.cc + } else { + cc = compiler_prefix + "clang" + } + + if (defined(invoker.cxx)) { + cxx = compiler_prefix + invoker.cxx + } else { + cxx = compiler_prefix + "clang++" + } + + if (defined(invoker.ld)) { + ld = invoker.ld + } else { + ld = cxx + } + + if (!defined(asm)) { + if (defined(invoker.asm)) { + asm = invoker.asm + } else { + asm = cc + } + } + + if (defined(invoker.ar)) { + ar = invoker.ar + } else { + ar = "llvm-ar" + } + + # if (defined(invoker.readelf)) { + # readelf = invoker.readelf + # } else { + # readelf = "llvm-readobj" + # } + + # TODO + # if (defined(invoker.nm)) { + # nm = invoker.nm + # } else { + # nm = "llvm-nm" + # } + + # Bring these into our scope for string interpolation with default values. + if (defined(invoker.link_libs_section_prefix)) { + link_libs_section_prefix = invoker.link_libs_section_prefix + } else { + link_libs_section_prefix = "" + } + + if (defined(invoker.link_libs_section_suffix)) { + link_libs_section_suffix = invoker.link_libs_section_suffix + } else { + link_libs_section_suffix = "" + } + + if (defined(invoker.solink_libs_section_prefix)) { + solink_libs_section_prefix = invoker.solink_libs_section_prefix + } else { + solink_libs_section_prefix = "" + } + + if (defined(invoker.solink_libs_section_suffix)) { + solink_libs_section_suffix = invoker.solink_libs_section_suffix + } else { + solink_libs_section_suffix = "" + } + + if (defined(invoker.extra_cflags) && invoker.extra_cflags != "") { + extra_cflags = " " + invoker.extra_cflags + } else { + extra_cflags = "" + } + + if (defined(invoker.extra_cxxflags) && invoker.extra_cxxflags != "") { + extra_cxxflags = " " + invoker.extra_cxxflags + } else { + extra_cxxflags = "" + } + + if (defined(invoker.extra_ccxxflags) && invoker.extra_ccxxflags != "") { + extra_ccxxflags = " " + invoker.extra_ccxxflags + } else { + extra_ccxxflags = "" + } + + if (defined(invoker.extra_asmflags) && invoker.extra_asmflags != "") { + extra_asmflags = " " + invoker.extra_asmflags + } else { + extra_asmflags = "" + } + + if (defined(invoker.extra_ldflags) && invoker.extra_ldflags != "") { + extra_ldflags = " " + invoker.extra_ldflags + } else { + extra_ldflags = "" + } + + # These library switches can apply to all tools below. + lib_switch = "-l" + lib_dir_switch = "-L" + + # Object files go in this directory. + object_subdir = "{{source_out_dir}}/{{label_name}}" + + # Compiler tools: C Compiler + tool("cc") { + depfile = "{{output}}.d" + depsformat = "gcc" + # command explain: + # * -MD : Write a depfile containing user and system headers + # * -MF : Write depfile output from -MMD, -MD, -MM, or -M to + # * -c : Only run preprocess, compile, and assemble steps + # * -o : Write output to + command = "$cc -MD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}${extra_ccxxflags}${extra_cflags} -c {{source}} -o {{output}}" + + description = "CC {{output}}" + + outputs = [ "$object_subdir/{{source_name_part}}.o" ] + } + + # Compiler tools: C++ compiler + tool("cxx") { + depfile = "{{output}}.d" + depsformat = "gcc" + # command explain: + # * -MD : Write a depfile containing user and system headers + # * -MF : Write depfile output from -MMD, -MD, -MM, or -M to + # * -c : Only run preprocess, compile, and assemble steps + # * -o : Write output to + command = "$cxx -MD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_ccxxflags}${extra_cxxflags} -c {{source}} -o {{output}}" + + description = "CXX {{output}}" + + outputs = [ "$object_subdir/{{source_name_part}}.o" ] + } + + # Compiler tools: Assembler + tool("asm") { + # For GCC we can just use the C compiler to compile assembly. + depfile = "{{output}}.d" + depsformat = "gcc" + command = "$asm -MD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}" + + description = "ASM {{output}}" + + outputs = [ "$object_subdir/{{source_name_part}}.o" ] + } + + # Linker tools: Linker for static libraries (archives) + tool("alink") { + # Name of the response file. If empty, no response file will be used. + rspfile = "{{output}}.rsp" + # The contents to be written to the response file. This may include all + # or part of the command to send to the tool which allows you to get + # around OS command-line length limits. + rspfile_content = "{{inputs}}" + + # command = "rm -f {{output}} && ar rcs {{output}} {{inputs}}" + command = "\"$ar\" -r -c -s -D {{output}} @\"$rspfile\"" + + description = "AR {{output}}" + + # Output files for actions and copy targets. + outputs = + [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ] + + # Default directory name for the output file relative to the root_build_dir. + # + # Shared libraries go in the target out directory by default so we can + # generate different targets with the same name and not have them collide. + default_output_dir = "{{target_out_dir}}" + + default_output_extension = ".a" + output_prefix = "lib" + } + + # Linker tools: Linker for shared libraries + tool("solink") { + soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". + sofile = "{{output_dir}}/$soname" + + # Name of the response file. If empty, no response file will be used. + rspfile = soname + ".rsp" + # The contents to be written to the response file. This may include all + # or part of the command to send to the tool which allows you to get + # around OS command-line length limits. + rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_suffix" + + command = + "$ld -shared {{ldflags}}${extra_ldflags} -o \"$sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\"" + + description = "SOLINK $soname" + + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + default_output_extension = ".so" + + # Default directory name for the output file relative to the root_build_dir. + # + # Use this for {{output_dir}} expansions unless a target manually overrides + # it (in which case {{output_dir}} will be what the target specifies). + default_output_dir = "{{root_out_dir}}" + + # Output files for actions and copy targets. + outputs = [ sofile ] + + link_output = sofile + depend_output = sofile + output_prefix = "lib" + } + + # Linker tools: Linker for executables + # TODO: strip & link wrapper + tool("link") { + # outfile = "{{target_output_name}}{{output_extension}}" + outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" + + # Name of the response file. If empty, no response file will be used. + rspfile = "${outfile}.rsp" + # The contents to be written to the response file. This may include all + # or part of the command to send to the tool which allows you to get + # around OS command-line length limits. + rspfile_content = "{{inputs}}" + + command = "$ld {{ldflags}}${extra_ldflags} -o ${outfile} ${link_libs_section_prefix} -Wl,--start-group @\"${rspfile}\" {{solibs}} {{libs}} -Wl,--end-group ${link_libs_section_suffix}" + + description = "LINK ${outfile}" + + # Default directory name for the output file relative to the root_build_dir. + default_output_dir = "{{root_out_dir}}" + outputs = [ outfile ] + } + + # Other tools: Tool for creating stamp files + tool("stamp") { + command = "touch {{output}}" + description = "STAMP {{output}}" + } + + # Other tools: Tool to copy files. + tool("copy") { + command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})" + description = "COPY {{source}} {{output}}" + } + } +} diff --git a/build/prebuild.sh b/build/prebuild.sh new file mode 100755 index 0000000000000000000000000000000000000000..9b6d36cbdd8ccd20ecf1b4ae8e1b5b38e1f2604f --- /dev/null +++ b/build/prebuild.sh @@ -0,0 +1,62 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +# ============================================================================= +# Python +# ============================================================================= +# +# check python3 in current system. +PYTHON_REQUIRED_VERSION="3.9.2" + +echo -e "\e[36m[-] Prepare python3 packages...\e[0m" + +# Check if python3 is installed +if ! command -v python3 &> /dev/null; then + echo "python3 is not installed" + exit 1 +fi +if ! command -v pip3 &> /dev/null; then + echo "pip3 is not installed" + exit 1 +fi + +# Check python version +PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}') + +# Compare the versions +if [ "$(printf '%s\n' "$PYTHON_REQUIRED_VERSION" "$PYTHON_VERSION" | sort -V | head -n1)" = "$PYTHON_REQUIRED_VERSION" ]; then + echo "The python3 version is $PYTHON_VERSION" +else + echo "The python3 version is less than $PYTHON_REQUIRED_VERSION" +fi + +# Install python packages +SCRIPT_DIR=$(cd $(dirname $0);pwd) +PROJECT_DIR=$(dirname ${SCRIPT_DIR}) + +pip3 install -r ${SCRIPT_DIR}/configs/requirements.txt + +# ============================================================================= +# System Packages +# ============================================================================= +# +# check system packages in current system by calling builder.py + +echo -e "\e[36m[-] Prepare system packages...\e[0m" + +# Check & Install required system packages +python3 ${PROJECT_DIR}/build/builder.py check --install-packages $* + +echo -e "\033[32m[*] Pre-build Done. You can exec 'build.sh' now.\033[0m" diff --git a/prebuilts/build-tools/linux-x64/bin/gn b/prebuilts/build-tools/linux-x64/bin/gn new file mode 100755 index 0000000000000000000000000000000000000000..f6d02b952d1ef8d7da26b8a9d4a5b59634a58de8 Binary files /dev/null and b/prebuilts/build-tools/linux-x64/bin/gn differ diff --git a/prebuilts/build-tools/linux-x64/bin/ninja b/prebuilts/build-tools/linux-x64/bin/ninja new file mode 100755 index 0000000000000000000000000000000000000000..3aaf2a9dc013ec0faae9c41f738482150cca841d Binary files /dev/null and b/prebuilts/build-tools/linux-x64/bin/ninja differ diff --git a/third_party/bounds_checking_function/BUILD.gn b/third_party/bounds_checking_function/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..062248828559946e1a21c29c8459ac553fc2cb59 --- /dev/null +++ b/third_party/bounds_checking_function/BUILD.gn @@ -0,0 +1,81 @@ +# +# Copyright (c) 2020 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +if (defined(ohos_lite)) { + import("//build/lite/config/component/lite_component.gni") +} else { + import("//build/ohos.gni") +} +import("libsec_src.gni") + +config("libsec_public_config") { + include_dirs = [ "include" ] +} + +if (defined(ohos_lite)) { + # When the kernel is liteos_m, use //kernel/liteos_m/kal/libsec/BUILD.gn to compile. + if (ohos_kernel_type == "liteos_m") { + group("libsec_static") { + } + } else { + lite_library("libsec_static") { + target_type = "static_library" + sources = libsec_sources + public_configs = [ ":libsec_public_config" ] + } + } + lite_library("libsec_shared") { + target_type = "shared_library" + sources = libsec_sources + public_configs = [ ":libsec_public_config" ] + } + group("sec_shared") { + deps = [ ":libsec_shared" ] + } +} else { + ohos_static_library("libsec_static") { + sources = libsec_sources + all_dependent_configs = [ ":libsec_public_config" ] + cflags = [ + "-D_INC_STRING_S", + "-D_INC_WCHAR_S", + "-D_SECIMP=//", + "-D_STDIO_S_DEFINED", + "-D_INC_STDIO_S", + "-D_INC_STDLIB_S", + "-D_INC_MEMORY_S", + ] + part_name = "bounds_checking_function" + subsystem_name = "thirdparty" + } + ohos_shared_library("libsec_shared") { + sources = libsec_sources + all_dependent_configs = [ ":libsec_public_config" ] + cflags = [ + "-D_INC_STRING_S", + "-D_INC_WCHAR_S", + "-D_SECIMP=//", + "-D_STDIO_S_DEFINED", + "-D_INC_STDIO_S", + "-D_INC_STDLIB_S", + "-D_INC_MEMORY_S", + ] + part_name = "bounds_checking_function" + subsystem_name = "thirdparty" + install_images = [ + "system", + "updater", + ] + } +} diff --git a/third_party/bounds_checking_function/LICENSE b/third_party/bounds_checking_function/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..42f2a83670c666eb8a37c96c31eb0e7eb019d8a0 --- /dev/null +++ b/third_party/bounds_checking_function/LICENSE @@ -0,0 +1,124 @@ +木兰宽松许可证, 第2版 + +2020年1月 http://license.coscl.org.cn/MulanPSL2 + +您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: + +0. 定义 + +“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 + +“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + +“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + +“法人实体” 是指提交贡献的机构及其“关联实体”。 + +“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + +1. 授予版权许可 + +每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 + +2. 授予专利许可 + +每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 + +3. 无商标许可 + +“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 + +4. 分发限制 + +您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + +5. 免责声明与责任限制 + +“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 + +6. 语言 + +“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 + +条款结束 + +如何将木兰宽松许可证,第2版,应用到您的软件 + +如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: + +1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + +2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + +3, 请将如下声明文本放入每个源文件的头部注释中。 + +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +Mulan Permissive Software License,Version 2 +Mulan Permissive Software License,Version 2 (Mulan PSL v2) + +January 2020 http://license.coscl.org.cn/MulanPSL2 + +Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + +0. Definition + +Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + +Contribution means the copyrightable work licensed by a particular Contributor under this License. + +Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + +Legal Entity means the entity making a Contribution and all its Affiliates. + +Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, 'control' means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + +1. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + +2. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + +3. No Trademark License + +No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4. + +4. Distribution Restriction + +You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + +5. Disclaimer of Warranty and Limitation of Liability + +THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT'S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +6. Language + +THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + +END OF THE TERMS AND CONDITIONS + +How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + +To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + +Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; +Create a file named "LICENSE" which contains the whole context of this License in the first directory of your software package; +Attach the statement to the appropriate annotated syntax at the beginning of each source file. +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. \ No newline at end of file diff --git a/third_party/bounds_checking_function/OAT.xml b/third_party/bounds_checking_function/OAT.xml new file mode 100644 index 0000000000000000000000000000000000000000..d7f574a0ea1801d7ce8893e5ab0041c417d7706f --- /dev/null +++ b/third_party/bounds_checking_function/OAT.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + diff --git a/third_party/bounds_checking_function/README.OpenSource b/third_party/bounds_checking_function/README.OpenSource new file mode 100644 index 0000000000000000000000000000000000000000..9c3a2bb3234eb754ec79ecb9b5db2631cdd892d3 --- /dev/null +++ b/third_party/bounds_checking_function/README.OpenSource @@ -0,0 +1,11 @@ +[ + { + "Name" : "bounds_checking_function", + "License" : "Mulan Permissive Software License,Version 2", + "License File" : "LICENSE", + "Version Number" : "v1.1.10", + "Owner" : "jianghan2@huawei.com", + "Upstream URL" : "https://gitee.com/openeuler/libboundscheck", + "Description" : "following the standard of C11 Annex K (bound-checking interfaces), functions of the common memory/string operation classes, such as memcpy_s, strcpy_s, are selected and implemented." + } +] diff --git a/third_party/bounds_checking_function/README.en.md b/third_party/bounds_checking_function/README.en.md new file mode 100644 index 0000000000000000000000000000000000000000..c905d57e51b80b9109123ed33c48157616e7eae2 --- /dev/null +++ b/third_party/bounds_checking_function/README.en.md @@ -0,0 +1,9 @@ +# bounds_checking_function + +#### Description + +- following the standard of C11 Annex K (bound-checking interfaces), functions of the common memory/string operation classes, such as memcpy_s, strcpy_s, are selected and implemented. + +- other standard functions in C11 Annex K will be analyzed in the future and implemented in this organization if necessary. + +- handles the release, update, and maintenance of bounds_checking_function. diff --git a/third_party/bounds_checking_function/README.md b/third_party/bounds_checking_function/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4cb88ea74afd61d685d37206a940c8b0979631c3 --- /dev/null +++ b/third_party/bounds_checking_function/README.md @@ -0,0 +1,6 @@ +# bounds_checking_function + +#### 介绍 +- 遵循C11 Annex K (Bounds-checking interfaces)的标准,选取并实现了常见的内存/字符串操作类的函数,如memcpy_s、strcpy_s等函数。 +- 未来将分析C11 Annex K中的其他标准函数,如果有必要,将在该组织中实现。 +- 处理边界检查函数的版本发布、更新以及维护。 diff --git a/third_party/bounds_checking_function/bundle.json b/third_party/bounds_checking_function/bundle.json new file mode 100644 index 0000000000000000000000000000000000000000..16cd84f017277f7291ebd6f19a0275f94a2e7008 --- /dev/null +++ b/third_party/bounds_checking_function/bundle.json @@ -0,0 +1,41 @@ +{ + "name": "@ohos/bounds_checking_function", + "description": "following the standard of C11 Annex K (bound-checking interfaces), functions of the common memory/string operation classes, such as memcpy_s, strcpy_s, are selected and implemented.", + "version": "3.1", + "license": "MulanPSL-2.0", + "publishAs": "code-segment", + "segment": { + "destPath": "third_party/bounds_checking_function" + }, + "dirs": {}, + "scripts": {}, + "component": { + "name": "bounds_checking_function", + "subsystem": "thirdparty", + "syscap": [], + "features": [], + "adapted_system_type": [ "mini", "small", "standard" ], + "rom": "", + "ram": "", + "deps": { + "components": [], + "third_party": [] + }, + "build": { + "sub_component": [ "//third_party/bounds_checking_function:libsec_shared" ], + "inner_kits": [ + { + "name": "//third_party/bounds_checking_function:libsec_shared", + "header": { + "header_files": [ + "securec.h", + "securectype.h" + ], + "header_base": "//third_party/bounds_checking_function/include" + } + } + ], + "test": [] + } + } +} \ No newline at end of file diff --git a/third_party/bounds_checking_function/ft_build/BUILD.gn b/third_party/bounds_checking_function/ft_build/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..b2a38b08d1ffc0922d42c6f09063181e1838a306 --- /dev/null +++ b/third_party/bounds_checking_function/ft_build/BUILD.gn @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Huawei Technologies Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import("//build/gn/fangtian.gni") +import("../libsec_src.gni") + +config("libsec_public_config") { + include_dirs = [ "../include" ] +} + +ft_static_library("libsec_static") { + sources = libsec_sources + all_dependent_configs = [ ":libsec_public_config" ] + cflags = [ + "-D_INC_STRING_S", + "-D_INC_WCHAR_S", + "-D_SECIMP=//", + "-D_STDIO_S_DEFINED", + "-D_INC_STDIO_S", + "-D_INC_STDLIB_S", + "-D_INC_MEMORY_S", + ] + + part_name = "bounds_checking_function" + subsystem_name = "thirdparty" +} diff --git a/third_party/bounds_checking_function/include/securec.h b/third_party/bounds_checking_function/include/securec.h new file mode 100644 index 0000000000000000000000000000000000000000..23bac2c4d83fd6abbeb066da48d076020a44f160 --- /dev/null +++ b/third_party/bounds_checking_function/include/securec.h @@ -0,0 +1,623 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: The user of this secure c library should include this header file in you source code. + * This header file declare all supported API prototype of the library, + * such as memcpy_s, strcpy_s, wcscpy_s,strcat_s, strncat_s, sprintf_s, scanf_s, and so on. + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SECUREC_H_5D13A042_DC3F_4ED9_A8D1_882811274C27 +#define SECUREC_H_5D13A042_DC3F_4ED9_A8D1_882811274C27 + +#include "securectype.h" +#ifndef SECUREC_HAVE_STDARG_H +#define SECUREC_HAVE_STDARG_H 1 +#endif + +#if SECUREC_HAVE_STDARG_H +#include +#endif + +#ifndef SECUREC_HAVE_ERRNO_H +#define SECUREC_HAVE_ERRNO_H 1 +#endif + +/* EINVAL ERANGE may defined in errno.h */ +#if SECUREC_HAVE_ERRNO_H +#if SECUREC_IN_KERNEL +#include +#else +#include +#endif +#endif + +/* Define error code */ +#if defined(SECUREC_NEED_ERRNO_TYPE) || !defined(__STDC_WANT_LIB_EXT1__) || \ + (defined(__STDC_WANT_LIB_EXT1__) && (!__STDC_WANT_LIB_EXT1__)) +#ifndef SECUREC_DEFINED_ERRNO_TYPE +#define SECUREC_DEFINED_ERRNO_TYPE +/* Just check whether macrodefinition exists. */ +#ifndef errno_t +typedef int errno_t; +#endif +#endif +#endif + +/* Success */ +#ifndef EOK +#define EOK 0 +#endif + +#ifndef EINVAL +/* The src buffer is not correct and destination buffer cant not be reset */ +#define EINVAL 22 +#endif + +#ifndef EINVAL_AND_RESET +/* Once the error is detected, the dest buffer must be reseted! Value is 22 or 128 */ +#define EINVAL_AND_RESET 150 +#endif + +#ifndef ERANGE +/* The destination buffer is not long enough and destination buffer can not be reset */ +#define ERANGE 34 +#endif + +#ifndef ERANGE_AND_RESET +/* Once the error is detected, the dest buffer must be reseted! Value is 34 or 128 */ +#define ERANGE_AND_RESET 162 +#endif + +#ifndef EOVERLAP_AND_RESET +/* Once the buffer overlap is detected, the dest buffer must be reseted! Value is 54 or 128 */ +#define EOVERLAP_AND_RESET 182 +#endif + +/* If you need export the function of this library in Win32 dll, use __declspec(dllexport) */ +#ifndef SECUREC_API +#if defined(SECUREC_DLL_EXPORT) +#define SECUREC_API __declspec(dllexport) +#elif defined(SECUREC_DLL_IMPORT) +#define SECUREC_API __declspec(dllimport) +#else +/* + * Standardized function declaration. If a security function is declared in the your code, + * it may cause a compilation alarm,Please delete the security function you declared. + * Adding extern under windows will cause the system to have inline functions to expand, + * so do not add the extern in default + */ +#if defined(_MSC_VER) +#define SECUREC_API +#else +#define SECUREC_API extern +#endif +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif +#if SECUREC_ENABLE_MEMSET + /* + * Description: The memset_s function copies the value of c (converted to an unsigned char) into each of + * the first count characters of the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: c - the value to be copied + * Parameter: count - copies count bytes of value to dest + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t memset_s(void *dest, size_t destMax, int c, size_t count); +#endif + +#ifndef SECUREC_ONLY_DECLARE_MEMSET +#define SECUREC_ONLY_DECLARE_MEMSET 0 +#endif + +#if !SECUREC_ONLY_DECLARE_MEMSET + +#if SECUREC_ENABLE_MEMMOVE + /* + * Description: The memmove_s function copies n characters from the object pointed to by src + * into the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: src - source address + * Parameter: count - copies count bytes from the src + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t memmove_s(void *dest, size_t destMax, const void *src, size_t count); +#endif + +#if SECUREC_ENABLE_MEMCPY + /* + * Description: The memcpy_s function copies n characters from the object pointed to + * by src into the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: src - source address + * Parameter: count - copies count bytes from the src + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count); +#endif + +#if SECUREC_ENABLE_STRCPY + /* + * Description: The strcpy_s function copies the string pointed to by strSrc (including + * the terminating null character) into the array pointed to by strDest + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null character) + * Parameter: strSrc - source address + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc); +#endif + +#if SECUREC_ENABLE_STRNCPY + /* + * Description: The strncpy_s function copies not more than n successive characters (not including + * the terminating null character) from the array pointed to by strSrc to the array pointed to by strDest. + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null character) + * Parameter: strSrc - source address + * Parameter: count - copies count characters from the src + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count); +#endif + +#if SECUREC_ENABLE_STRCAT + /* + * Description: The strcat_s function appends a copy of the string pointed to by strSrc (including + * the terminating null character) to the end of the string pointed to by strDest. + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null wide character) + * Parameter: strSrc - source address + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t strcat_s(char *strDest, size_t destMax, const char *strSrc); +#endif + +#if SECUREC_ENABLE_STRNCAT + /* + * Description: The strncat_s function appends not more than n successive characters (not including + * the terminating null character) + * from the array pointed to by strSrc to the end of the string pointed to by strDest. + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null character) + * Parameter: strSrc - source address + * Parameter: count - copies count characters from the src + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count); +#endif + +#if SECUREC_ENABLE_VSPRINTF + /* + * Description: The vsprintf_s function is equivalent to the vsprintf function except for the parameter destMax + * and the explicit runtime-constraints violation + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null wide characte) + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1. + */ + SECUREC_API int vsprintf_s(char *strDest, size_t destMax, const char *format, + va_list argList) SECUREC_ATTRIBUTE(3, 0); +#endif + +#if SECUREC_ENABLE_SPRINTF + /* + * Description: The sprintf_s function is equivalent to the sprintf function except for the parameter destMax + * and the explicit runtime-constraints violation + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: format - fromat string + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1. + */ + SECUREC_API int sprintf_s(char *strDest, size_t destMax, const char *format, ...) SECUREC_ATTRIBUTE(3, 4); +#endif + +#if SECUREC_ENABLE_VSNPRINTF + /* + * Description: The vsnprintf_s function is equivalent to the vsnprintf function except for + * the parameter destMax/count and the explicit runtime-constraints violation + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: count - do not write more than count bytes to strDest(not including the terminating null byte '\0') + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1.Pay special attention to returning -1 when truncation occurs + */ + SECUREC_API int vsnprintf_s(char *strDest, size_t destMax, size_t count, const char *format, + va_list argList) SECUREC_ATTRIBUTE(4, 0); +#endif + +#if SECUREC_ENABLE_SNPRINTF + /* + * Description: The snprintf_s function is equivalent to the snprintf function except for + * the parameter destMax/count and the explicit runtime-constraints violation + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: count - do not write more than count bytes to strDest(not including the terminating null byte '\0') + * Parameter: format - fromat string + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1.Pay special attention to returning -1 when truncation occurs + */ + SECUREC_API int snprintf_s(char *strDest, size_t destMax, size_t count, const char *format, + ...) SECUREC_ATTRIBUTE(4, 5); +#endif + +#if SECUREC_SNPRINTF_TRUNCATED + /* + * Description: The vsnprintf_truncated_s function is equivalent to the vsnprintf_s function except + * no count parameter and return value + * Parameter: strDest - produce output according to a format ,write to the character string strDest + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1.Pay special attention to returning destMax - 1 when truncation occurs + */ + SECUREC_API int vsnprintf_truncated_s(char *strDest, size_t destMax, const char *format, + va_list argList) SECUREC_ATTRIBUTE(3, 0); + + /* + * Description: The snprintf_truncated_s function is equivalent to the snprintf_2 function except + * no count parameter and return value + * Parameter: strDest - produce output according to a format ,write to the character string strDest. + * Parameter: destMax - The maximum length of destination buffer(including the terminating null byte '\0') + * Parameter: format - fromat string + * Return: the number of characters printed(not including the terminating null byte '\0'), + * If an error occurred Return: -1.Pay special attention to returning destMax - 1 when truncation occurs + */ + SECUREC_API int snprintf_truncated_s(char *strDest, size_t destMax, + const char *format, ...) SECUREC_ATTRIBUTE(3, 4); +#endif + +#if SECUREC_ENABLE_SCANF + /* + * Description: The scanf_s function is equivalent to fscanf_s with the argument stdin + * interposed before the arguments to scanf_s + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int scanf_s(const char *format, ...); +#endif + +#if SECUREC_ENABLE_VSCANF + /* + * Description: The vscanf_s function is equivalent to scanf_s, with the variable argument list replaced by argList + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int vscanf_s(const char *format, va_list argList); +#endif + +#if SECUREC_ENABLE_SSCANF + /* + * Description: The sscanf_s function is equivalent to fscanf_s, except that input is obtained from a + * string (specified by the argument buffer) rather than from a stream + * Parameter: buffer - read character from buffer + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int sscanf_s(const char *buffer, const char *format, ...); +#endif + +#if SECUREC_ENABLE_VSSCANF + /* + * Description: The vsscanf_s function is equivalent to sscanf_s, with the variable argument list + * replaced by argList + * Parameter: buffer - read character from buffer + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int vsscanf_s(const char *buffer, const char *format, va_list argList); +#endif + +#if SECUREC_ENABLE_FSCANF + /* + * Description: The fscanf_s function is equivalent to fscanf except that the c, s, and [ conversion specifiers + * apply to a pair of arguments (unless assignment suppression is indicated by a*) + * Parameter: stream - stdio file stream + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int fscanf_s(FILE *stream, const char *format, ...); +#endif + +#if SECUREC_ENABLE_VFSCANF + /* + * Description: The vfscanf_s function is equivalent to fscanf_s, with the variable argument list + * replaced by argList + * Parameter: stream - stdio file stream + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int vfscanf_s(FILE *stream, const char *format, va_list argList); +#endif + +#if SECUREC_ENABLE_STRTOK + /* + * Description: The strtok_s function parses a string into a sequence of strToken, + * replace all characters in strToken string that match to strDelimit set with 0. + * On the first call to strtok_s the string to be parsed should be specified in strToken. + * In each subsequent call that should parse the same string, strToken should be NULL + * Parameter: strToken - the string to be delimited + * Parameter: strDelimit - specifies a set of characters that delimit the tokens in the parsed string + * Parameter: context - is a pointer to a char * variable that is used internally by strtok_s function + * Return: On the first call returns the address of the first non \0 character, otherwise NULL is returned. + * In subsequent calls, the strtoken is set to NULL, and the context set is the same as the previous call, + * return NULL if the *context string length is equal 0, otherwise return *context. + */ + SECUREC_API char *strtok_s(char *strToken, const char *strDelimit, char **context); +#endif + +#if SECUREC_ENABLE_GETS && !SECUREC_IN_KERNEL + /* + * Description: The gets_s function reads at most one less than the number of characters specified + * by destMax from the stream pointed to by stdin, into the array pointed to by buffer + * Parameter: buffer - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating null character) + * Return: buffer if there was no runtime-constraint violation,If an error occurred Return: NULL. + */ + SECUREC_API char *gets_s(char *buffer, size_t destMax); +#endif + +#if SECUREC_ENABLE_WCHAR_FUNC +#if SECUREC_ENABLE_MEMCPY + /* + * Description: The wmemcpy_s function copies n successive wide characters from the object pointed to + * by src into the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: src - source address + * Parameter: count - copies count wide characters from the src + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wmemcpy_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count); +#endif + +#if SECUREC_ENABLE_MEMMOVE + /* + * Description: The wmemmove_s function copies n successive wide characters from the object + * pointed to by src into the object pointed to by dest. + * Parameter: dest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: src - source address + * Parameter: count - copies count wide characters from the src + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wmemmove_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count); +#endif + +#if SECUREC_ENABLE_STRCPY + /* + * Description: The wcscpy_s function copies the wide string pointed to by strSrc (including theterminating + * null wide character) into the array pointed to by strDest + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer + * Parameter: strSrc - source address + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wcscpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc); +#endif + +#if SECUREC_ENABLE_STRNCPY + /* + * Description: The wcsncpy_s function copies not more than n successive wide characters (not including the + * terminating null wide character) from the array pointed to by strSrc to the array pointed to by strDest + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character) + * Parameter: strSrc - source address + * Parameter: count - copies count wide characters from the src + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wcsncpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count); +#endif + +#if SECUREC_ENABLE_STRCAT + /* + * Description: The wcscat_s function appends a copy of the wide string pointed to by strSrc (including the + * terminating null wide character) to the end of the wide string pointed to by strDest + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character) + * Parameter: strSrc - source address + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wcscat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc); +#endif + +#if SECUREC_ENABLE_STRNCAT + /* + * Description: The wcsncat_s function appends not more than n successive wide characters (not including the + * terminating null wide character) from the array pointed to by strSrc to the end of the wide string pointed to + * by strDest. + * Parameter: strDest - destination address + * Parameter: destMax - The maximum length of destination buffer(including the terminating wide character) + * Parameter: strSrc - source address + * Parameter: count - copies count wide characters from the src + * Return: EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wcsncat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count); +#endif + +#if SECUREC_ENABLE_STRTOK + /* + * Description: The wcstok_s function is the wide-character equivalent of the strtok_s function + * Parameter: strToken - the string to be delimited + * Parameter: strDelimit - specifies a set of characters that delimit the tokens in the parsed string + * Parameter: context - is a pointer to a char * variable that is used internally by strtok_s function + * Return: a pointer to the first character of a token, or a null pointer if there is no token + * or there is a runtime-constraint violation. + */ + SECUREC_API wchar_t *wcstok_s(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context); +#endif + +#if SECUREC_ENABLE_VSPRINTF + /* + * Description: The vswprintf_s function is the wide-character equivalent of the vsprintf_s function + * Parameter: strDest - produce output according to a format ,write to the character string strDest + * Parameter: destMax - The maximum length of destination buffer(including the terminating null ) + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of characters printed(not including the terminating null wide characte), + * If an error occurred Return: -1. + */ + SECUREC_API int vswprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, va_list argList); +#endif + +#if SECUREC_ENABLE_SPRINTF + + /* + * Description: The swprintf_s function is the wide-character equivalent of the sprintf_s function + * Parameter: strDest - produce output according to a format ,write to the character string strDest + * Parameter: destMax - The maximum length of destination buffer(including the terminating null ) + * Parameter: format - fromat string + * Return: the number of characters printed(not including the terminating null wide characte), + * If an error occurred Return: -1. + */ + SECUREC_API int swprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, ...); +#endif + +#if SECUREC_ENABLE_FSCANF + /* + * Description: The fwscanf_s function is the wide-character equivalent of the fscanf_s function + * Parameter: stream - stdio file stream + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int fwscanf_s(FILE *stream, const wchar_t *format, ...); +#endif + +#if SECUREC_ENABLE_VFSCANF + /* + * Description: The vfwscanf_s function is the wide-character equivalent of the vfscanf_s function + * Parameter: stream - stdio file stream + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int vfwscanf_s(FILE *stream, const wchar_t *format, va_list argList); +#endif + +#if SECUREC_ENABLE_SCANF + /* + * Description: The wscanf_s function is the wide-character equivalent of the scanf_s function + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int wscanf_s(const wchar_t *format, ...); +#endif + +#if SECUREC_ENABLE_VSCANF + /* + * Description: The vwscanf_s function is the wide-character equivalent of the vscanf_s function + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int vwscanf_s(const wchar_t *format, va_list argList); +#endif + +#if SECUREC_ENABLE_SSCANF + /* + * Description: The swscanf_s function is the wide-character equivalent of the sscanf_s function + * Parameter: buffer - read character from buffer + * Parameter: format - fromat string + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int swscanf_s(const wchar_t *buffer, const wchar_t *format, ...); +#endif + +#if SECUREC_ENABLE_VSSCANF + /* + * Description: The vswscanf_s function is the wide-character equivalent of the vsscanf_s function + * Parameter: buffer - read character from buffer + * Parameter: format - fromat string + * Parameter: argList - instead of a variable number of arguments + * Return: the number of input items assigned, If an error occurred Return: -1. + */ + SECUREC_API int vswscanf_s(const wchar_t *buffer, const wchar_t *format, va_list argList); +#endif +#endif /* SECUREC_ENABLE_WCHAR_FUNC */ +#endif + + /* Those functions are used by macro ,must declare hare , also for without function declaration warning */ + extern errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count); + extern errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc); + +#if SECUREC_WITH_PERFORMANCE_ADDONS + /* Those functions are used by macro */ + extern errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count); + extern errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count); + extern errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count); + extern errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count); + +/* The strcpy_sp is a macro, not a function in performance optimization mode. */ +#define strcpy_sp(dest, destMax, src) ((__builtin_constant_p((destMax)) && \ + __builtin_constant_p((src))) ? \ + SECUREC_STRCPY_SM((dest), (destMax), (src)) : \ + strcpy_s((dest), (destMax), (src))) + +/* The strncpy_sp is a macro, not a function in performance optimization mode. */ +#define strncpy_sp(dest, destMax, src, count) ((__builtin_constant_p((count)) && \ + __builtin_constant_p((destMax)) && \ + __builtin_constant_p((src))) ? \ + SECUREC_STRNCPY_SM((dest), (destMax), (src), (count)) : \ + strncpy_s((dest), (destMax), (src), (count))) + +/* The strcat_sp is a macro, not a function in performance optimization mode. */ +#define strcat_sp(dest, destMax, src) ((__builtin_constant_p((destMax)) && \ + __builtin_constant_p((src))) ? \ + SECUREC_STRCAT_SM((dest), (destMax), (src)) : \ + strcat_s((dest), (destMax), (src))) + +/* The strncat_sp is a macro, not a function in performance optimization mode. */ +#define strncat_sp(dest, destMax, src, count) ((__builtin_constant_p((count)) && \ + __builtin_constant_p((destMax)) && \ + __builtin_constant_p((src))) ? \ + SECUREC_STRNCAT_SM((dest), (destMax), (src), (count)) : \ + strncat_s((dest), (destMax), (src), (count))) + +/* The memcpy_sp is a macro, not a function in performance optimization mode. */ +#define memcpy_sp(dest, destMax, src, count) (__builtin_constant_p((count)) ? \ + (SECUREC_MEMCPY_SM((dest), (destMax), (src), (count))) : \ + (__builtin_constant_p((destMax)) ? \ + (((size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_MEM_MAX_LEN)) ? \ + memcpy_sOptTc((dest), (destMax), (src), (count)) : ERANGE) : \ + memcpy_sOptAsm((dest), (destMax), (src), (count)))) + +/* The memset_sp is a macro, not a function in performance optimization mode. */ +#define memset_sp(dest, destMax, c, count) (__builtin_constant_p((count)) ? \ + (SECUREC_MEMSET_SM((dest), (destMax), (c), (count))) : \ + (__builtin_constant_p((destMax)) ? \ + (((((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_MEM_MAX_LEN)) ? \ + memset_sOptTc((dest), (destMax), (c), (count)) : ERANGE) : \ + memset_sOptAsm((dest), (destMax), (c), (count)))) + +#endif + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/third_party/bounds_checking_function/include/securectype.h b/third_party/bounds_checking_function/include/securectype.h new file mode 100644 index 0000000000000000000000000000000000000000..17cca940d83f611bdbbaeca2552ed3bb937a9113 --- /dev/null +++ b/third_party/bounds_checking_function/include/securectype.h @@ -0,0 +1,570 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: Define internal used macro and data type. The marco of SECUREC_ON_64BITS + * will be determined in this header file, which is a switch for part + * of code. Some macro are used to supress warning by MS compiler. + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SECURECTYPE_H_A7BBB686_AADA_451B_B9F9_44DACDAE18A7 +#define SECURECTYPE_H_A7BBB686_AADA_451B_B9F9_44DACDAE18A7 + +#ifndef SECUREC_USING_STD_SECURE_LIB +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(__STDC_WANT_SECURE_LIB__) && (!__STDC_WANT_SECURE_LIB__) +/* Security functions have been provided since vs2005, default use of system library functions */ +#define SECUREC_USING_STD_SECURE_LIB 0 +#else +#define SECUREC_USING_STD_SECURE_LIB 1 +#endif +#else +#define SECUREC_USING_STD_SECURE_LIB 0 +#endif +#endif + +/* Compatibility with older Secure C versions, shielding VC symbol redefinition warning */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && (!SECUREC_USING_STD_SECURE_LIB) +#ifndef SECUREC_DISABLE_CRT_FUNC +#define SECUREC_DISABLE_CRT_FUNC 1 +#endif +#ifndef SECUREC_DISABLE_CRT_IMP +#define SECUREC_DISABLE_CRT_IMP 1 +#endif +#else /* MSC VER */ +#ifndef SECUREC_DISABLE_CRT_FUNC +#define SECUREC_DISABLE_CRT_FUNC 0 +#endif +#ifndef SECUREC_DISABLE_CRT_IMP +#define SECUREC_DISABLE_CRT_IMP 0 +#endif +#endif + +#if SECUREC_DISABLE_CRT_FUNC +#ifdef __STDC_WANT_SECURE_LIB__ +#undef __STDC_WANT_SECURE_LIB__ +#endif +#define __STDC_WANT_SECURE_LIB__ 0 +#endif + +#if SECUREC_DISABLE_CRT_IMP +#ifdef _CRTIMP_ALTERNATIVE +#undef _CRTIMP_ALTERNATIVE +#endif +#define _CRTIMP_ALTERNATIVE /* Comment microsoft *_s function */ +#endif + +/* Compile in kernel under macro control */ +#ifndef SECUREC_IN_KERNEL +#ifdef __KERNEL__ +#define SECUREC_IN_KERNEL 1 +#else +#define SECUREC_IN_KERNEL 0 +#endif +#endif + +#if SECUREC_IN_KERNEL +#ifndef SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF_FILE 0 +#endif +#ifndef SECUREC_ENABLE_WCHAR_FUNC +#define SECUREC_ENABLE_WCHAR_FUNC 0 +#endif +#else /* SECUREC_IN_KERNEL */ +#ifndef SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF_FILE 1 +#endif +#ifndef SECUREC_ENABLE_WCHAR_FUNC +#define SECUREC_ENABLE_WCHAR_FUNC 1 +#endif +#endif + +/* Default secure function declaration, default declarations for non-standard functions */ +#ifndef SECUREC_SNPRINTF_TRUNCATED +#define SECUREC_SNPRINTF_TRUNCATED 1 +#endif + +#if SECUREC_USING_STD_SECURE_LIB +#if defined(_MSC_VER) && _MSC_VER >= 1400 +/* Declare secure functions that are not available in the VS compiler */ +#ifndef SECUREC_ENABLE_MEMSET +#define SECUREC_ENABLE_MEMSET 1 +#endif +/* VS 2005 have vsnprintf_s function */ +#ifndef SECUREC_ENABLE_VSNPRINTF +#define SECUREC_ENABLE_VSNPRINTF 0 +#endif +#ifndef SECUREC_ENABLE_SNPRINTF +/* VS 2005 have vsnprintf_s function Adapt the snprintf_s of the security function */ +#define snprintf_s _snprintf_s +#define SECUREC_ENABLE_SNPRINTF 0 +#endif +/* Before VS 2010 do not have v functions */ +#if _MSC_VER <= 1600 || defined(SECUREC_FOR_V_SCANFS) +#ifndef SECUREC_ENABLE_VFSCANF +#define SECUREC_ENABLE_VFSCANF 1 +#endif +#ifndef SECUREC_ENABLE_VSCANF +#define SECUREC_ENABLE_VSCANF 1 +#endif +#ifndef SECUREC_ENABLE_VSSCANF +#define SECUREC_ENABLE_VSSCANF 1 +#endif +#endif + +#else /* MSC VER */ +#ifndef SECUREC_ENABLE_MEMSET +#define SECUREC_ENABLE_MEMSET 0 +#endif +#ifndef SECUREC_ENABLE_SNPRINTF +#define SECUREC_ENABLE_SNPRINTF 0 +#endif +#ifndef SECUREC_ENABLE_VSNPRINTF +#define SECUREC_ENABLE_VSNPRINTF 0 +#endif +#endif + +#ifndef SECUREC_ENABLE_MEMMOVE +#define SECUREC_ENABLE_MEMMOVE 0 +#endif +#ifndef SECUREC_ENABLE_MEMCPY +#define SECUREC_ENABLE_MEMCPY 0 +#endif +#ifndef SECUREC_ENABLE_STRCPY +#define SECUREC_ENABLE_STRCPY 0 +#endif +#ifndef SECUREC_ENABLE_STRNCPY +#define SECUREC_ENABLE_STRNCPY 0 +#endif +#ifndef SECUREC_ENABLE_STRCAT +#define SECUREC_ENABLE_STRCAT 0 +#endif +#ifndef SECUREC_ENABLE_STRNCAT +#define SECUREC_ENABLE_STRNCAT 0 +#endif +#ifndef SECUREC_ENABLE_SPRINTF +#define SECUREC_ENABLE_SPRINTF 0 +#endif +#ifndef SECUREC_ENABLE_VSPRINTF +#define SECUREC_ENABLE_VSPRINTF 0 +#endif +#ifndef SECUREC_ENABLE_SSCANF +#define SECUREC_ENABLE_SSCANF 0 +#endif +#ifndef SECUREC_ENABLE_VSSCANF +#define SECUREC_ENABLE_VSSCANF 0 +#endif +#ifndef SECUREC_ENABLE_SCANF +#define SECUREC_ENABLE_SCANF 0 +#endif +#ifndef SECUREC_ENABLE_VSCANF +#define SECUREC_ENABLE_VSCANF 0 +#endif + +#ifndef SECUREC_ENABLE_FSCANF +#define SECUREC_ENABLE_FSCANF 0 +#endif +#ifndef SECUREC_ENABLE_VFSCANF +#define SECUREC_ENABLE_VFSCANF 0 +#endif +#ifndef SECUREC_ENABLE_STRTOK +#define SECUREC_ENABLE_STRTOK 0 +#endif +#ifndef SECUREC_ENABLE_GETS +#define SECUREC_ENABLE_GETS 0 +#endif + +#else /* SECUREC USE STD SECURE LIB */ + +#ifndef SECUREC_ENABLE_MEMSET +#define SECUREC_ENABLE_MEMSET 1 +#endif +#ifndef SECUREC_ENABLE_MEMMOVE +#define SECUREC_ENABLE_MEMMOVE 1 +#endif +#ifndef SECUREC_ENABLE_MEMCPY +#define SECUREC_ENABLE_MEMCPY 1 +#endif +#ifndef SECUREC_ENABLE_STRCPY +#define SECUREC_ENABLE_STRCPY 1 +#endif +#ifndef SECUREC_ENABLE_STRNCPY +#define SECUREC_ENABLE_STRNCPY 1 +#endif +#ifndef SECUREC_ENABLE_STRCAT +#define SECUREC_ENABLE_STRCAT 1 +#endif +#ifndef SECUREC_ENABLE_STRNCAT +#define SECUREC_ENABLE_STRNCAT 1 +#endif +#ifndef SECUREC_ENABLE_SPRINTF +#define SECUREC_ENABLE_SPRINTF 1 +#endif +#ifndef SECUREC_ENABLE_VSPRINTF +#define SECUREC_ENABLE_VSPRINTF 1 +#endif +#ifndef SECUREC_ENABLE_SNPRINTF +#define SECUREC_ENABLE_SNPRINTF 1 +#endif +#ifndef SECUREC_ENABLE_VSNPRINTF +#define SECUREC_ENABLE_VSNPRINTF 1 +#endif +#ifndef SECUREC_ENABLE_SSCANF +#define SECUREC_ENABLE_SSCANF 1 +#endif +#ifndef SECUREC_ENABLE_VSSCANF +#define SECUREC_ENABLE_VSSCANF 1 +#endif +#ifndef SECUREC_ENABLE_SCANF +#if SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF 1 +#else +#define SECUREC_ENABLE_SCANF 0 +#endif +#endif +#ifndef SECUREC_ENABLE_VSCANF +#if SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_VSCANF 1 +#else +#define SECUREC_ENABLE_VSCANF 0 +#endif +#endif + +#ifndef SECUREC_ENABLE_FSCANF +#if SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_FSCANF 1 +#else +#define SECUREC_ENABLE_FSCANF 0 +#endif +#endif +#ifndef SECUREC_ENABLE_VFSCANF +#if SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_VFSCANF 1 +#else +#define SECUREC_ENABLE_VFSCANF 0 +#endif +#endif + +#ifndef SECUREC_ENABLE_STRTOK +#define SECUREC_ENABLE_STRTOK 1 +#endif +#ifndef SECUREC_ENABLE_GETS +#define SECUREC_ENABLE_GETS 1 +#endif +#endif /* SECUREC_USE_STD_SECURE_LIB */ + +#if !SECUREC_ENABLE_SCANF_FILE +#if SECUREC_ENABLE_FSCANF +#undef SECUREC_ENABLE_FSCANF +#define SECUREC_ENABLE_FSCANF 0 +#endif +#if SECUREC_ENABLE_VFSCANF +#undef SECUREC_ENABLE_VFSCANF +#define SECUREC_ENABLE_VFSCANF 0 +#endif +#if SECUREC_ENABLE_SCANF +#undef SECUREC_ENABLE_SCANF +#define SECUREC_ENABLE_SCANF 0 +#endif +#if SECUREC_ENABLE_FSCANF +#undef SECUREC_ENABLE_FSCANF +#define SECUREC_ENABLE_FSCANF 0 +#endif + +#endif + +#if SECUREC_IN_KERNEL +#include +#include +#else +#ifndef SECUREC_HAVE_STDIO_H +#define SECUREC_HAVE_STDIO_H 1 +#endif +#ifndef SECUREC_HAVE_STRING_H +#define SECUREC_HAVE_STRING_H 1 +#endif +#ifndef SECUREC_HAVE_STDLIB_H +#define SECUREC_HAVE_STDLIB_H 1 +#endif +#if SECUREC_HAVE_STDIO_H +#include +#endif +#if SECUREC_HAVE_STRING_H +#include +#endif +#if SECUREC_HAVE_STDLIB_H +#include +#endif +#endif + +/* + * If you need high performance, enable the SECUREC_WITH_PERFORMANCE_ADDONS macro, default is enable. + * The macro is automatically closed on the windows platform and linux kernel + */ +#ifndef SECUREC_WITH_PERFORMANCE_ADDONS +#if SECUREC_IN_KERNEL +#define SECUREC_WITH_PERFORMANCE_ADDONS 0 +#else +#define SECUREC_WITH_PERFORMANCE_ADDONS 1 +#endif +#endif + +/* If enable SECUREC_COMPATIBLE_WIN_FORMAT, the output format will be compatible to Windows. */ +#if (defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)) && !defined(SECUREC_COMPATIBLE_LINUX_FORMAT) +#ifndef SECUREC_COMPATIBLE_WIN_FORMAT +#define SECUREC_COMPATIBLE_WIN_FORMAT +#endif +#endif + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) +/* On windows platform, can't use optimized function for there is no __builtin_constant_p like function */ +/* If need optimized macro, can define this: define __builtin_constant_p(x) 0 */ +#ifdef SECUREC_WITH_PERFORMANCE_ADDONS +#undef SECUREC_WITH_PERFORMANCE_ADDONS +#define SECUREC_WITH_PERFORMANCE_ADDONS 0 +#endif +#endif + +#if defined(__VXWORKS__) || defined(__vxworks) || defined(__VXWORKS) || defined(_VXWORKS_PLATFORM_) || \ + defined(SECUREC_VXWORKS_VERSION_5_4) +#ifndef SECUREC_VXWORKS_PLATFORM +#define SECUREC_VXWORKS_PLATFORM +#endif +#endif + +/* If enable SECUREC_COMPATIBLE_LINUX_FORMAT, the output format will be compatible to Linux. */ +#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT) && !defined(SECUREC_VXWORKS_PLATFORM) +#ifndef SECUREC_COMPATIBLE_LINUX_FORMAT +#define SECUREC_COMPATIBLE_LINUX_FORMAT +#endif +#endif + +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +#ifndef SECUREC_HAVE_STDDEF_H +#define SECUREC_HAVE_STDDEF_H 1 +#endif +/* Some system may no stddef.h */ +#if SECUREC_HAVE_STDDEF_H +#if !SECUREC_IN_KERNEL +#include +#endif +#endif +#endif + +/* + * Add the -DSECUREC_SUPPORT_FORMAT_WARNING=1 compiler option to supoort -Wformat=2. + * Default does not check the format is that the same data type in the actual code. + * In the product is different in the original data type definition of VxWorks and Linux. + */ +#ifndef SECUREC_SUPPORT_FORMAT_WARNING +#define SECUREC_SUPPORT_FORMAT_WARNING 0 +#endif + +#if SECUREC_SUPPORT_FORMAT_WARNING +#define SECUREC_ATTRIBUTE(x, y) __attribute__((format(printf, (x), (y)))) +#else +#define SECUREC_ATTRIBUTE(x, y) +#endif + +/* + * Add the -DSECUREC_SUPPORT_BUILTIN_EXPECT=0 compiler option, if complier can not support __builtin_expect. + */ +#ifndef SECUREC_SUPPORT_BUILTIN_EXPECT +#define SECUREC_SUPPORT_BUILTIN_EXPECT 1 +#endif + +#if SECUREC_SUPPORT_BUILTIN_EXPECT && defined(__GNUC__) && ((__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3))) +/* + * This is a built-in function that can be used without a declaration, if warning for declaration not found occurred, + * you can add -DSECUREC_NEED_BUILTIN_EXPECT_DECLARE to complier options + */ +#ifdef SECUREC_NEED_BUILTIN_EXPECT_DECLARE +long __builtin_expect(long exp, long c); +#endif + +#define SECUREC_LIKELY(x) __builtin_expect(!!(x), 1) +#define SECUREC_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define SECUREC_LIKELY(x) (x) +#define SECUREC_UNLIKELY(x) (x) +#endif + +/* Define the max length of the string */ +#ifndef SECUREC_STRING_MAX_LEN +#define SECUREC_STRING_MAX_LEN 0x7fffffffUL +#endif +#define SECUREC_WCHAR_STRING_MAX_LEN (SECUREC_STRING_MAX_LEN / sizeof(wchar_t)) + +/* Add SECUREC_MEM_MAX_LEN for memcpy and memmove */ +#ifndef SECUREC_MEM_MAX_LEN +#define SECUREC_MEM_MAX_LEN 0x7fffffffUL +#endif +#define SECUREC_WCHAR_MEM_MAX_LEN (SECUREC_MEM_MAX_LEN / sizeof(wchar_t)) + +#if SECUREC_STRING_MAX_LEN > 0x7fffffffUL +#error "max string is 2G" +#endif + +#if (defined(__GNUC__) && defined(__SIZEOF_POINTER__)) +#if (__SIZEOF_POINTER__ != 4) && (__SIZEOF_POINTER__ != 8) +#error "unsupported system" +#endif +#endif + +#if defined(_WIN64) || defined(WIN64) || defined(__LP64__) || defined(_LP64) +#define SECUREC_ON_64BITS +#endif + +#if (!defined(SECUREC_ON_64BITS) && defined(__GNUC__) && defined(__SIZEOF_POINTER__)) +#if __SIZEOF_POINTER__ == 8 +#define SECUREC_ON_64BITS +#endif +#endif + +#if defined(__SVR4) || defined(__svr4__) +#define SECUREC_ON_SOLARIS +#endif + +#if (defined(__hpux) || defined(_AIX) || defined(SECUREC_ON_SOLARIS)) +#define SECUREC_ON_UNIX +#endif + +/* + * Codes should run under the macro SECUREC_COMPATIBLE_LINUX_FORMAT in unknow system on default, + * and strtold. + * The function strtold is referenced first at ISO9899:1999(C99), and some old compilers can + * not support these functions. Here provides a macro to open these functions: + * SECUREC_SUPPORT_STRTOLD -- If defined, strtold will be used + */ +#ifndef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 0 +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) +#if defined(__USE_ISOC99) || \ + (defined(_AIX) && defined(_ISOC99_SOURCE)) || \ + (defined(__hpux) && defined(__ia64)) || \ + (defined(SECUREC_ON_SOLARIS) && (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \ + defined(_STDC_C99) || defined(__EXTENSIONS__)) +#undef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 1 +#endif +#endif +#if ((defined(SECUREC_WRLINUX_BELOW4) || defined(_WRLINUX_BELOW4_))) +#undef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 0 +#endif +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS + +#ifndef SECUREC_TWO_MIN +#define SECUREC_TWO_MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* For strncpy_s performance optimization */ +#define SECUREC_STRNCPY_SM(dest, destMax, src, count) \ + (((void *)(dest) != NULL && (void *)(src) != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (SECUREC_TWO_MIN((size_t)(count), strlen(src)) + 1) <= (size_t)(destMax)) ? \ + (((size_t)(count) < strlen(src)) ? (memcpy((dest), (src), (count)), *((char *)(dest) + (count)) = '\0', EOK) : \ + (memcpy((dest), (src), strlen(src) + 1), EOK)) : (strncpy_error((dest), (destMax), (src), (count)))) + +#define SECUREC_STRCPY_SM(dest, destMax, src) \ + (((void *)(dest) != NULL && (void *)(src) != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (strlen(src) + 1) <= (size_t)(destMax)) ? (memcpy((dest), (src), strlen(src) + 1), EOK) : \ + (strcpy_error((dest), (destMax), (src)))) + +/* For strcat_s performance optimization */ +#if defined(__GNUC__) +#define SECUREC_STRCAT_SM(dest, destMax, src) ({ \ + int catRet_ = EOK; \ + if ((void *)(dest) != NULL && (void *)(src) != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)) { \ + char *catTmpDst_ = (char *)(dest); \ + size_t catRestSize_ = (destMax); \ + while (catRestSize_ > 0 && *catTmpDst_ != '\0') { \ + ++catTmpDst_; \ + --catRestSize_; \ + } \ + if (catRestSize_ == 0) { \ + catRet_ = EINVAL; \ + } else if ((strlen(src) + 1) <= catRestSize_) { \ + memcpy(catTmpDst_, (src), strlen(src) + 1); \ + catRet_ = EOK; \ + } else { \ + catRet_ = ERANGE; \ + } \ + if (catRet_ != EOK) { \ + catRet_ = strcat_s((dest), (destMax), (src)); \ + } \ + } else { \ + catRet_ = strcat_s((dest), (destMax), (src)); \ + } \ + catRet_; \ +}) +#else +#define SECUREC_STRCAT_SM(dest, destMax, src) strcat_s((dest), (destMax), (src)) +#endif + +/* For strncat_s performance optimization */ +#if defined(__GNUC__) +#define SECUREC_STRNCAT_SM(dest, destMax, src, count) ({ \ + int ncatRet_ = EOK; \ + if ((void *)(dest) != NULL && (void *)(src) != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (((unsigned long long)(count) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)) { \ + char *ncatTmpDest_ = (char *)(dest); \ + size_t ncatRestSize_ = (size_t)(destMax); \ + while (ncatRestSize_ > 0 && *ncatTmpDest_ != '\0') { \ + ++ncatTmpDest_; \ + --ncatRestSize_; \ + } \ + if (ncatRestSize_ == 0) { \ + ncatRet_ = EINVAL; \ + } else if ((SECUREC_TWO_MIN((count), strlen(src)) + 1) <= ncatRestSize_) { \ + if ((size_t)(count) < strlen(src)) { \ + memcpy(ncatTmpDest_, (src), (count)); \ + *(ncatTmpDest_ + (count)) = '\0'; \ + } else { \ + memcpy(ncatTmpDest_, (src), strlen(src) + 1); \ + } \ + } else { \ + ncatRet_ = ERANGE; \ + } \ + if (ncatRet_ != EOK) { \ + ncatRet_ = strncat_s((dest), (destMax), (src), (count)); \ + } \ + } else { \ + ncatRet_ = strncat_s((dest), (destMax), (src), (count)); \ + } \ + ncatRet_; \ +}) +#else +#define SECUREC_STRNCAT_SM(dest, destMax, src, count) strncat_s((dest), (destMax), (src), (count)) +#endif + +/* This macro do not check buffer overlap by default */ +#define SECUREC_MEMCPY_SM(dest, destMax, src, count) \ + (!(((size_t)(destMax) == 0) || \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) > SECUREC_MEM_MAX_LEN) || \ + ((size_t)(count) > (size_t)(destMax)) || ((void *)(dest)) == NULL || ((void *)(src) == NULL)) ? \ + (memcpy((dest), (src), (count)), EOK) : \ + (memcpy_s((dest), (destMax), (src), (count)))) + +#define SECUREC_MEMSET_SM(dest, destMax, c, count) \ + (!((((unsigned long long)(destMax) & (unsigned long long)(-2)) > SECUREC_MEM_MAX_LEN) || \ + ((void *)(dest) == NULL) || ((size_t)(count) > (size_t)(destMax))) ? \ + (memset((dest), (c), (count)), EOK) : \ + (memset_s((dest), (destMax), (c), (count)))) + +#endif +#endif + diff --git a/third_party/bounds_checking_function/libsec_src.gni b/third_party/bounds_checking_function/libsec_src.gni new file mode 100644 index 0000000000000000000000000000000000000000..a6f5df33b84c1c11f450ef0d01a166726ce29287 --- /dev/null +++ b/third_party/bounds_checking_function/libsec_src.gni @@ -0,0 +1,58 @@ +# +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +libsec_include_dirs = [ "//third_party/bounds_checking_function/include" ] + +libsec_sources = [ + "//third_party/bounds_checking_function/src/fscanf_s.c", + "//third_party/bounds_checking_function/src/fwscanf_s.c", + "//third_party/bounds_checking_function/src/gets_s.c", + "//third_party/bounds_checking_function/src/memcpy_s.c", + "//third_party/bounds_checking_function/src/memmove_s.c", + "//third_party/bounds_checking_function/src/memset_s.c", + "//third_party/bounds_checking_function/src/scanf_s.c", + "//third_party/bounds_checking_function/src/securecutil.c", + "//third_party/bounds_checking_function/src/secureinput_a.c", + "//third_party/bounds_checking_function/src/secureinput_w.c", + "//third_party/bounds_checking_function/src/secureprintoutput_a.c", + "//third_party/bounds_checking_function/src/secureprintoutput_w.c", + "//third_party/bounds_checking_function/src/snprintf_s.c", + "//third_party/bounds_checking_function/src/sprintf_s.c", + "//third_party/bounds_checking_function/src/sscanf_s.c", + "//third_party/bounds_checking_function/src/strcat_s.c", + "//third_party/bounds_checking_function/src/strcpy_s.c", + "//third_party/bounds_checking_function/src/strncat_s.c", + "//third_party/bounds_checking_function/src/strncpy_s.c", + "//third_party/bounds_checking_function/src/strtok_s.c", + "//third_party/bounds_checking_function/src/swprintf_s.c", + "//third_party/bounds_checking_function/src/swscanf_s.c", + "//third_party/bounds_checking_function/src/vfscanf_s.c", + "//third_party/bounds_checking_function/src/vfwscanf_s.c", + "//third_party/bounds_checking_function/src/vscanf_s.c", + "//third_party/bounds_checking_function/src/vsnprintf_s.c", + "//third_party/bounds_checking_function/src/vsprintf_s.c", + "//third_party/bounds_checking_function/src/vsscanf_s.c", + "//third_party/bounds_checking_function/src/vswprintf_s.c", + "//third_party/bounds_checking_function/src/vswscanf_s.c", + "//third_party/bounds_checking_function/src/vwscanf_s.c", + "//third_party/bounds_checking_function/src/wcscat_s.c", + "//third_party/bounds_checking_function/src/wcscpy_s.c", + "//third_party/bounds_checking_function/src/wcsncat_s.c", + "//third_party/bounds_checking_function/src/wcsncpy_s.c", + "//third_party/bounds_checking_function/src/wcstok_s.c", + "//third_party/bounds_checking_function/src/wmemcpy_s.c", + "//third_party/bounds_checking_function/src/wmemmove_s.c", + "//third_party/bounds_checking_function/src/wscanf_s.c", +] diff --git a/third_party/bounds_checking_function/src/fscanf_s.c b/third_party/bounds_checking_function/src/fscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..2d1e735c3c8cec8d2c171a8eac2669588f77cc07 --- /dev/null +++ b/third_party/bounds_checking_function/src/fscanf_s.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: fscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +/* + * + * The fscanf_s function is equivalent to fscanf except that the c, s, + * and [ conversion specifiers apply to a pair of arguments (unless assignment suppression is indicated by a*) + * The fscanf function reads data from the current position of stream into + * the locations given by argument (if any). Each argument must be a pointer + * to a variable of a type that corresponds to a type specifier in format. + * format controls the interpretation of the input fields and has the same + * form and function as the format argument for scanf. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The convered value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int fscanf_s(FILE *stream, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vfscanf_s(stream, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} + diff --git a/third_party/bounds_checking_function/src/fwscanf_s.c b/third_party/bounds_checking_function/src/fwscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..ed2438b1d91b59cdede3669d3537da9cc0c6ee1a --- /dev/null +++ b/third_party/bounds_checking_function/src/fwscanf_s.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: fwscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +/* + * + * The fwscanf_s function is the wide-character equivalent of the fscanf_s function + * The fwscanf_s function reads data from the current position of stream into + * the locations given by argument (if any). Each argument must be a pointer + * to a variable of a type that corresponds to a type specifier in format. + * format controls the interpretation of the input fields and has the same + * form and function as the format argument for scanf. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int fwscanf_s(FILE *stream, const wchar_t *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vfwscanf_s(stream, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} + diff --git a/third_party/bounds_checking_function/src/gets_s.c b/third_party/bounds_checking_function/src/gets_s.c new file mode 100644 index 0000000000000000000000000000000000000000..18d785888cde0d9bdc01b1e9e2ccf9549f7a5b76 --- /dev/null +++ b/third_party/bounds_checking_function/src/gets_s.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: gets_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +/* + * The parameter size is buffer size in byte + */ +SECUREC_INLINE void SecTrimCRLF(char *buffer, size_t size) +{ + size_t len = strlen(buffer); + --len; /* Unsigned integer wrapping is accepted and is checked afterwards */ + while (len < size && (buffer[len] == '\r' || buffer[len] == '\n')) { + buffer[len] = '\0'; + --len; /* Unsigned integer wrapping is accepted and is checked next loop */ + } +} + +/* + * + * The gets_s function reads at most one less than the number of characters + * specified by destMax from the std input stream, into the array pointed to by buffer + * The line consists of all characters up to and including + * the first newline character ('\n'). gets_s then replaces the newline + * character with a null character ('\0') before returning the line. + * If the first character read is the end-of-file character, a null character + * is stored at the beginning of buffer and NULL is returned. + * + * + * buffer Storage location for input string. + * destMax The size of the buffer. + * + * + * buffer is updated + * + * + * buffer Successful operation + * NULL Improper parameter or read fail + */ +char *gets_s(char *buffer, size_t destMax) +{ +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + size_t bufferSize = ((destMax == (size_t)(-1)) ? SECUREC_STRING_MAX_LEN : destMax); +#else + size_t bufferSize = destMax; +#endif + + if (buffer == NULL || bufferSize == 0 || bufferSize > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_PARAMTER("gets_s"); + return NULL; + } + + if (fgets(buffer, (int)bufferSize, SECUREC_STREAM_STDIN) != NULL) { + SecTrimCRLF(buffer, bufferSize); + return buffer; + } + + return NULL; +} + diff --git a/third_party/bounds_checking_function/src/input.inl b/third_party/bounds_checking_function/src/input.inl new file mode 100644 index 0000000000000000000000000000000000000000..06fff4157fc784e458f86722c842928b9333f221 --- /dev/null +++ b/third_party/bounds_checking_function/src/input.inl @@ -0,0 +1,2227 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: Used by secureinput_a.c and secureinput_w.c to include. + * This file provides a template function for ANSI and UNICODE compiling by + * different type definition. The functions of SecInputS or + * SecInputSW provides internal implementation for scanf family API, such as sscanf_s, fscanf_s. + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef INPUT_INL_5D13A042_DC3F_4ED9_A8D1_882811274C27 +#define INPUT_INL_5D13A042_DC3F_4ED9_A8D1_882811274C27 + +#if SECUREC_IN_KERNEL +#if !defined(SECUREC_CTYPE_MACRO_ADAPT) +#include +#endif +#else +#if !defined(SECUREC_SYSAPI4VXWORKS) && !defined(SECUREC_CTYPE_MACRO_ADAPT) +#include +#ifdef SECUREC_FOR_WCHAR +#include /* For iswspace */ +#endif +#endif +#endif + +#ifndef EOF +#define EOF (-1) +#endif + +#define SECUREC_NUM_WIDTH_SHORT 0 +#define SECUREC_NUM_WIDTH_INT 1 +#define SECUREC_NUM_WIDTH_LONG 2 +#define SECUREC_NUM_WIDTH_LONG_LONG 3 /* Also long double */ + +#define SECUREC_BUFFERED_BLOK_SIZE 1024U + +#if defined(SECUREC_VXWORKS_PLATFORM) && !defined(va_copy) && !defined(__va_copy) +/* The name is the same as system macro. */ +#define __va_copy(dest, src) do { \ + size_t destSize_ = (size_t)sizeof(dest); \ + size_t srcSize_ = (size_t)sizeof(src); \ + if (destSize_ != srcSize_) { \ + (void)memcpy((dest), (src), sizeof(va_list)); \ + } else { \ + (void)memcpy(&(dest), &(src), sizeof(va_list)); \ + } \ +} SECUREC_WHILE_ZERO +#endif + +#define SECUREC_MULTI_BYTE_MAX_LEN 6 + +/* Compatibility macro name cannot be modifie */ +#ifndef UNALIGNED +#if !(defined(_M_IA64)) && !(defined(_M_AMD64)) +#define UNALIGNED +#else +#define UNALIGNED __unaligned +#endif +#endif + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) +/* Max 64bit value is 0xffffffffffffffff */ +#define SECUREC_MAX_64BITS_VALUE 18446744073709551615ULL +#define SECUREC_MAX_64BITS_VALUE_DIV_TEN 1844674407370955161ULL +#define SECUREC_MAX_64BITS_VALUE_CUT_LAST_DIGIT 18446744073709551610ULL +#define SECUREC_MIN_64BITS_NEG_VALUE 9223372036854775808ULL +#define SECUREC_MAX_64BITS_POS_VALUE 9223372036854775807ULL +#define SECUREC_MIN_32BITS_NEG_VALUE 2147483648UL +#define SECUREC_MAX_32BITS_POS_VALUE 2147483647UL +#define SECUREC_MAX_32BITS_VALUE 4294967295UL +#define SECUREC_MAX_32BITS_VALUE_INC 4294967296UL +#define SECUREC_MAX_32BITS_VALUE_DIV_TEN 429496729UL +#define SECUREC_LONG_BIT_NUM ((unsigned int)(sizeof(long) << 3U)) +/* Use ULL to clean up cl6x compilation alerts */ +#define SECUREC_MAX_LONG_POS_VALUE ((unsigned long)(1ULL << (SECUREC_LONG_BIT_NUM - 1)) - 1) +#define SECUREC_MIN_LONG_NEG_VALUE ((unsigned long)(1ULL << (SECUREC_LONG_BIT_NUM - 1))) + +/* Covert to long long to clean up cl6x compilation alerts */ +#define SECUREC_LONG_HEX_BEYOND_MAX(number) (((unsigned long long)(number) >> (SECUREC_LONG_BIT_NUM - 4U)) > 0) +#define SECUREC_LONG_OCTAL_BEYOND_MAX(number) (((unsigned long long)(number) >> (SECUREC_LONG_BIT_NUM - 3U)) > 0) + +#define SECUREC_QWORD_HEX_BEYOND_MAX(number) (((number) >> (64U - 4U)) > 0) +#define SECUREC_QWORD_OCTAL_BEYOND_MAX(number) (((number) >> (64U - 3U)) > 0) + +#define SECUREC_LP64_BIT_WIDTH 64 +#define SECUREC_LP32_BIT_WIDTH 32 + +#define SECUREC_CONVERT_IS_SIGNED(conv) ((conv) == 'd' || (conv) == 'i') +#endif + +#define SECUREC_BRACE '{' /* [ to { */ +#define SECUREC_FILED_WIDTH_ENOUGH(spec) ((spec)->widthSet == 0 || (spec)->width > 0) +#define SECUREC_FILED_WIDTH_DEC(spec) do { \ + if ((spec)->widthSet != 0) { \ + --(spec)->width; \ + } \ +} SECUREC_WHILE_ZERO + +#ifdef SECUREC_FOR_WCHAR +/* Bits for all wchar, size is 65536/8, only supports wide characters with a maximum length of two bytes */ +#define SECUREC_BRACKET_TABLE_SIZE 8192 +#define SECUREC_EOF WEOF +#define SECUREC_MB_LEN 16 /* Max. # bytes in multibyte char ,see MB_LEN_MAX */ +#else +/* Bits for all char, size is 256/8 */ +#define SECUREC_BRACKET_TABLE_SIZE 32 +#define SECUREC_EOF EOF +#endif + +#if SECUREC_HAVE_WCHART +#define SECUREC_ARRAY_WIDTH_IS_WRONG(spec) ((spec).arrayWidth == 0 || \ + ((spec).isWCharOrLong <= 0 && (spec).arrayWidth > SECUREC_STRING_MAX_LEN) || \ + ((spec).isWCharOrLong > 0 && (spec).arrayWidth > SECUREC_WCHAR_STRING_MAX_LEN)) +#else +#define SECUREC_ARRAY_WIDTH_IS_WRONG(spec) ((spec).arrayWidth == 0 || (spec).arrayWidth > SECUREC_STRING_MAX_LEN) +#endif + +typedef struct { +#ifdef SECUREC_FOR_WCHAR + unsigned char *table; /* Default NULL */ +#else + unsigned char table[SECUREC_BRACKET_TABLE_SIZE]; /* Array length is large enough in application scenarios */ +#endif + unsigned char mask; /* Default 0 */ +} SecBracketTable; + +#ifdef SECUREC_FOR_WCHAR +#define SECUREC_INIT_BRACKET_TABLE { NULL, 0 } +#else +#define SECUREC_INIT_BRACKET_TABLE { {0}, 0 } +#endif + +#if SECUREC_ENABLE_SCANF_FLOAT +typedef struct { + size_t floatStrTotalLen; /* Initialization must be length of buffer in charater */ + size_t floatStrUsedLen; /* Store float string len */ + SecChar *floatStr; /* Initialization must point to buffer */ + SecChar *allocatedFloatStr; /* Initialization must be NULL to store alloced point */ + SecChar buffer[SECUREC_FLOAT_BUFSIZE + 1]; +} SecFloatSpec; +#endif + +#define SECUREC_NUMBER_STATE_DEFAULT 0U +#define SECUREC_NUMBER_STATE_STARTED 1U + +typedef struct { + SecInt ch; /* Char read from input */ + int charCount; /* Number of characters processed */ + void *argPtr; /* Variable parameter pointer, point to the end of the string */ + size_t arrayWidth; /* Length of pointer Variable parameter, in charaters */ + SecUnsignedInt64 number64; /* Store input number64 value */ + unsigned long number; /* Store input number32 value */ + int numberWidth; /* 0 = SHORT, 1 = int, > 1 long or L_DOUBLE */ + int numberArgType; /* 1 for 64-bit integer, 0 otherwise. use it as decode function index */ + unsigned int negative; /* 0 is positive */ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + unsigned int beyondMax; /* Non-zero means beyond */ +#endif + unsigned int numberState; /* Identifies whether to start processing numbers, 1 is can input number*/ + int width; /* Width number in format */ + int widthSet; /* 0 is not set width in format */ + int convChr; /* Lowercase format conversion characters */ + int oriConvChr; /* Store original format conversion, convChr may change when parsing integers */ + signed char isWCharOrLong; /* -1/0 not wchar or long, 1 for wchar or long */ + unsigned char suppress; /* 0 is not have %* in format */ +} SecScanSpec; + +#ifdef SECUREC_FOR_WCHAR +#define SECUREC_GETC fgetwc +#define SECUREC_UN_GETC ungetwc +/* Only supports wide characters with a maximum length of two bytes in format string */ +#define SECUREC_BRACKET_CHAR_MASK 0xffffU +#else +#define SECUREC_GETC fgetc +#define SECUREC_UN_GETC ungetc +#define SECUREC_BRACKET_CHAR_MASK 0xffU +#endif + +#define SECUREC_CHAR_SIZE ((unsigned int)(sizeof(SecChar))) +/* To avoid 648, mask high bit: 0x00ffffff 0x0000ffff or 0x00000000 */ +#define SECUREC_CHAR_MASK_HIGH (((((((((unsigned int)(-1) >> SECUREC_CHAR_SIZE) >> SECUREC_CHAR_SIZE) >> \ + SECUREC_CHAR_SIZE) >> SECUREC_CHAR_SIZE) >> \ + SECUREC_CHAR_SIZE) >> SECUREC_CHAR_SIZE) >> \ + SECUREC_CHAR_SIZE) >> SECUREC_CHAR_SIZE) + +/* For char is 0xff, wcahr_t is 0xffff or 0xffffffff. */ +#define SECUREC_CHAR_MASK (~((((((((((unsigned int)(-1) & SECUREC_CHAR_MASK_HIGH) << \ + SECUREC_CHAR_SIZE) << SECUREC_CHAR_SIZE) << \ + SECUREC_CHAR_SIZE) << SECUREC_CHAR_SIZE) << \ + SECUREC_CHAR_SIZE) << SECUREC_CHAR_SIZE) << \ + SECUREC_CHAR_SIZE) << SECUREC_CHAR_SIZE)) + +/* According wchar_t has multiple bytes, so use sizeof */ +#define SECUREC_GET_CHAR(stream, outCh) do { \ + if ((stream)->count >= sizeof(SecChar)) { \ + *(outCh) = (SecInt)(SECUREC_CHAR_MASK & \ + (unsigned int)(int)(*((const SecChar *)(const void *)(stream)->cur))); \ + (stream)->cur += sizeof(SecChar); \ + (stream)->count -= sizeof(SecChar); \ + } else { \ + *(outCh) = SECUREC_EOF; \ + } \ +} SECUREC_WHILE_ZERO + +#define SECUREC_UN_GET_CHAR(stream) do { \ + if ((stream)->cur > (stream)->base) { \ + (stream)->cur -= sizeof(SecChar); \ + (stream)->count += sizeof(SecChar); \ + } \ +} SECUREC_WHILE_ZERO + +/* Convert wchar_t to int and then to unsigned int to keep data clearing warning */ +#define SECUREC_TO_LOWERCASE(chr) ((int)((unsigned int)(int)(chr) | (unsigned int)('a' - 'A'))) + +/* Record a flag for each bit */ +#define SECUREC_BRACKET_INDEX(x) ((unsigned int)(x) >> 3U) +#define SECUREC_BRACKET_VALUE(x) ((unsigned char)(1U << ((unsigned int)(x) & 7U))) +#if SECUREC_IN_KERNEL +#define SECUREC_CONVERT_IS_UNSIGNED(conv) ((conv) == 'x' || (conv) == 'o' || (conv) == 'u') +#endif + +/* + * Set char in %[xxx] into table, only supports wide characters with a maximum length of two bytes + */ +SECUREC_INLINE void SecBracketSetBit(unsigned char *table, SecUnsignedChar ch) +{ + unsigned int tableIndex = SECUREC_BRACKET_INDEX(((unsigned int)(int)ch & SECUREC_BRACKET_CHAR_MASK)); + unsigned int tableValue = SECUREC_BRACKET_VALUE(((unsigned int)(int)ch & SECUREC_BRACKET_CHAR_MASK)); + /* Do not use |= optimize this code, it will cause compiling warning */ + table[tableIndex] = (unsigned char)(table[tableIndex] | tableValue); +} + +SECUREC_INLINE void SecBracketSetBitRange(unsigned char *table, SecUnsignedChar startCh, SecUnsignedChar endCh) +{ + SecUnsignedChar expCh; + /* %[a-z] %[a-a] Format %[a-\xff] end is 0xFF, condition (expCh <= endChar) cause dead loop */ + for (expCh = startCh; expCh < endCh; ++expCh) { + SecBracketSetBit(table, expCh); + } + SecBracketSetBit(table, endCh); +} +/* + * Determine whether the expression can be satisfied + */ +SECUREC_INLINE int SecCanInputForBracket(int convChr, SecInt ch, const SecBracketTable *bracketTable) +{ + unsigned int tableIndex = SECUREC_BRACKET_INDEX(((unsigned int)(int)ch & SECUREC_BRACKET_CHAR_MASK)); + unsigned int tableValue = SECUREC_BRACKET_VALUE(((unsigned int)(int)ch & SECUREC_BRACKET_CHAR_MASK)); +#ifdef SECUREC_FOR_WCHAR + if (((unsigned int)(int)ch & (~(SECUREC_BRACKET_CHAR_MASK))) != 0) { + /* The value of the wide character exceeds the size of two bytes */ + return 0; + } + return (int)(convChr == SECUREC_BRACE && bracketTable->table != NULL && + ((bracketTable->table[tableIndex] ^ bracketTable->mask) & tableValue) != 0); +#else + return (int)(convChr == SECUREC_BRACE && + ((bracketTable->table[tableIndex] ^ bracketTable->mask) & tableValue) != 0); +#endif +} + +/* + * String input ends when blank character is encountered + */ +SECUREC_INLINE int SecCanInputString(int convChr, SecInt ch) +{ + return (int)(convChr == 's' && + (!(ch >= SECUREC_CHAR('\t') && ch <= SECUREC_CHAR('\r')) && ch != SECUREC_CHAR(' '))); +} + +/* + * Can input a character when format is %c + */ +SECUREC_INLINE int SecCanInputCharacter(int convChr) +{ + return (int)(convChr == 'c'); +} + +/* + * Determine if it is a 64-bit pointer function + * Return 0 is not ,1 is 64bit pointer + */ +SECUREC_INLINE int SecNumberArgType(size_t sizeOfVoidStar) +{ + /* Point size is 4 or 8 , Under the 64 bit system, the value not 0 */ + /* To clear e778 */ + if ((sizeOfVoidStar & sizeof(SecInt64)) != 0) { + return 1; + } + return 0; +} +SECUREC_INLINE int SecIsDigit(SecInt ch); +SECUREC_INLINE int SecIsXdigit(SecInt ch); +SECUREC_INLINE int SecIsSpace(SecInt ch); +SECUREC_INLINE SecInt SecSkipSpaceChar(SecFileStream *stream, int *counter); +SECUREC_INLINE SecInt SecGetChar(SecFileStream *stream, int *counter); +SECUREC_INLINE void SecUnGetChar(SecInt ch, SecFileStream *stream, int *counter); + +#if SECUREC_ENABLE_SCANF_FLOAT + +/* + * Convert a floating point string to a floating point number + */ +SECUREC_INLINE void SecAssignFloat(const char *floatStr, int numberWidth, void *argPtr) +{ + char *endPtr = NULL; + double d; +#if SECUREC_SUPPORT_STRTOLD + if (numberWidth == SECUREC_NUM_WIDTH_LONG_LONG) { + long double d2 = strtold(floatStr, &endPtr); + *(long double UNALIGNED *)(argPtr) = d2; + return; + } +#endif + d = strtod(floatStr, &endPtr); + if (numberWidth > SECUREC_NUM_WIDTH_INT) { + *(double UNALIGNED *)(argPtr) = (double)d; + } else { + *(float UNALIGNED *)(argPtr) = (float)d; + } +} + +#ifdef SECUREC_FOR_WCHAR +/* + * Convert a floating point wchar string to a floating point number + * Success ret 0 + */ +SECUREC_INLINE int SecAssignFloatW(const SecFloatSpec *floatSpec, const SecScanSpec *spec) +{ + /* Convert float string */ + size_t mbsLen; + size_t tempFloatStrLen = (size_t)(floatSpec->floatStrTotalLen + 1) * sizeof(wchar_t); + char *tempFloatStr = (char *)SECUREC_MALLOC(tempFloatStrLen); + + if (tempFloatStr == NULL) { + return -1; + } + tempFloatStr[0] = '\0'; + SECUREC_MASK_MSVC_CRT_WARNING + mbsLen = wcstombs(tempFloatStr, floatSpec->floatStr, tempFloatStrLen - 1); + SECUREC_END_MASK_MSVC_CRT_WARNING + /* This condition must satisfy mbsLen is not -1 */ + if (mbsLen >= tempFloatStrLen) { + SECUREC_FREE(tempFloatStr); + return -1; + } + tempFloatStr[mbsLen] = '\0'; + SecAssignFloat(tempFloatStr, spec->numberWidth, spec->argPtr); + SECUREC_FREE(tempFloatStr); + return 0; +} +#endif + +/* + * Init SecFloatSpec befor parse format + */ +SECUREC_INLINE void SecInitFloatSpec(SecFloatSpec *floatSpec) +{ + floatSpec->floatStr = floatSpec->buffer; + floatSpec->allocatedFloatStr = NULL; + floatSpec->floatStrTotalLen = sizeof(floatSpec->buffer) / sizeof(floatSpec->buffer[0]); + floatSpec->floatStrUsedLen = 0; +} + +SECUREC_INLINE void SecFreeFloatSpec(SecFloatSpec *floatSpec, int *doneCount) +{ + /* LSD 2014.3.6 add, clear the stack data */ + if (memset_s(floatSpec->buffer, sizeof(floatSpec->buffer), 0, sizeof(floatSpec->buffer)) != EOK) { + *doneCount = 0; /* This code just to meet the coding requirements */ + } + /* The pFloatStr can be alloced in SecExtendFloatLen function, clear and free it */ + if (floatSpec->allocatedFloatStr != NULL) { + size_t bufferSize = floatSpec->floatStrTotalLen * sizeof(SecChar); + if (memset_s(floatSpec->allocatedFloatStr, bufferSize, 0, bufferSize) != EOK) { + *doneCount = 0; /* This code just to meet the coding requirements */ + } + SECUREC_FREE(floatSpec->allocatedFloatStr); + floatSpec->allocatedFloatStr = NULL; + floatSpec->floatStr = NULL; + } +} + +/* + * Splice floating point string + * Return 0 OK + */ +SECUREC_INLINE int SecExtendFloatLen(SecFloatSpec *floatSpec) +{ + if (floatSpec->floatStrUsedLen >= floatSpec->floatStrTotalLen) { + /* Buffer size is len x sizeof(SecChar) */ + size_t oriSize = floatSpec->floatStrTotalLen * sizeof(SecChar); + /* Add one character to clear tool warning */ + size_t nextSize = (oriSize * 2) + sizeof(SecChar); /* Multiply 2 to extend buffer size */ + + /* Prevents integer overflow, the maximum length of SECUREC_MAX_WIDTH_LEN is enough */ + if (nextSize <= (size_t)SECUREC_MAX_WIDTH_LEN) { + void *nextBuffer = (void *)SECUREC_MALLOC(nextSize); + if (nextBuffer == NULL) { + return -1; + } + if (memcpy_s(nextBuffer, nextSize, floatSpec->floatStr, oriSize) != EOK) { + SECUREC_FREE(nextBuffer); /* This is a dead code, just to meet the coding requirements */ + return -1; + } + /* Clear old buffer memory */ + if (memset_s(floatSpec->floatStr, oriSize, 0, oriSize) != EOK) { + SECUREC_FREE(nextBuffer); /* This is a dead code, just to meet the coding requirements */ + return -1; + } + /* Free old allocated buffer */ + if (floatSpec->allocatedFloatStr != NULL) { + SECUREC_FREE(floatSpec->allocatedFloatStr); + } + floatSpec->allocatedFloatStr = (SecChar *)(nextBuffer); /* Use to clear free on stack warning */ + floatSpec->floatStr = (SecChar *)(nextBuffer); + floatSpec->floatStrTotalLen = nextSize / sizeof(SecChar); /* Get buffer total len in character */ + return 0; + } + return -1; /* Next size is beyond max */ + } + return 0; +} + +/* Do not use localeconv()->decimal_pointif onlay support '.' */ +SECUREC_INLINE int SecIsFloatDecimal(SecChar ch) +{ + return (int)(ch == SECUREC_CHAR('.')); +} + +SECUREC_INLINE int SecInputFloatSign(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec) +{ + if (!SECUREC_FILED_WIDTH_ENOUGH(spec)) { + return 0; + } + spec->ch = SecGetChar(stream, &(spec->charCount)); + if (spec->ch == SECUREC_CHAR('+') || spec->ch == SECUREC_CHAR('-')) { + SECUREC_FILED_WIDTH_DEC(spec); /* Make sure the count after un get char is correct */ + if (spec->ch == SECUREC_CHAR('-')) { + floatSpec->floatStr[floatSpec->floatStrUsedLen] = SECUREC_CHAR('-'); + ++floatSpec->floatStrUsedLen; + if (SecExtendFloatLen(floatSpec) != 0) { + return -1; + } + } + } else { + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + } + return 0; +} + +SECUREC_INLINE int SecInputFloatDigit(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec) +{ + /* Now get integral part */ + while (SECUREC_FILED_WIDTH_ENOUGH(spec)) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + if (SecIsDigit(spec->ch) == 0) { + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + return 0; + } + SECUREC_FILED_WIDTH_DEC(spec); /* Must be behind un get char, otherwise the logic is incorrect */ + spec->numberState = SECUREC_NUMBER_STATE_STARTED; + floatSpec->floatStr[floatSpec->floatStrUsedLen] = (SecChar)spec->ch; + ++floatSpec->floatStrUsedLen; + if (SecExtendFloatLen(floatSpec) != 0) { + return -1; + } + } + return 0; +} + +/* +* Scan value of exponent. +* Return 0 OK +*/ +SECUREC_INLINE int SecInputFloatE(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec) +{ + if (SecInputFloatSign(stream, spec, floatSpec) == -1) { + return -1; + } + if (SecInputFloatDigit(stream, spec, floatSpec) != 0) { + return -1; + } + return 0; +} + +SECUREC_INLINE int SecInputFloatFractional(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec) +{ + if (SECUREC_FILED_WIDTH_ENOUGH(spec)) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + if (SecIsFloatDecimal((SecChar)spec->ch) == 0) { + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + return 0; + } + SECUREC_FILED_WIDTH_DEC(spec); /* Must be behind un get char, otherwise the logic is incorrect */ + /* Now check for decimal */ + floatSpec->floatStr[floatSpec->floatStrUsedLen] = (SecChar)spec->ch; + ++floatSpec->floatStrUsedLen; + if (SecExtendFloatLen(floatSpec) != 0) { + return -1; + } + if (SecInputFloatDigit(stream, spec, floatSpec) != 0) { + return -1; + } + } + return 0; +} + +SECUREC_INLINE int SecInputFloatExponent(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec) +{ + /* Now get exponent part */ + if (spec->numberState == SECUREC_NUMBER_STATE_STARTED && SECUREC_FILED_WIDTH_ENOUGH(spec)) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + if (spec->ch != SECUREC_CHAR('e') && spec->ch != SECUREC_CHAR('E')) { + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + return 0; + } + SECUREC_FILED_WIDTH_DEC(spec); /* Must be behind un get char, otherwise the logic is incorrect */ + floatSpec->floatStr[floatSpec->floatStrUsedLen] = SECUREC_CHAR('e'); + ++floatSpec->floatStrUsedLen; + if (SecExtendFloatLen(floatSpec) != 0) { + return -1; + } + if (SecInputFloatE(stream, spec, floatSpec) != 0) { + return -1; + } + } + return 0; +} + +/* +* Scan %f. +* Return 0 OK +*/ +SECUREC_INLINE int SecInputFloat(SecFileStream *stream, SecScanSpec *spec, SecFloatSpec *floatSpec) +{ + floatSpec->floatStrUsedLen = 0; + + /* The following code sequence is strict */ + if (SecInputFloatSign(stream, spec, floatSpec) != 0) { + return -1; + } + if (SecInputFloatDigit(stream, spec, floatSpec) != 0) { + return -1; + } + if (SecInputFloatFractional(stream, spec, floatSpec) != 0) { + return -1; + } + if (SecInputFloatExponent(stream, spec, floatSpec) != 0) { + return -1; + } + + /* Make sure have a string terminator, buffer is large enough */ + floatSpec->floatStr[floatSpec->floatStrUsedLen] = SECUREC_CHAR('\0'); + if (spec->numberState == SECUREC_NUMBER_STATE_STARTED) { + return 0; + } + return -1; +} +#endif + +#if (!defined(SECUREC_FOR_WCHAR) && SECUREC_HAVE_WCHART && SECUREC_HAVE_MBTOWC) || \ + (!defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION)) +/* LSD only multi-bytes string need isleadbyte() function */ +SECUREC_INLINE int SecIsLeadByte(SecInt ch) +{ + unsigned int c = (unsigned int)ch; +#if !(defined(_MSC_VER) || defined(_INC_WCTYPE)) + return (int)(c & 0x80U); /* Use bitwise operation to check if the most significant bit is 1 */ +#else + return (int)isleadbyte((int)(c & 0xffU)); /* Use bitwise operations to limit character values to valid ranges */ +#endif +} +#endif + +/* + * Parsing whether it is a wide character + */ +SECUREC_INLINE void SecUpdateWcharFlagByType(SecUnsignedChar ch, SecScanSpec *spec) +{ + if (spec->isWCharOrLong != 0) { + /* Wide character identifiers have been explicitly set by l or h flag */ + return; + } + + /* Set default flag */ +#if defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_WIN_FORMAT) + spec->isWCharOrLong = 1; /* On windows wide char version %c %s %[ is wide char */ +#else + spec->isWCharOrLong = -1; /* On linux all version %c %s %[ is multi char */ +#endif + + if (ch == SECUREC_CHAR('C') || ch == SECUREC_CHAR('S')) { +#if defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_WIN_FORMAT) + spec->isWCharOrLong = -1; /* On windows wide char version %C %S is multi char */ +#else + spec->isWCharOrLong = 1; /* On linux all version %C %S is wide char */ +#endif + } + + return; +} +/* + * Decode %l %ll + */ +SECUREC_INLINE void SecDecodeScanQualifierL(const SecUnsignedChar **format, SecScanSpec *spec) +{ + const SecUnsignedChar *fmt = *format; + if (*(fmt + 1) == SECUREC_CHAR('l')) { + spec->numberArgType = 1; + spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG; + ++fmt; + } else { + spec->numberWidth = SECUREC_NUM_WIDTH_LONG; +#if defined(SECUREC_ON_64BITS) && !(defined(SECUREC_COMPATIBLE_WIN_FORMAT)) + /* On window 64 system sizeof long is 32bit */ + spec->numberArgType = 1; +#endif + spec->isWCharOrLong = 1; + } + *format = fmt; +} + +/* + * Decode %I %I43 %I64 %Id %Ii %Io ... + * Set finishFlag to 1 finish Flag + */ +SECUREC_INLINE void SecDecodeScanQualifierI(const SecUnsignedChar **format, SecScanSpec *spec, int *finishFlag) +{ + const SecUnsignedChar *fmt = *format; + if ((*(fmt + 1) == SECUREC_CHAR('6')) && + (*(fmt + 2) == SECUREC_CHAR('4'))) { /* Offset 2 for I64 */ + spec->numberArgType = 1; + *format = *format + 2; /* Add 2 to skip I64 point to '4' next loop will inc */ + } else if ((*(fmt + 1) == SECUREC_CHAR('3')) && + (*(fmt + 2) == SECUREC_CHAR('2'))) { /* Offset 2 for I32 */ + *format = *format + 2; /* Add 2 to skip I32 point to '2' next loop will inc */ + } else if ((*(fmt + 1) == SECUREC_CHAR('d')) || + (*(fmt + 1) == SECUREC_CHAR('i')) || + (*(fmt + 1) == SECUREC_CHAR('o')) || + (*(fmt + 1) == SECUREC_CHAR('x')) || + (*(fmt + 1) == SECUREC_CHAR('X'))) { + spec->numberArgType = SecNumberArgType(sizeof(void *)); + } else { + /* For %I */ + spec->numberArgType = SecNumberArgType(sizeof(void *)); + *finishFlag = 1; + } +} + +SECUREC_INLINE int SecDecodeScanWidth(const SecUnsignedChar **format, SecScanSpec *spec) +{ + const SecUnsignedChar *fmt = *format; + while (SecIsDigit((SecInt)(int)(*fmt)) != 0) { + spec->widthSet = 1; + if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(spec->width)) { + return -1; + } + spec->width = (int)SECUREC_MUL_TEN((unsigned int)spec->width) + (unsigned char)(*fmt - SECUREC_CHAR('0')); + ++fmt; + } + *format = fmt; + return 0; +} + +/* + * Init default flags for each format. do not init ch this variable is context-dependent + */ +SECUREC_INLINE void SecSetDefaultScanSpec(SecScanSpec *spec) +{ + /* The ch and charCount member variables cannot be initialized here */ + spec->argPtr = NULL; + spec->arrayWidth = 0; + spec->number64 = 0; + spec->number = 0; + spec->numberWidth = SECUREC_NUM_WIDTH_INT; /* 0 = SHORT, 1 = int, > 1 long or L_DOUBLE */ + spec->numberArgType = 0; /* 1 for 64-bit integer, 0 otherwise */ + spec->width = 0; + spec->widthSet = 0; + spec->convChr = 0; + spec->oriConvChr = 0; + spec->isWCharOrLong = 0; + spec->suppress = 0; +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + spec->beyondMax = 0; +#endif + spec->negative = 0; + spec->numberState = SECUREC_NUMBER_STATE_DEFAULT; +} + +/* + * Decode qualifier %I %L %h ... + * Set finishFlag to 1 finish Flag + */ +SECUREC_INLINE void SecDecodeScanQualifier(const SecUnsignedChar **format, SecScanSpec *spec, int *finishFlag) +{ + switch (**format) { + case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('N'): + break; + case SECUREC_CHAR('h'): + --spec->numberWidth; /* The h for SHORT , hh for CHAR */ + spec->isWCharOrLong = -1; + break; +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + case SECUREC_CHAR('j'): + spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG; /* For intmax_t or uintmax_t */ + spec->numberArgType = 1; + break; + case SECUREC_CHAR('t'): /* fall-through */ /* FALLTHRU */ +#endif +#if SECUREC_IN_KERNEL + case SECUREC_CHAR('Z'): /* fall-through */ /* FALLTHRU */ +#endif + case SECUREC_CHAR('z'): +#ifdef SECUREC_ON_64BITS + spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG; + spec->numberArgType = 1; +#else + spec->numberWidth = SECUREC_NUM_WIDTH_LONG; +#endif + break; + case SECUREC_CHAR('L'): /* For long double */ /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('q'): + spec->numberWidth = SECUREC_NUM_WIDTH_LONG_LONG; + spec->numberArgType = 1; + break; + case SECUREC_CHAR('l'): + SecDecodeScanQualifierL(format, spec); + break; + case SECUREC_CHAR('w'): + spec->isWCharOrLong = 1; + break; + case SECUREC_CHAR('*'): + spec->suppress = 1; + break; + case SECUREC_CHAR('I'): + SecDecodeScanQualifierI(format, spec, finishFlag); + break; + default: + *finishFlag = 1; + break; + } +} +/* + * Decode width and qualifier in format + */ +SECUREC_INLINE int SecDecodeScanFlag(const SecUnsignedChar **format, SecScanSpec *spec) +{ + const SecUnsignedChar *fmt = *format; + int finishFlag = 0; + + do { + ++fmt; /* First skip % , next seek fmt */ + /* May %*6d , so put it inside the loop */ + if (SecDecodeScanWidth(&fmt, spec) != 0) { + return -1; + } + SecDecodeScanQualifier(&fmt, spec, &finishFlag); + } while (finishFlag == 0); + *format = fmt; + return 0; +} + +/* + * Judging whether a zeroing buffer is needed according to different formats + */ +SECUREC_INLINE int SecDecodeClearFormat(const SecUnsignedChar *format, int *convChr) +{ + const SecUnsignedChar *fmt = format; + /* To lowercase */ + int ch = SECUREC_TO_LOWERCASE(*fmt); + if (!(ch == 'c' || ch == 's' || ch == SECUREC_BRACE)) { + return -1; /* First argument is not a string type */ + } + if (ch == SECUREC_BRACE) { +#if !(defined(SECUREC_COMPATIBLE_WIN_FORMAT)) + if (*fmt == SECUREC_CHAR('{')) { + return -1; + } +#endif + ++fmt; + if (*fmt == SECUREC_CHAR('^')) { + ++fmt; + } + if (*fmt == SECUREC_CHAR(']')) { + ++fmt; + } + while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR(']')) { + ++fmt; + } + if (*fmt == SECUREC_CHAR('\0')) { + return -1; /* Trunc'd format string */ + } + } + *convChr = ch; + return 0; +} + +/* + * Add L'\0' for wchar string , add '\0' for char string + */ +SECUREC_INLINE void SecAddEndingZero(void *ptr, const SecScanSpec *spec) +{ + if (spec->suppress == 0) { + *(char *)ptr = '\0'; +#if SECUREC_HAVE_WCHART + if (spec->isWCharOrLong > 0) { + *(wchar_t UNALIGNED *)ptr = L'\0'; + } +#endif + } +} + +SECUREC_INLINE void SecDecodeClearArg(SecScanSpec *spec, va_list argList) +{ + va_list argListSave; /* Backup for argList value, this variable don't need initialized */ + (void)memset(&argListSave, 0, sizeof(va_list)); /* To clear e530 argListSave not initialized */ +#if defined(va_copy) + va_copy(argListSave, argList); +#elif defined(__va_copy) /* For vxworks */ + __va_copy(argListSave, argList); +#else + argListSave = argList; +#endif + spec->argPtr = (void *)va_arg(argListSave, void *); + /* Get the next argument, size of the array in characters */ + /* Use 0xffffffffUL mask to Support pass integer as array length */ + spec->arrayWidth = ((size_t)(va_arg(argListSave, size_t))) & 0xffffffffUL; + va_end(argListSave); + /* To clear e438 last value assigned not used , the compiler will optimize this code */ + (void)argListSave; +} + +#ifdef SECUREC_FOR_WCHAR +/* + * Clean up the first %s %c buffer to zero for wchar version + */ +void SecClearDestBufW(const wchar_t *buffer, const wchar_t *format, va_list argList) +#else +/* + * Clean up the first %s %c buffer to zero for char version + */ +void SecClearDestBuf(const char *buffer, const char *format, va_list argList) +#endif +{ + SecScanSpec spec; + int convChr = 0; + const SecUnsignedChar *fmt = (const SecUnsignedChar *)format; + if (fmt == NULL) { + return; + } + + /* Find first % */ + while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR('%')) { + ++fmt; + } + if (*fmt == SECUREC_CHAR('\0')) { + return; + } + + SecSetDefaultScanSpec(&spec); + if (SecDecodeScanFlag(&fmt, &spec) != 0) { + return; + } + + /* Update wchar flag for %S %C */ + SecUpdateWcharFlagByType(*fmt, &spec); + if (spec.suppress != 0) { + return; + } + + if (SecDecodeClearFormat(fmt, &convChr) != 0) { + return; + } + + if (buffer != NULL && *buffer != SECUREC_CHAR('\0') && convChr != 's') { + /* + * When buffer not empty just clear %s. + * Example call sscanf by argment of (" \n", "%s", s, sizeof(s)) + */ + return; + } + + SecDecodeClearArg(&spec, argList); + /* There is no need to judge the upper limit */ + if (spec.arrayWidth == 0 || spec.argPtr == NULL) { + return; + } + /* Clear one char */ + SecAddEndingZero(spec.argPtr, &spec); + return; +} + +/* + * Assign number to output buffer + */ +SECUREC_INLINE void SecAssignNumber(const SecScanSpec *spec) +{ + void *argPtr = spec->argPtr; + if (spec->numberArgType != 0) { +#if defined(SECUREC_VXWORKS_PLATFORM) +#if defined(SECUREC_VXWORKS_PLATFORM_COMP) + *(SecInt64 UNALIGNED *)argPtr = (SecInt64)(spec->number64); +#else + /* Take number64 as unsigned number unsigned to int clear Compile warning */ + *(SecInt64 UNALIGNED *)argPtr = *(SecUnsignedInt64 *)(&(spec->number64)); +#endif +#else + /* Take number64 as unsigned number */ + *(SecInt64 UNALIGNED *)argPtr = (SecInt64)(spec->number64); +#endif + return; + } + if (spec->numberWidth > SECUREC_NUM_WIDTH_INT) { + /* Take number as unsigned number */ + *(long UNALIGNED *)argPtr = (long)(spec->number); + } else if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) { + *(int UNALIGNED *)argPtr = (int)(spec->number); + } else if (spec->numberWidth == SECUREC_NUM_WIDTH_SHORT) { + /* Take number as unsigned number */ + *(short UNALIGNED *)argPtr = (short)(spec->number); + } else { /* < 0 for hh format modifier */ + /* Take number as unsigned number */ + *(char UNALIGNED *)argPtr = (char)(spec->number); + } +} + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) +/* + * Judge the long bit width + */ +SECUREC_INLINE int SecIsLongBitEqual(int bitNum) +{ + return (int)((unsigned int)bitNum == SECUREC_LONG_BIT_NUM); +} +#endif + +/* + * Convert hexadecimal characters to decimal value + */ +SECUREC_INLINE int SecHexValueOfChar(SecInt ch) +{ + /* Use isdigt Causing tool false alarms */ + return (int)((ch >= '0' && ch <= '9') ? ((unsigned char)ch - '0') : + ((((unsigned char)ch | (unsigned char)('a' - 'A')) - ('a')) + 10)); /* Adding 10 is to hex value */ +} + +/* + * Parse decimal character to integer for 32bit . + */ +static void SecDecodeNumberDecimal(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + unsigned long decimalEdge = SECUREC_MAX_32BITS_VALUE_DIV_TEN; +#ifdef SECUREC_ON_64BITS + if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) { + decimalEdge = (unsigned long)SECUREC_MAX_64BITS_VALUE_DIV_TEN; + } +#endif + if (spec->number > decimalEdge) { + spec->beyondMax = 1; + } +#endif + spec->number = SECUREC_MUL_TEN(spec->number); +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->number == SECUREC_MUL_TEN(decimalEdge)) { + /* This code is specially converted to unsigned long type for compatibility */ + SecUnsignedInt64 number64As = (unsigned long)SECUREC_MAX_64BITS_VALUE - spec->number; + if (number64As < (SecUnsignedInt64)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0'))) { + spec->beyondMax = 1; + } + } +#endif + spec->number += (unsigned long)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0')); +} + +/* + * Parse Hex character to integer for 32bit . + */ +static void SecDecodeNumberHex(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (SECUREC_LONG_HEX_BEYOND_MAX(spec->number)) { + spec->beyondMax = 1; + } +#endif + spec->number = SECUREC_MUL_SIXTEEN(spec->number); + spec->number += (unsigned long)(unsigned int)SecHexValueOfChar(spec->ch); +} + +/* + * Parse Octal character to integer for 32bit . + */ +static void SecDecodeNumberOctal(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (SECUREC_LONG_OCTAL_BEYOND_MAX(spec->number)) { + spec->beyondMax = 1; + } +#endif + spec->number = SECUREC_MUL_EIGHT(spec->number); + spec->number += (unsigned long)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0')); +} + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) +/* Compatible with integer negative values other than int */ +SECUREC_INLINE void SecFinishNumberNegativeOther(SecScanSpec *spec) +{ + if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) { + if (spec->number > SECUREC_MIN_LONG_NEG_VALUE) { + spec->number = SECUREC_MIN_LONG_NEG_VALUE; + } else { + spec->number = (unsigned long)(0U - spec->number); /* Wrap with unsigned long numbers */ + } + if (spec->beyondMax != 0) { + if (spec->numberWidth < SECUREC_NUM_WIDTH_INT) { + spec->number = 0; + } + if (spec->numberWidth == SECUREC_NUM_WIDTH_LONG) { + spec->number = SECUREC_MIN_LONG_NEG_VALUE; + } + } + } else { /* For o, u, x, X, p */ + spec->number = (unsigned long)(0U - spec->number); /* Wrap with unsigned long numbers */ + if (spec->beyondMax != 0) { + spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + } +} +/* Compatible processing of integer negative numbers */ +SECUREC_INLINE void SecFinishNumberNegativeInt(SecScanSpec *spec) +{ + if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) { +#ifdef SECUREC_ON_64BITS + if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) { + if ((spec->number > SECUREC_MIN_64BITS_NEG_VALUE)) { + spec->number = 0; + } else { + spec->number = (unsigned int)(0U - (unsigned int)spec->number); /* Wrap with unsigned int numbers */ + } + } +#else + if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH) != 0) { + if ((spec->number > SECUREC_MIN_32BITS_NEG_VALUE)) { + spec->number = SECUREC_MIN_32BITS_NEG_VALUE; + } else { + spec->number = (unsigned int)(0U - (unsigned int)spec->number); /* Wrap with unsigned int numbers */ + } + } +#endif + if (spec->beyondMax != 0) { +#ifdef SECUREC_ON_64BITS + if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) { + spec->number = 0; + } +#else + if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH) != 0) { + spec->number = SECUREC_MIN_32BITS_NEG_VALUE; + } +#endif + } + } else { /* For o, u, x, X ,p */ +#ifdef SECUREC_ON_64BITS + if (spec->number > SECUREC_MAX_32BITS_VALUE_INC) { + spec->number = SECUREC_MAX_32BITS_VALUE; + } else { + spec->number = (unsigned int)(0U - (unsigned int)spec->number); /* Wrap with unsigned int numbers */ + } +#else + spec->number = (unsigned int)(0U - (unsigned int)spec->number); /* Wrap with unsigned int numbers */ +#endif + if (spec->beyondMax != 0) { + spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + } +} + +/* Compatible with integer positive values other than int */ +SECUREC_INLINE void SecFinishNumberPositiveOther(SecScanSpec *spec) +{ + if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) { + if (spec->number > SECUREC_MAX_LONG_POS_VALUE) { + spec->number = SECUREC_MAX_LONG_POS_VALUE; + } + if ((spec->beyondMax != 0 && spec->numberWidth < SECUREC_NUM_WIDTH_INT)) { + spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + if (spec->beyondMax != 0 && spec->numberWidth == SECUREC_NUM_WIDTH_LONG) { + spec->number = SECUREC_MAX_LONG_POS_VALUE; + } + } else { + if (spec->beyondMax != 0) { + spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + } +} + +/* Compatible processing of integer positive numbers */ +SECUREC_INLINE void SecFinishNumberPositiveInt(SecScanSpec *spec) +{ + if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) { +#ifdef SECUREC_ON_64BITS + if (SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) { + if (spec->number > SECUREC_MAX_64BITS_POS_VALUE) { + spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE; + } + } + if (spec->beyondMax != 0 && SecIsLongBitEqual(SECUREC_LP64_BIT_WIDTH) != 0) { + spec->number = (unsigned long)SECUREC_MAX_64BITS_VALUE; + } +#else + if (SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH) != 0) { + if (spec->number > SECUREC_MAX_32BITS_POS_VALUE) { + spec->number = SECUREC_MAX_32BITS_POS_VALUE; + } + } + if (spec->beyondMax != 0 && SecIsLongBitEqual(SECUREC_LP32_BIT_WIDTH) != 0) { + spec->number = SECUREC_MAX_32BITS_POS_VALUE; + } +#endif + } else { /* For o,u,x,X,p */ + if (spec->beyondMax != 0) { + spec->number = SECUREC_MAX_32BITS_VALUE; + } + } +} + +#endif + +/* + * Parse decimal character to integer for 64bit . + */ +static void SecDecodeNumber64Decimal(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->number64 > SECUREC_MAX_64BITS_VALUE_DIV_TEN) { + spec->beyondMax = 1; + } +#endif + spec->number64 = SECUREC_MUL_TEN(spec->number64); +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->number64 == SECUREC_MAX_64BITS_VALUE_CUT_LAST_DIGIT) { + SecUnsignedInt64 number64As = (SecUnsignedInt64)SECUREC_MAX_64BITS_VALUE - spec->number64; + if (number64As < (SecUnsignedInt64)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0'))) { + spec->beyondMax = 1; + } + } +#endif + spec->number64 += (SecUnsignedInt64)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0')); +} + +/* + * Parse Hex character to integer for 64bit . + */ +static void SecDecodeNumber64Hex(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (SECUREC_QWORD_HEX_BEYOND_MAX(spec->number64)) { + spec->beyondMax = 1; + } +#endif + spec->number64 = SECUREC_MUL_SIXTEEN(spec->number64); + spec->number64 += (SecUnsignedInt64)(unsigned int)SecHexValueOfChar(spec->ch); +} + +/* + * Parse Octal character to integer for 64bit . + */ +static void SecDecodeNumber64Octal(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (SECUREC_QWORD_OCTAL_BEYOND_MAX(spec->number64)) { + spec->beyondMax = 1; + } +#endif + spec->number64 = SECUREC_MUL_EIGHT(spec->number64); + spec->number64 += (SecUnsignedInt64)((SecUnsignedInt)spec->ch - SECUREC_CHAR('0')); +} + +#define SECUREC_DECODE_NUMBER_FUNC_NUM 2 + +/* + * Parse 64-bit integer formatted input, return 0 when ch is a number. + */ +SECUREC_INLINE int SecDecodeNumber(SecScanSpec *spec) +{ + /* Function name cannot add address symbol, causing 546 alarm */ + static void (*secDecodeNumberHex[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = { + SecDecodeNumberHex, SecDecodeNumber64Hex + }; + static void (*secDecodeNumberOctal[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = { + SecDecodeNumberOctal, SecDecodeNumber64Octal + }; + static void (*secDecodeNumberDecimal[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = { + SecDecodeNumberDecimal, SecDecodeNumber64Decimal + }; + if (spec->convChr == 'x' || spec->convChr == 'p') { + if (SecIsXdigit(spec->ch) != 0) { + (*secDecodeNumberHex[spec->numberArgType])(spec); + } else { + return -1; + } + return 0; + } + if (SecIsDigit(spec->ch) == 0) { + return -1; + } + if (spec->convChr == 'o') { + if (spec->ch < SECUREC_CHAR('8')) { /* Octal maximum limit '8' */ + (*secDecodeNumberOctal[spec->numberArgType])(spec); + } else { + return -1; + } + } else { /* The convChr is 'd' */ + (*secDecodeNumberDecimal[spec->numberArgType])(spec); + } + return 0; +} + +/* + * Complete the final 32-bit integer formatted input + */ +static void SecFinishNumber(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->negative != 0) { + if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) { + SecFinishNumberNegativeInt(spec); + } else { + SecFinishNumberNegativeOther(spec); + } + } else { + if (spec->numberWidth == SECUREC_NUM_WIDTH_INT) { + SecFinishNumberPositiveInt(spec); + } else { + SecFinishNumberPositiveOther(spec); + } + } +#else + if (spec->negative != 0) { +#if defined(__hpux) + if (spec->oriConvChr != 'p') { + spec->number = (unsigned long)(0U - spec->number); /* Wrap with unsigned long numbers */ + } +#else + spec->number = (unsigned long)(0U - spec->number); /* Wrap with unsigned long numbers */ +#endif + } +#endif + return; +} + +/* + * Complete the final 64-bit integer formatted input + */ +static void SecFinishNumber64(SecScanSpec *spec) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && !(defined(SECUREC_ON_UNIX))) + if (spec->negative != 0) { + if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) { + if (spec->number64 > SECUREC_MIN_64BITS_NEG_VALUE) { + spec->number64 = SECUREC_MIN_64BITS_NEG_VALUE; + } else { + spec->number64 = (SecUnsignedInt64)(0U - spec->number64); /* Wrap with unsigned int64 numbers */ + } + if (spec->beyondMax != 0) { + spec->number64 = SECUREC_MIN_64BITS_NEG_VALUE; + } + } else { /* For o, u, x, X, p */ + spec->number64 = (SecUnsignedInt64)(0U - spec->number64); /* Wrap with unsigned int64 numbers */ + if (spec->beyondMax != 0) { + spec->number64 = SECUREC_MAX_64BITS_VALUE; + } + } + } else { + if (SECUREC_CONVERT_IS_SIGNED(spec->oriConvChr)) { + if (spec->number64 > SECUREC_MAX_64BITS_POS_VALUE) { + spec->number64 = SECUREC_MAX_64BITS_POS_VALUE; + } + if (spec->beyondMax != 0) { + spec->number64 = SECUREC_MAX_64BITS_POS_VALUE; + } + } else { + if (spec->beyondMax != 0) { + spec->number64 = SECUREC_MAX_64BITS_VALUE; + } + } + } +#else + if (spec->negative != 0) { +#if defined(__hpux) + if (spec->oriConvChr != 'p') { + spec->number64 = (SecUnsignedInt64)(0U - spec->number64); /* Wrap with unsigned int64 numbers */ + } +#else + spec->number64 = (SecUnsignedInt64)(0U - spec->number64); /* Wrap with unsigned int64 numbers */ +#endif + } +#endif + return; +} + +#if SECUREC_ENABLE_SCANF_FILE + +/* + * Adjust the pointer position of the file stream + */ +SECUREC_INLINE void SecSeekStream(SecFileStream *stream) +{ + if (stream->count == 0) { + if (feof(stream->pf) != 0) { + /* File pointer at the end of file, don't need to seek back */ + stream->base[0] = '\0'; + return; + } + } + /* Seek to original position, for file read, but nothing to input */ + if (fseek(stream->pf, stream->oriFilePos, SEEK_SET) != 0) { + /* Seek failed, ignore it */ + stream->oriFilePos = 0; + return; + } + + if (stream->fileRealRead > 0) { /* Do not seek without input data */ +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + size_t residue = stream->fileRealRead % SECUREC_BUFFERED_BLOK_SIZE; + size_t loops; + for (loops = 0; loops < (stream->fileRealRead / SECUREC_BUFFERED_BLOK_SIZE); ++loops) { + if (fread(stream->base, (size_t)SECUREC_BUFFERED_BLOK_SIZE, (size_t)1, stream->pf) != (size_t)1) { + break; + } + } + if (residue != 0) { + long curFilePos; + if (fread(stream->base, residue, (size_t)1, stream->pf) != (size_t)1) { + return; + } + curFilePos = ftell(stream->pf); + if (curFilePos < stream->oriFilePos || + (size_t)(unsigned long)(curFilePos - stream->oriFilePos) < stream->fileRealRead) { + /* Try to remedy the problem */ + (void)fseek(stream->pf, (long)stream->fileRealRead, SEEK_CUR); + } + } +#else + /* Seek from oriFilePos. Regardless of the integer sign problem, call scanf will not read very large data */ + if (fseek(stream->pf, (long)stream->fileRealRead, SEEK_CUR) != 0) { + /* Seek failed, ignore it */ + stream->oriFilePos = 0; + return; + } +#endif + } + return; +} + +/* + * Adjust the pointer position of the file stream and free memory + */ +SECUREC_INLINE void SecAdjustStream(SecFileStream *stream) +{ + if (stream != NULL && (stream->flag & SECUREC_FILE_STREAM_FLAG) != 0 && stream->base != NULL) { + SecSeekStream(stream); + SECUREC_FREE(stream->base); + stream->base = NULL; + } + return; +} +#endif + +SECUREC_INLINE void SecSkipSpaceFormat(const SecUnsignedChar **format) +{ + const SecUnsignedChar *fmt = *format; + while (SecIsSpace((SecInt)(int)(*fmt)) != 0) { + ++fmt; + } + *format = fmt; +} + +#if !defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION) +/* + * Handling multi-character characters + */ +SECUREC_INLINE int SecDecodeLeadByte(SecScanSpec *spec, const SecUnsignedChar **format, SecFileStream *stream) +{ +#if SECUREC_HAVE_MBTOWC + const SecUnsignedChar *fmt = *format; + int ch1 = (int)spec->ch; + int ch2 = SecGetChar(stream, &(spec->charCount)); + spec->ch = (SecInt)ch2; + if (*fmt == SECUREC_CHAR('\0') || (int)(*fmt) != ch2) { + /* LSD in console mode, ungetc twice may cause problem */ + SecUnGetChar(ch2, stream, &(spec->charCount)); + SecUnGetChar(ch1, stream, &(spec->charCount)); + return -1; + } + ++fmt; + if ((unsigned int)MB_CUR_MAX >= SECUREC_UTF8_BOM_HEADER_SIZE && + (((unsigned char)ch1 & SECUREC_UTF8_LEAD_1ST) == SECUREC_UTF8_LEAD_1ST) && + (((unsigned char)ch2 & SECUREC_UTF8_LEAD_2ND) == SECUREC_UTF8_LEAD_2ND)) { + /* This char is very likely to be a UTF-8 char */ + wchar_t tempWChar; + char temp[SECUREC_MULTI_BYTE_MAX_LEN]; + int ch3 = (int)SecGetChar(stream, &(spec->charCount)); + spec->ch = (SecInt)ch3; + if (*fmt == SECUREC_CHAR('\0') || (int)(*fmt) != ch3) { + SecUnGetChar(ch3, stream, &(spec->charCount)); + return -1; + } + temp[0] = (char)ch1; + temp[1] = (char)ch2; /* 1 index of second character */ + temp[2] = (char)ch3; /* 2 index of third character */ + temp[3] = '\0'; /* 3 of string terminator position */ + if (mbtowc(&tempWChar, temp, sizeof(temp)) > 0) { + /* Succeed */ + ++fmt; + --spec->charCount; + } else { + SecUnGetChar(ch3, stream, &(spec->charCount)); + } + } + --spec->charCount; /* Only count as one character read */ + *format = fmt; + return 0; +#else + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + (void)format; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + return -1; +#endif +} +#endif + +/* + * Resolving sequence of characters from %[ format, format wile point to ']' + */ +SECUREC_INLINE int SecSetupBracketTable(const SecUnsignedChar **format, SecBracketTable *bracketTable) +{ + const SecUnsignedChar *fmt = *format; + SecUnsignedChar prevChar = 0; +#if !(defined(SECUREC_COMPATIBLE_WIN_FORMAT)) + if (*fmt == SECUREC_CHAR('{')) { + return -1; + } +#endif + /* For building "table" data */ + ++fmt; /* Skip [ */ + bracketTable->mask = 0; /* Set all bits to 0 */ + if (*fmt == SECUREC_CHAR('^')) { + ++fmt; + bracketTable->mask = (unsigned char)0xffU; /* Use 0xffU to set all bits to 1 */ + } + if (*fmt == SECUREC_CHAR(']')) { + prevChar = SECUREC_CHAR(']'); + ++fmt; + SecBracketSetBit(bracketTable->table, SECUREC_CHAR(']')); + } + while (*fmt != SECUREC_CHAR('\0') && *fmt != SECUREC_CHAR(']')) { + SecUnsignedChar expCh = *fmt; + ++fmt; + if (expCh != SECUREC_CHAR('-') || prevChar == 0 || *fmt == SECUREC_CHAR(']')) { + /* Normal character */ + prevChar = expCh; + SecBracketSetBit(bracketTable->table, expCh); + } else { + /* For %[a-z] */ + expCh = *fmt; /* Get end of range */ + ++fmt; + if (prevChar <= expCh) { /* %[a-z] %[a-a] */ + SecBracketSetBitRange(bracketTable->table, prevChar, expCh); + } else { + /* For %[z-a] */ +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + /* Swap start and end characters */ + SecBracketSetBitRange(bracketTable->table, expCh, prevChar); +#else + SecBracketSetBit(bracketTable->table, SECUREC_CHAR('-')); + SecBracketSetBit(bracketTable->table, expCh); +#endif + } + prevChar = 0; + } + } + *format = fmt; + return 0; +} + +#ifdef SECUREC_FOR_WCHAR +SECUREC_INLINE int SecInputForWchar(SecScanSpec *spec) +{ + void *endPtr = spec->argPtr; + if (spec->isWCharOrLong > 0) { + *(wchar_t UNALIGNED *)endPtr = (wchar_t)spec->ch; + endPtr = (wchar_t *)endPtr + 1; + --spec->arrayWidth; + } else { +#if SECUREC_HAVE_WCTOMB + int temp; + char tmpBuf[SECUREC_MB_LEN + 1]; + SECUREC_MASK_MSVC_CRT_WARNING temp = wctomb(tmpBuf, (wchar_t)spec->ch); + SECUREC_END_MASK_MSVC_CRT_WARNING + if (temp <= 0 || (size_t)(unsigned int)temp > sizeof(tmpBuf)) { + /* If wctomb error, then ignore character */ + return 0; + } + if (((size_t)(unsigned int)temp) > spec->arrayWidth) { + return -1; + } + if (memcpy_s(endPtr, spec->arrayWidth, tmpBuf, (size_t)(unsigned int)temp) != EOK) { + return -1; + } + endPtr = (char *)endPtr + temp; + spec->arrayWidth -= (size_t)(unsigned int)temp; +#else + return -1; +#endif + } + spec->argPtr = endPtr; + return 0; +} +#endif + +#ifndef SECUREC_FOR_WCHAR +#if SECUREC_HAVE_WCHART +SECUREC_INLINE wchar_t SecConvertInputCharToWchar(SecScanSpec *spec, SecFileStream *stream) +{ + wchar_t tempWChar = L'?'; /* Set default char is ? */ +#if SECUREC_HAVE_MBTOWC + char temp[SECUREC_MULTI_BYTE_MAX_LEN + 1]; + temp[0] = (char)spec->ch; + temp[1] = '\0'; +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + if (SecIsLeadByte(spec->ch) != 0) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + temp[1] = (char)spec->ch; + temp[2] = '\0'; /* 2 of string terminator position */ + } + if (mbtowc(&tempWChar, temp, sizeof(temp)) <= 0) { + /* No string termination error for tool */ + tempWChar = L'?'; + } +#else + if (SecIsLeadByte(spec->ch) != 0) { + int convRes = 0; + int di = 1; + /* On Linux like system, the string is encoded in UTF-8 */ + while (convRes <= 0 && di < (int)MB_CUR_MAX && di < SECUREC_MULTI_BYTE_MAX_LEN) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + temp[di] = (char)spec->ch; + ++di; + temp[di] = '\0'; + convRes = mbtowc(&tempWChar, temp, sizeof(temp)); + } + if (convRes <= 0) { + tempWChar = L'?'; + } + } else { + if (mbtowc(&tempWChar, temp, sizeof(temp)) <= 0) { + tempWChar = L'?'; + } + } +#endif +#else + (void)spec; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + (void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */ +#endif /* SECUREC_HAVE_MBTOWC */ + + return tempWChar; +} +#endif /* SECUREC_HAVE_WCHART */ + +SECUREC_INLINE int SecInputForChar(SecScanSpec *spec, SecFileStream *stream) +{ + void *endPtr = spec->argPtr; + if (spec->isWCharOrLong > 0) { +#if SECUREC_HAVE_WCHART + *(wchar_t UNALIGNED *)endPtr = SecConvertInputCharToWchar(spec, stream); + endPtr = (wchar_t *)endPtr + 1; + --spec->arrayWidth; +#else + (void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + return -1; +#endif + } else { + *(char *)endPtr = (char)spec->ch; + endPtr = (char *)endPtr + 1; + --spec->arrayWidth; + } + spec->argPtr = endPtr; + return 0; +} +#endif + +/* + * Scan digital part of %d %i %o %u %x %p. + * Return 0 OK + */ +SECUREC_INLINE int SecInputNumberDigital(SecFileStream *stream, SecScanSpec *spec) +{ + static void (*secFinishNumber[SECUREC_DECODE_NUMBER_FUNC_NUM])(SecScanSpec *spec) = { + SecFinishNumber, SecFinishNumber64 + }; + while (SECUREC_FILED_WIDTH_ENOUGH(spec)) { + spec->ch = SecGetChar(stream, &(spec->charCount)); + /* Decode ch to number */ + if (SecDecodeNumber(spec) != 0) { + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + break; + } + SECUREC_FILED_WIDTH_DEC(spec); /* Must be behind un get char, otherwise the logic is incorrect */ + spec->numberState = SECUREC_NUMBER_STATE_STARTED; + } + /* Handling integer negative numbers and beyond max */ + (*secFinishNumber[spec->numberArgType])(spec); + if (spec->numberState == SECUREC_NUMBER_STATE_STARTED) { + return 0; + } + return -1; +} + +/* + * Scan %d %i %o %u %x %p. + * Return 0 OK + */ +SECUREC_INLINE int SecInputNumber(SecFileStream *stream, SecScanSpec *spec) +{ + /* Character already read */ + if (spec->ch == SECUREC_CHAR('+') || spec->ch == SECUREC_CHAR('-')) { + if (spec->ch == SECUREC_CHAR('-')) { + spec->negative = 1; +#if SECUREC_IN_KERNEL + /* In kernel Refuse to enter negative number */ + if (SECUREC_CONVERT_IS_UNSIGNED(spec->oriConvChr)) { + return -1; + } +#endif + } + SECUREC_FILED_WIDTH_DEC(spec); /* Do not need to check width here, must be greater than 0 */ + spec->ch = SecGetChar(stream, &(spec->charCount)); /* Eat + or - */ + spec->ch = SecGetChar(stream, &(spec->charCount)); /* Get next character, used for the '0' judgments */ + SecUnGetChar(spec->ch, stream, &(spec->charCount)); /* Not sure if it was actually read, so push back */ + } + + if (spec->oriConvChr == 'i') { + spec->convChr = 'd'; /* The i could be d, o, or x, use d as default */ + } + + if (spec->ch == SECUREC_CHAR('0') && (spec->oriConvChr == 'x' || spec->oriConvChr == 'i') && + SECUREC_FILED_WIDTH_ENOUGH(spec)) { + /* Input string begin with 0, may be 0x123 0X123 0123 0x 01 0yy 09 0 0ab 00 */ + SECUREC_FILED_WIDTH_DEC(spec); + spec->ch = SecGetChar(stream, &(spec->charCount)); /* ch is '0' */ + + /* Read only '0' due to width limitation */ + if (!SECUREC_FILED_WIDTH_ENOUGH(spec)) { + /* The number or number64 in spec has been set 0 */ + return 0; + } + + spec->ch = SecGetChar(stream, &(spec->charCount)); /* Get next char to check x or X, do not dec width */ + if ((SecChar)spec->ch == SECUREC_CHAR('x') || (SecChar)spec->ch == SECUREC_CHAR('X')) { + spec->convChr = 'x'; + SECUREC_FILED_WIDTH_DEC(spec); /* Make incorrect width for x or X */ + } else { + if (spec->oriConvChr == 'i') { + spec->convChr = 'o'; + } + /* For "0y" "08" "01" "0a" ... ,push the 'y' '8' '1' 'a' back */ + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + /* Since 0 has been read, it indicates that a valid character has been read */ + spec->numberState = SECUREC_NUMBER_STATE_STARTED; + } + } + return SecInputNumberDigital(stream, spec); +} + +/* + * Scan %c %s %[ + * Return 0 OK + */ +SECUREC_INLINE int SecInputString(SecFileStream *stream, SecScanSpec *spec, + const SecBracketTable *bracketTable, int *doneCount) +{ + void *startPtr = spec->argPtr; + int suppressed = 0; + int errNoMem = 0; + + while (SECUREC_FILED_WIDTH_ENOUGH(spec)) { + SECUREC_FILED_WIDTH_DEC(spec); + spec->ch = SecGetChar(stream, &(spec->charCount)); + /* + * The char condition or string condition and bracket condition. + * Only supports wide characters with a maximum length of two bytes + */ + if (spec->ch != SECUREC_EOF && (SecCanInputCharacter(spec->convChr) != 0 || + SecCanInputString(spec->convChr, spec->ch) != 0 || + SecCanInputForBracket(spec->convChr, spec->ch, bracketTable) != 0)) { + if (spec->suppress != 0) { + /* Used to identify processed data for %*, use argPtr to identify will cause 613, so use suppressed */ + suppressed = 1; + continue; + } + /* Now suppress is not set */ + if (spec->arrayWidth == 0) { + errNoMem = 1; /* We have exhausted the user's buffer */ + break; + } +#ifdef SECUREC_FOR_WCHAR + errNoMem = SecInputForWchar(spec); +#else + errNoMem = SecInputForChar(spec, stream); +#endif + if (errNoMem != 0) { + break; + } + } else { + SecUnGetChar(spec->ch, stream, &(spec->charCount)); + break; + } + } + + if (errNoMem != 0) { + /* In case of error, blank out the input buffer */ + SecAddEndingZero(startPtr, spec); + return -1; + } + if ((spec->suppress != 0 && suppressed == 0) || + (spec->suppress == 0 && startPtr == spec->argPtr)) { + /* No input was scanned */ + return -1; + } + if (spec->convChr != 'c') { + /* Add null-terminate for strings */ + SecAddEndingZero(spec->argPtr, spec); + } + if (spec->suppress == 0) { + *doneCount = *doneCount + 1; + } + return 0; +} + +#ifdef SECUREC_FOR_WCHAR +/* + * Alloce buffer for wchar version of %[. + * Return 0 OK + */ +SECUREC_INLINE int SecAllocBracketTable(SecBracketTable *bracketTable) +{ + if (bracketTable->table == NULL) { + /* Table should be freed after use */ + bracketTable->table = (unsigned char *)SECUREC_MALLOC(SECUREC_BRACKET_TABLE_SIZE); + if (bracketTable->table == NULL) { + return -1; + } + } + return 0; +} + +/* + * Free buffer for wchar version of %[ + */ +SECUREC_INLINE void SecFreeBracketTable(SecBracketTable *bracketTable) +{ + if (bracketTable->table != NULL) { + SECUREC_FREE(bracketTable->table); + bracketTable->table = NULL; + } +} +#endif + +#ifdef SECUREC_FOR_WCHAR +/* + * Formatting input core functions for wchar version.Called by a function such as vswscanf_s + */ +int SecInputSW(SecFileStream *stream, const wchar_t *cFormat, va_list argList) +#else +/* + * Formatting input core functions for char version.Called by a function such as vsscanf_s + */ +int SecInputS(SecFileStream *stream, const char *cFormat, va_list argList) +#endif +{ + const SecUnsignedChar *format = (const SecUnsignedChar *)cFormat; + SecBracketTable bracketTable = SECUREC_INIT_BRACKET_TABLE; + SecScanSpec spec; + int doneCount = 0; + int formatError = 0; + int paraIsNull = 0; + int match = 0; /* When % is found , inc this value */ + int errRet = 0; +#if SECUREC_ENABLE_SCANF_FLOAT + SecFloatSpec floatSpec; + SecInitFloatSpec(&floatSpec); +#endif + spec.ch = 0; /* Need to initialize to 0 */ + spec.charCount = 0; /* Need to initialize to 0 */ + + /* Format must not NULL, use err < 1 to claer 845 */ + while (errRet < 1 && *format != SECUREC_CHAR('\0')) { + /* Skip space in format and space in input */ + if (SecIsSpace((SecInt)(int)(*format)) != 0) { + /* Read first no space char */ + spec.ch = SecSkipSpaceChar(stream, &(spec.charCount)); + /* Read the EOF cannot be returned directly here, because the case of " %n" needs to be handled */ + /* Put fist no space char backup. put EOF back is also OK, and to modify the character count */ + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + SecSkipSpaceFormat(&format); + continue; + } + + if (*format != SECUREC_CHAR('%')) { + spec.ch = SecGetChar(stream, &(spec.charCount)); + if ((int)(*format) != (int)(spec.ch)) { + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + break; + } + ++format; +#if !defined(SECUREC_FOR_WCHAR) && defined(SECUREC_COMPATIBLE_VERSION) + if (SecIsLeadByte(spec.ch) != 0) { + if (SecDecodeLeadByte(&spec, &format, stream) != 0) { + break; + } + } +#endif + continue; + } + + /* Now *format is % */ + /* Set default value for each % */ + SecSetDefaultScanSpec(&spec); + if (SecDecodeScanFlag(&format, &spec) != 0) { + formatError = 1; + ++errRet; + continue; + } + if (!SECUREC_FILED_WIDTH_ENOUGH(&spec)) { + /* 0 width in format */ + ++errRet; + continue; + } + + /* Update wchar flag for %S %C */ + SecUpdateWcharFlagByType(*format, &spec); + + spec.convChr = SECUREC_TO_LOWERCASE(*format); + spec.oriConvChr = spec.convChr; /* convChr may be modified to handle integer logic */ + if (spec.convChr != 'n') { + if (spec.convChr != 'c' && spec.convChr != SECUREC_BRACE) { + spec.ch = SecSkipSpaceChar(stream, &(spec.charCount)); + } else { + spec.ch = SecGetChar(stream, &(spec.charCount)); + } + if (spec.ch == SECUREC_EOF) { + ++errRet; + continue; + } + } + + /* Now no 0 width in format and get one char from input */ + switch (spec.oriConvChr) { + case 'c': /* Also 'C' */ + if (spec.widthSet == 0) { + spec.widthSet = 1; + spec.width = 1; + } + /* fall-through */ /* FALLTHRU */ + case 's': /* Also 'S': */ + /* fall-through */ /* FALLTHRU */ + case SECUREC_BRACE: + /* Unset last char to stream */ + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + /* Check dest buffer and size */ + if (spec.suppress == 0) { + spec.argPtr = (void *)va_arg(argList, void *); + if (spec.argPtr == NULL) { + paraIsNull = 1; + ++errRet; + continue; + } + /* Get the next argument, size of the array in characters */ +#ifdef SECUREC_ON_64BITS + /* Use 0xffffffffUL mask to Support pass integer as array length */ + spec.arrayWidth = ((size_t)(va_arg(argList, size_t))) & 0xffffffffUL; +#else /* !SECUREC_ON_64BITS */ + spec.arrayWidth = (size_t)va_arg(argList, size_t); +#endif + if (SECUREC_ARRAY_WIDTH_IS_WRONG(spec)) { + /* Do not clear buffer just go error */ + ++errRet; + continue; + } + /* One element is needed for '\0' for %s and %[ */ + if (spec.convChr != 'c') { + --spec.arrayWidth; + } + } else { + /* Set argPtr to NULL is necessary, in supress mode we don't use argPtr to store data */ + spec.argPtr = NULL; + } + + if (spec.convChr == SECUREC_BRACE) { + /* Malloc when first %[ is meet for wchar version */ +#ifdef SECUREC_FOR_WCHAR + if (SecAllocBracketTable(&bracketTable) != 0) { + ++errRet; + continue; + } +#endif + (void)memset(bracketTable.table, 0, (size_t)SECUREC_BRACKET_TABLE_SIZE); + if (SecSetupBracketTable(&format, &bracketTable) != 0) { + ++errRet; + continue; + } + + if (*format == SECUREC_CHAR('\0')) { + /* Default add string terminator */ + SecAddEndingZero(spec.argPtr, &spec); + ++errRet; + /* Truncated format */ + continue; + } + } + + /* Set completed. Now read string or character */ + if (SecInputString(stream, &spec, &bracketTable, &doneCount) != 0) { + ++errRet; + continue; + } + break; + case 'p': + /* Make %hp same as %p */ + spec.numberWidth = SECUREC_NUM_WIDTH_INT; +#ifdef SECUREC_ON_64BITS + spec.numberArgType = 1; +#endif + /* fall-through */ /* FALLTHRU */ + case 'o': /* fall-through */ /* FALLTHRU */ + case 'u': /* fall-through */ /* FALLTHRU */ + case 'd': /* fall-through */ /* FALLTHRU */ + case 'i': /* fall-through */ /* FALLTHRU */ + case 'x': + /* Unset last char to stream */ + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + if (SecInputNumber(stream, &spec) != 0) { + ++errRet; + continue; + } + if (spec.suppress == 0) { + spec.argPtr = (void *)va_arg(argList, void *); + if (spec.argPtr == NULL) { + paraIsNull = 1; + ++errRet; + continue; + } + SecAssignNumber(&spec); + ++doneCount; + } + break; + case 'n': /* Char count */ + if (spec.suppress == 0) { + spec.argPtr = (void *)va_arg(argList, void *); + if (spec.argPtr == NULL) { + paraIsNull = 1; + ++errRet; + continue; + } + spec.number = (unsigned long)(unsigned int)(spec.charCount); + spec.numberArgType = 0; + SecAssignNumber(&spec); + } + break; + case 'e': /* fall-through */ /* FALLTHRU */ + case 'f': /* fall-through */ /* FALLTHRU */ + case 'g': /* Scan a float */ + /* Unset last char to stream */ + SecUnGetChar(spec.ch, stream, &(spec.charCount)); +#if SECUREC_ENABLE_SCANF_FLOAT + if (SecInputFloat(stream, &spec, &floatSpec) != 0) { + ++errRet; + continue; + } + if (spec.suppress == 0) { + spec.argPtr = (void *)va_arg(argList, void *); + if (spec.argPtr == NULL) { + ++errRet; + paraIsNull = 1; + continue; + } +#ifdef SECUREC_FOR_WCHAR + if (SecAssignFloatW(&floatSpec, &spec) != 0) { + ++errRet; + continue; + } +#else + SecAssignFloat(floatSpec.floatStr, spec.numberWidth, spec.argPtr); +#endif + ++doneCount; + } + break; +#else /* SECUREC_ENABLE_SCANF_FLOAT */ + ++errRet; + continue; +#endif + default: + if ((int)(*format) != (int)spec.ch) { + SecUnGetChar(spec.ch, stream, &(spec.charCount)); + formatError = 1; + ++errRet; + continue; + } else { + --match; /* Compensate for the self-increment of the following code */ + } + break; + } + ++match; + ++format; + } + +#ifdef SECUREC_FOR_WCHAR + SecFreeBracketTable(&bracketTable); +#endif + +#if SECUREC_ENABLE_SCANF_FLOAT + SecFreeFloatSpec(&floatSpec, &doneCount); +#endif + +#if SECUREC_ENABLE_SCANF_FILE + SecAdjustStream(stream); +#endif + + if (spec.ch == SECUREC_EOF) { + return ((doneCount != 0 || match != 0) ? doneCount : SECUREC_SCANF_EINVAL); + } + if (formatError != 0 || paraIsNull != 0) { + /* Invalid Input Format or parameter, but not meet EOF */ + return SECUREC_SCANF_ERROR_PARA; + } + return doneCount; +} + +#if SECUREC_ENABLE_SCANF_FILE +#if SECUREC_USE_STD_UNGETC +/* + * Get char from stream use std function + */ +SECUREC_INLINE SecInt SecGetCharFromStream(const SecFileStream *stream) +{ + SecInt ch; + ch = SECUREC_GETC(stream->pf); + return ch; +} +#else +/* + * Get char from stream or buffer + */ +SECUREC_INLINE SecInt SecGetCharFromStream(SecFileStream *stream) +{ + SecInt ch; + if (stream->fUnGet == 1) { + ch = (SecInt) stream->lastChar; + stream->fUnGet = 0; + } else { + ch = SECUREC_GETC(stream->pf); + stream->lastChar = (unsigned int)ch; + } + return ch; +} +#endif + +/* + * Try to read the BOM header, when meet a BOM head, discard it, then data is Aligned to base + */ +SECUREC_INLINE void SecReadAndSkipBomHeader(SecFileStream *stream) +{ + /* Use size_t type conversion to clean e747 */ + stream->count = fread(stream->base, (size_t)1, (size_t)SECUREC_BOM_HEADER_SIZE, stream->pf); + if (stream->count > SECUREC_BOM_HEADER_SIZE) { + stream->count = 0; + } + if (SECUREC_BEGIN_WITH_BOM(stream->base, stream->count)) { + /* It's BOM header, discard it */ + stream->count = 0; + } +} + +/* + * Get char from file stream or buffer + */ +SECUREC_INLINE SecInt SecGetCharFromFile(SecFileStream *stream) +{ + SecInt ch; + if (stream->count < sizeof(SecChar)) { + /* Load file to buffer */ + size_t len; + if (stream->base != NULL) { + /* Put the last unread data in the buffer head */ + for (len = 0; len < stream->count; ++len) { + stream->base[len] = stream->cur[len]; + } + } else { + stream->oriFilePos = ftell(stream->pf); /* Save original file read position */ + if (stream->oriFilePos == -1) { + /* It may be a pipe stream */ + stream->flag = SECUREC_PIPE_STREAM_FLAG; + return SecGetCharFromStream(stream); + } + /* Reserve the length of BOM head */ + stream->base = (char *)SECUREC_MALLOC(SECUREC_BUFFERED_BLOK_SIZE + + SECUREC_BOM_HEADER_SIZE + sizeof(SecChar)); /* To store '\0' and aligned to wide char */ + if (stream->base == NULL) { + return SECUREC_EOF; + } + /* First read file */ + if (stream->oriFilePos == 0) { + /* Make sure the data is aligned to base */ + SecReadAndSkipBomHeader(stream); + } + } + + /* Skip existing data and read data */ + len = fread(stream->base + stream->count, (size_t)1, (size_t)SECUREC_BUFFERED_BLOK_SIZE, stream->pf); + if (len > SECUREC_BUFFERED_BLOK_SIZE) { /* It won't happen, */ + len = 0; + } + stream->count += len; + stream->cur = stream->base; + stream->flag |= SECUREC_LOAD_FILE_TO_MEM_FLAG; + stream->base[stream->count] = '\0'; /* For tool Warning string null */ + } + + SECUREC_GET_CHAR(stream, &ch); + if (ch != SECUREC_EOF) { + stream->fileRealRead += sizeof(SecChar); + } + return ch; +} +#endif + +/* + * Get char for wchar version + */ +SECUREC_INLINE SecInt SecGetChar(SecFileStream *stream, int *counter) +{ + *counter = *counter + 1; /* Always plus 1 */ + /* The main scenario is scanf str */ + if ((stream->flag & SECUREC_MEM_STR_FLAG) != 0) { + SecInt ch; + SECUREC_GET_CHAR(stream, &ch); + return ch; + } +#if SECUREC_ENABLE_SCANF_FILE + if ((stream->flag & SECUREC_FILE_STREAM_FLAG) != 0) { + return SecGetCharFromFile(stream); + } + if ((stream->flag & SECUREC_PIPE_STREAM_FLAG) != 0) { + return SecGetCharFromStream(stream); + } +#endif + return SECUREC_EOF; +} + +/* + * Unget Public realizatio char for wchar and char version + */ +SECUREC_INLINE void SecUnGetCharImpl(SecInt ch, SecFileStream *stream) +{ + if ((stream->flag & SECUREC_MEM_STR_FLAG) != 0) { + SECUREC_UN_GET_CHAR(stream); + return; + } +#if SECUREC_ENABLE_SCANF_FILE + if ((stream->flag & SECUREC_LOAD_FILE_TO_MEM_FLAG) != 0) { + SECUREC_UN_GET_CHAR(stream); + if (stream->fileRealRead > 0) { + stream->fileRealRead -= sizeof(SecChar); + } + return; + } + if ((stream->flag & SECUREC_PIPE_STREAM_FLAG) != 0) { +#if SECUREC_USE_STD_UNGETC + (void)SECUREC_UN_GETC(ch, stream->pf); +#else + stream->lastChar = (unsigned int)ch; + stream->fUnGet = 1; +#endif + return; + } +#else + (void)ch; /* To clear e438 last value assigned not used , the compiler will optimize this code */ +#endif +} + +/* + * Unget char for char version + */ +SECUREC_INLINE void SecUnGetChar(SecInt ch, SecFileStream *stream, int *counter) +{ + *counter = *counter - 1; /* Always mius 1 */ + if (ch != SECUREC_EOF) { + SecUnGetCharImpl(ch, stream); + } +} + +/* + * Skip space char by isspace + */ +SECUREC_INLINE SecInt SecSkipSpaceChar(SecFileStream *stream, int *counter) +{ + SecInt ch; + do { + ch = SecGetChar(stream, counter); + if (ch == SECUREC_EOF) { + break; + } + } while (SecIsSpace(ch) != 0); + return ch; +} +#endif /* INPUT_INL_5D13A042_DC3F_4ED9_A8D1_882811274C27 */ + diff --git a/third_party/bounds_checking_function/src/memcpy_s.c b/third_party/bounds_checking_function/src/memcpy_s.c new file mode 100644 index 0000000000000000000000000000000000000000..4062a322d25576d499877e81f9b728de2156506b --- /dev/null +++ b/third_party/bounds_checking_function/src/memcpy_s.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: memcpy_s function + * Author: lishunda + * Create: 2014-02-25 + */ +/* + * [Standardize-exceptions] Use unsafe function: Portability + * [reason] Use unsafe function to implement security function to maintain platform compatibility. + * And sufficient input validation is performed before calling + */ + +#include "securecutil.h" + +#ifndef SECUREC_MEMCOPY_WITH_PERFORMANCE +#define SECUREC_MEMCOPY_WITH_PERFORMANCE 0 +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS || SECUREC_MEMCOPY_WITH_PERFORMANCE +#ifndef SECUREC_MEMCOPY_THRESHOLD_SIZE +#define SECUREC_MEMCOPY_THRESHOLD_SIZE 64UL +#endif + +#define SECUREC_SMALL_MEM_COPY(dest, src, count) do { \ + if (SECUREC_ADDR_ALIGNED_8(dest) && SECUREC_ADDR_ALIGNED_8(src)) { \ + /* Use struct assignment */ \ + switch (count) { \ + case 1: \ + *(unsigned char *)(dest) = *(const unsigned char *)(src); \ + break; \ + case 2: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 2); \ + break; \ + case 3: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 3); \ + break; \ + case 4: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 4); \ + break; \ + case 5: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 5); \ + break; \ + case 6: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 6); \ + break; \ + case 7: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 7); \ + break; \ + case 8: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 8); \ + break; \ + case 9: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 9); \ + break; \ + case 10: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 10); \ + break; \ + case 11: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 11); \ + break; \ + case 12: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 12); \ + break; \ + case 13: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 13); \ + break; \ + case 14: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 14); \ + break; \ + case 15: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 15); \ + break; \ + case 16: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 16); \ + break; \ + case 17: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 17); \ + break; \ + case 18: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 18); \ + break; \ + case 19: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 19); \ + break; \ + case 20: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 20); \ + break; \ + case 21: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 21); \ + break; \ + case 22: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 22); \ + break; \ + case 23: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 23); \ + break; \ + case 24: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 24); \ + break; \ + case 25: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 25); \ + break; \ + case 26: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 26); \ + break; \ + case 27: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 27); \ + break; \ + case 28: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 28); \ + break; \ + case 29: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 29); \ + break; \ + case 30: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 30); \ + break; \ + case 31: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 31); \ + break; \ + case 32: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 32); \ + break; \ + case 33: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 33); \ + break; \ + case 34: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 34); \ + break; \ + case 35: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 35); \ + break; \ + case 36: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 36); \ + break; \ + case 37: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 37); \ + break; \ + case 38: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 38); \ + break; \ + case 39: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 39); \ + break; \ + case 40: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 40); \ + break; \ + case 41: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 41); \ + break; \ + case 42: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 42); \ + break; \ + case 43: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 43); \ + break; \ + case 44: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 44); \ + break; \ + case 45: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 45); \ + break; \ + case 46: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 46); \ + break; \ + case 47: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 47); \ + break; \ + case 48: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 48); \ + break; \ + case 49: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 49); \ + break; \ + case 50: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 50); \ + break; \ + case 51: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 51); \ + break; \ + case 52: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 52); \ + break; \ + case 53: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 53); \ + break; \ + case 54: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 54); \ + break; \ + case 55: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 55); \ + break; \ + case 56: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 56); \ + break; \ + case 57: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 57); \ + break; \ + case 58: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 58); \ + break; \ + case 59: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 59); \ + break; \ + case 60: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 60); \ + break; \ + case 61: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 61); \ + break; \ + case 62: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 62); \ + break; \ + case 63: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 63); \ + break; \ + case 64: \ + SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 64); \ + break; \ + default: \ + /* Do nothing */ \ + break; \ + } /* END switch */ \ + } else { \ + unsigned char *tmpDest_ = (unsigned char *)(dest); \ + const unsigned char *tmpSrc_ = (const unsigned char *)(src); \ + switch (count) { \ + case 64: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 63: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 62: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 61: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 60: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 59: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 58: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 57: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 56: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 55: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 54: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 53: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 52: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 51: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 50: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 49: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 48: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 47: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 46: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 45: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 44: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 43: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 42: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 41: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 40: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 39: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 38: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 37: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 36: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 35: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 34: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 33: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 32: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 31: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 30: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 29: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 28: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 27: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 26: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 25: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 24: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 23: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 22: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 21: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 20: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 19: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 18: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 17: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 16: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 15: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 14: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 13: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 12: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 11: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 10: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 9: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 8: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 7: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 6: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 5: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 4: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 3: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 2: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 1: \ + *(tmpDest_++) = *(tmpSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + default: \ + /* Do nothing */ \ + break; \ + } \ + } \ +} SECUREC_WHILE_ZERO + +/* + * Performance optimization + */ +#define SECUREC_MEMCPY_OPT(dest, src, count) do { \ + if ((count) > SECUREC_MEMCOPY_THRESHOLD_SIZE) { \ + SECUREC_MEMCPY_WARP_OPT((dest), (src), (count)); \ + } else { \ + SECUREC_SMALL_MEM_COPY((dest), (src), (count)); \ + } \ +} SECUREC_WHILE_ZERO +#endif + +/* + * Handling errors + */ +SECUREC_INLINE errno_t SecMemcpyError(void *dest, size_t destMax, const void *src, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("memcpy_s"); + return ERANGE; + } + if (dest == NULL || src == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("memcpy_s"); + if (dest != NULL) { + (void)memset(dest, 0, destMax); + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > destMax) { + (void)memset(dest, 0, destMax); + SECUREC_ERROR_INVALID_RANGE("memcpy_s"); + return ERANGE_AND_RESET; + } + if (SECUREC_MEMORY_IS_OVERLAP(dest, src, count)) { + (void)memset(dest, 0, destMax); + SECUREC_ERROR_BUFFER_OVERLAP("memcpy_s"); + return EOVERLAP_AND_RESET; + } + /* Count is 0 or dest equal src also ret EOK */ + return EOK; +} + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + /* + * The fread API in windows will call memcpy_s and pass 0xffffffff to destMax. + * To avoid the failure of fread, we don't check desMax limit. + */ +#define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) (SECUREC_LIKELY((count) <= (destMax) && \ + (dest) != NULL && (src) != NULL && \ + (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) +#else +#define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) (SECUREC_LIKELY((count) <= (destMax) && \ + (dest) != NULL && (src) != NULL && (destMax) <= SECUREC_MEM_MAX_LEN && \ + (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) +#endif + +/* + * + * The memcpy_s function copies n characters from the object pointed to by src into the object pointed to by dest + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Buffer to copy from. + * count Number of characters to copy + * + * + * dest buffer is updated. + * + * + * EOK Success + * EINVAL dest is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * ERANGE destMax > SECUREC_MEM_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * and dest != NULL and src != NULL + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and + * count <= destMax destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL + * and src != NULL and dest != src + * + * if an error occured, dest will be filled with 0. + * If the source and destination overlap, the behavior of memcpy_s is undefined. + * Use memmove_s to handle overlapping regions. + */ +errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count) +{ + if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) { +#if SECUREC_MEMCOPY_WITH_PERFORMANCE + SECUREC_MEMCPY_OPT(dest, src, count); +#else + SECUREC_MEMCPY_WARP_OPT(dest, src, count); +#endif + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemcpyError(dest, destMax, src, count); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(memcpy_s); +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS +/* + * Performance optimization + */ +errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count) +{ + if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) { + SECUREC_MEMCPY_OPT(dest, src, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemcpyError(dest, destMax, src, count); +} + +/* Trim judgement on "destMax <= SECUREC_MEM_MAX_LEN" */ +errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count) +{ + if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL && \ + count > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) { + SECUREC_MEMCPY_OPT(dest, src, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemcpyError(dest, destMax, src, count); +} +#endif + diff --git a/third_party/bounds_checking_function/src/memmove_s.c b/third_party/bounds_checking_function/src/memmove_s.c new file mode 100644 index 0000000000000000000000000000000000000000..417df8828956f1fc1219535cd52dd7a9f66d21a1 --- /dev/null +++ b/third_party/bounds_checking_function/src/memmove_s.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: memmove_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +#ifdef SECUREC_NOT_CALL_LIBC_CORE_API +/* + * Implementing memory data movement + */ +SECUREC_INLINE void SecUtilMemmove(void *dst, const void *src, size_t count) +{ + unsigned char *pDest = (unsigned char *)dst; + const unsigned char *pSrc = (const unsigned char *)src; + size_t maxCount = count; + + if (dst <= src || pDest >= (pSrc + maxCount)) { + /* + * Non-Overlapping Buffers + * Copy from lower addresses to higher addresses + */ + while (maxCount > 0) { + --maxCount; + *pDest = *pSrc; + ++pDest; + ++pSrc; + } + } else { + /* + * Overlapping Buffers + * Copy from higher addresses to lower addresses + */ + pDest = pDest + maxCount - 1; + pSrc = pSrc + maxCount - 1; + while (maxCount > 0) { + --maxCount; + *pDest = *pSrc; + --pDest; + --pSrc; + } + } +} +#endif + +/* + * + * The memmove_s function copies count bytes of characters from src to dest. + * This function can be assigned correctly when memory overlaps. + * + * dest Destination object. + * destMax Size of the destination buffer. + * src Source object. + * count Number of characters to copy. + * + * + * dest buffer is uptdated. + * + * + * EOK Success + * EINVAL dest is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * ERANGE destMax > SECUREC_MEM_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET count > destMax and dest != NULL and src != NULL and destMax != 0 + * and destMax <= SECUREC_MEM_MAX_LEN + * + * If an error occured, dest will be filled with 0 when dest and destMax valid. + * If some regions of the source area and the destination overlap, memmove_s + * ensures that the original source bytes in the overlapping region are copied + * before being overwritten. + */ +errno_t memmove_s(void *dest, size_t destMax, const void *src, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("memmove_s"); + return ERANGE; + } + if (dest == NULL || src == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("memmove_s"); + if (dest != NULL) { + (void)memset(dest, 0, destMax); + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > destMax) { + (void)memset(dest, 0, destMax); + SECUREC_ERROR_INVALID_RANGE("memmove_s"); + return ERANGE_AND_RESET; + } + if (dest == src) { + return EOK; + } + + if (count > 0) { +#ifdef SECUREC_NOT_CALL_LIBC_CORE_API + SecUtilMemmove(dest, src, count); +#else + /* Use underlying memmove for performance consideration */ + (void)memmove(dest, src, count); +#endif + } + return EOK; +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(memmove_s); +#endif + diff --git a/third_party/bounds_checking_function/src/memset_s.c b/third_party/bounds_checking_function/src/memset_s.c new file mode 100644 index 0000000000000000000000000000000000000000..fc0cdbe6d59e94cee0d20b47052ac06455f08c17 --- /dev/null +++ b/third_party/bounds_checking_function/src/memset_s.c @@ -0,0 +1,509 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: memset_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +#define SECUREC_MEMSET_PARAM_OK(dest, destMax, count) (SECUREC_LIKELY((destMax) <= SECUREC_MEM_MAX_LEN && \ + (dest) != NULL && (count) <= (destMax))) + +#if SECUREC_WITH_PERFORMANCE_ADDONS + +/* Use union to clear strict-aliasing warning */ +typedef union { + SecStrBuf32 buf32; + SecStrBuf31 buf31; + SecStrBuf30 buf30; + SecStrBuf29 buf29; + SecStrBuf28 buf28; + SecStrBuf27 buf27; + SecStrBuf26 buf26; + SecStrBuf25 buf25; + SecStrBuf24 buf24; + SecStrBuf23 buf23; + SecStrBuf22 buf22; + SecStrBuf21 buf21; + SecStrBuf20 buf20; + SecStrBuf19 buf19; + SecStrBuf18 buf18; + SecStrBuf17 buf17; + SecStrBuf16 buf16; + SecStrBuf15 buf15; + SecStrBuf14 buf14; + SecStrBuf13 buf13; + SecStrBuf12 buf12; + SecStrBuf11 buf11; + SecStrBuf10 buf10; + SecStrBuf9 buf9; + SecStrBuf8 buf8; + SecStrBuf7 buf7; + SecStrBuf6 buf6; + SecStrBuf5 buf5; + SecStrBuf4 buf4; + SecStrBuf3 buf3; + SecStrBuf2 buf2; +} SecStrBuf32Union; +/* C standard initializes the first member of the consortium. */ +static const SecStrBuf32 g_allZero = {{ + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' +}}; +static const SecStrBuf32 g_allFF = {{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}}; + +/* Clear coversion warning strict aliasing" */ +SECUREC_INLINE const SecStrBuf32Union *SecStrictAliasingCast(const SecStrBuf32 *buf) +{ + return (const SecStrBuf32Union *)buf; +} + +#ifndef SECUREC_MEMSET_THRESHOLD_SIZE +#define SECUREC_MEMSET_THRESHOLD_SIZE 32UL +#endif + +#define SECUREC_UNALIGNED_SET(dest, c, count) do { \ + unsigned char *pDest_ = (unsigned char *)(dest); \ + switch (count) { \ + case 32: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 31: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 30: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 29: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 28: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 27: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 26: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 25: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 24: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 23: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 22: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 21: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 20: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 19: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 18: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 17: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 16: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 15: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 14: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 13: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 12: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 11: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 10: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 9: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 8: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 7: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 6: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 5: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 4: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 3: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 2: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + case 1: \ + *(pDest_++) = (unsigned char)(c); \ + /* fall-through */ /* FALLTHRU */ \ + default: \ + /* Do nothing */ \ + break; \ + } \ +} SECUREC_WHILE_ZERO + +#define SECUREC_SET_VALUE_BY_STRUCT(dest, dataName, n) do { \ + *(SecStrBuf##n *)(dest) = *(const SecStrBuf##n *)(&((SecStrictAliasingCast(&(dataName)))->buf##n)); \ +} SECUREC_WHILE_ZERO + +#define SECUREC_ALIGNED_SET_OPT_ZERO_FF(dest, c, count) do { \ + switch (c) { \ + case 0: \ + switch (count) { \ + case 1: \ + *(unsigned char *)(dest) = (unsigned char)0; \ + break; \ + case 2: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 2); \ + break; \ + case 3: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 3); \ + break; \ + case 4: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 4); \ + break; \ + case 5: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 5); \ + break; \ + case 6: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 6); \ + break; \ + case 7: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 7); \ + break; \ + case 8: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 8); \ + break; \ + case 9: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 9); \ + break; \ + case 10: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 10); \ + break; \ + case 11: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 11); \ + break; \ + case 12: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 12); \ + break; \ + case 13: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 13); \ + break; \ + case 14: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 14); \ + break; \ + case 15: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 15); \ + break; \ + case 16: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 16); \ + break; \ + case 17: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 17); \ + break; \ + case 18: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 18); \ + break; \ + case 19: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 19); \ + break; \ + case 20: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 20); \ + break; \ + case 21: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 21); \ + break; \ + case 22: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 22); \ + break; \ + case 23: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 23); \ + break; \ + case 24: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 24); \ + break; \ + case 25: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 25); \ + break; \ + case 26: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 26); \ + break; \ + case 27: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 27); \ + break; \ + case 28: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 28); \ + break; \ + case 29: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 29); \ + break; \ + case 30: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 30); \ + break; \ + case 31: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 31); \ + break; \ + case 32: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 32); \ + break; \ + default: \ + /* Do nothing */ \ + break; \ + } \ + break; \ + case 0xFF: \ + switch (count) { \ + case 1: \ + *(unsigned char *)(dest) = (unsigned char)0xffU; \ + break; \ + case 2: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 2); \ + break; \ + case 3: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 3); \ + break; \ + case 4: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 4); \ + break; \ + case 5: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 5); \ + break; \ + case 6: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 6); \ + break; \ + case 7: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 7); \ + break; \ + case 8: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 8); \ + break; \ + case 9: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 9); \ + break; \ + case 10: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 10); \ + break; \ + case 11: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 11); \ + break; \ + case 12: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 12); \ + break; \ + case 13: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 13); \ + break; \ + case 14: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 14); \ + break; \ + case 15: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 15); \ + break; \ + case 16: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 16); \ + break; \ + case 17: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 17); \ + break; \ + case 18: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 18); \ + break; \ + case 19: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 19); \ + break; \ + case 20: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 20); \ + break; \ + case 21: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 21); \ + break; \ + case 22: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 22); \ + break; \ + case 23: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 23); \ + break; \ + case 24: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 24); \ + break; \ + case 25: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 25); \ + break; \ + case 26: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 26); \ + break; \ + case 27: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 27); \ + break; \ + case 28: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 28); \ + break; \ + case 29: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 29); \ + break; \ + case 30: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 30); \ + break; \ + case 31: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 31); \ + break; \ + case 32: \ + SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 32); \ + break; \ + default: \ + /* Do nothing */ \ + break; \ + } \ + break; \ + default: \ + SECUREC_UNALIGNED_SET((dest), (c), (count)); \ + break; \ + } /* END switch */ \ +} SECUREC_WHILE_ZERO + +#define SECUREC_SMALL_MEM_SET(dest, c, count) do { \ + if (SECUREC_ADDR_ALIGNED_8((dest))) { \ + SECUREC_ALIGNED_SET_OPT_ZERO_FF((dest), (c), (count)); \ + } else { \ + SECUREC_UNALIGNED_SET((dest), (c), (count)); \ + } \ +} SECUREC_WHILE_ZERO + +/* + * Performance optimization + */ +#define SECUREC_MEMSET_OPT(dest, c, count) do { \ + if ((count) > SECUREC_MEMSET_THRESHOLD_SIZE) { \ + SECUREC_MEMSET_WARP_OPT((dest), (c), (count)); \ + } else { \ + SECUREC_SMALL_MEM_SET((dest), (c), (count)); \ + } \ +} SECUREC_WHILE_ZERO +#endif + +/* + * Handling errors + */ +SECUREC_INLINE errno_t SecMemsetError(void *dest, size_t destMax, int c, size_t count) +{ + /* Check destMax is 0 compatible with _sp macro */ + if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("memset_s"); + return ERANGE; + } + if (dest == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("memset_s"); + return EINVAL; + } + if (count > destMax) { + (void)memset(dest, c, destMax); /* Set entire buffer to value c */ + SECUREC_ERROR_INVALID_RANGE("memset_s"); + return ERANGE_AND_RESET; + } + return EOK; +} + +/* + * + * The memset_s function copies the value of c (converted to an unsigned char) + * into each of the first count characters of the object pointed to by dest. + * + * + * dest Pointer to destination. + * destMax The size of the buffer. + * c Character to set. + * count Number of characters. + * + * + * dest buffer is uptdated. + * + * + * EOK Success + * EINVAL dest == NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN + * ERANGE destMax > SECUREC_MEM_MAX_LEN or (destMax is 0 and count > destMax) + * ERANGE_AND_RESET count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL + * + * if return ERANGE_AND_RESET then fill dest to c ,fill length is destMax + */ +errno_t memset_s(void *dest, size_t destMax, int c, size_t count) +{ + if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) { + SECUREC_MEMSET_WARP_OPT(dest, c, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemsetError(dest, destMax, c, count); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(memset_s); +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS +/* + * Performance optimization + */ +errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count) +{ + if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) { + SECUREC_MEMSET_OPT(dest, c, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemsetError(dest, destMax, c, count); +} + +/* + * Performance optimization, trim judgement on "destMax <= SECUREC_MEM_MAX_LEN" + */ +errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count) +{ + if (SECUREC_LIKELY(count <= destMax && dest != NULL)) { + SECUREC_MEMSET_OPT(dest, c, count); + return EOK; + } + /* Meet some runtime violation, return error code */ + return SecMemsetError(dest, destMax, c, count); +} +#endif + diff --git a/third_party/bounds_checking_function/src/output.inl b/third_party/bounds_checking_function/src/output.inl new file mode 100644 index 0000000000000000000000000000000000000000..20dd4b3bd87771848a0cc2bc3606cf0dc92e32c6 --- /dev/null +++ b/third_party/bounds_checking_function/src/output.inl @@ -0,0 +1,1668 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: Used by secureprintoutput_a.c and secureprintoutput_w.c to include. + * This file provides a template function for ANSI and UNICODE compiling + * by different type definition. The functions of SecOutputS or + * SecOutputSW provides internal implementation for printf family API, such as sprintf, swprintf_s. + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 +#define OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 + +#ifndef SECUREC_ENABLE_SPRINTF_LONG_DOUBLE +/* Some compilers do not support long double */ +#define SECUREC_ENABLE_SPRINTF_LONG_DOUBLE 1 +#endif + +#define SECUREC_NULL_STRING_SIZE 8 +#define SECUREC_STATE_TABLE_SIZE 337 + +#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS) +#define SECUREC_DIV_QUOTIENT_OCTAL(val64) ((val64) >> 3ULL) +#define SECUREC_DIV_RESIDUE_OCTAL(val64) ((val64) & 7ULL) + +#define SECUREC_DIV_QUOTIENT_HEX(val64) ((val64) >> 4ULL) +#define SECUREC_DIV_RESIDUE_HEX(val64) ((val64) & 0xfULL) +#endif + +#define SECUREC_RADIX_OCTAL 8U +#define SECUREC_RADIX_DECIMAL 10U +#define SECUREC_RADIX_HEX 16U +#define SECUREC_PREFIX_LEN 2 +/* Size include '+' and '\0' */ +#define SECUREC_FLOAT_BUF_EXT 2 + +/* Sign extend or Zero-extend */ +#define SECUREC_GET_LONG_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \ + (SecInt64)(long)va_arg(argList, long) : \ + (SecInt64)(unsigned long)va_arg(argList, long)) + +/* Sign extend or Zero-extend */ +#define SECUREC_GET_CHAR_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \ + SecUpdateNegativeChar(&(attr), ((char)va_arg(argList, int))) : \ + (SecInt64)(unsigned char)va_arg(argList, int)) + +/* Sign extend or Zero-extend */ +#define SECUREC_GET_SHORT_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \ + (SecInt64)(short)va_arg(argList, int) : \ + (SecInt64)(unsigned short)va_arg(argList, int)) + +/* Sign extend or Zero-extend */ +#define SECUREC_GET_INT_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \ + (SecInt64)(int)va_arg(argList, int) : \ + (SecInt64)(unsigned int)va_arg(argList, int)) + +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +/* Sign extend or Zero-extend. No suitable macros were found to handle the branch */ +#define SECUREC_GET_SIZE_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \ + ((SecIsSameSize(sizeof(size_t), sizeof(long)) != 0) ? (SecInt64)(long)va_arg(argList, long) : \ + ((SecIsSameSize(sizeof(size_t), sizeof(long long)) != 0) ? (SecInt64)(long long)va_arg(argList, long long) : \ + (SecInt64)(int)va_arg(argList, int))) : \ + (SecInt64)(size_t)va_arg(argList, size_t)) +#endif + +typedef union { + /* Integer formatting refers to the end of the buffer, plus 1 to prevent tool alarms */ + char str[SECUREC_BUFFER_SIZE + 1]; +#if SECUREC_HAVE_WCHART + wchar_t wStr[SECUREC_WCHAR_BUFFER_SIZE]; /* Just for %lc */ +#endif +} SecBuffer; + +typedef union { + char *str; /* Not a null terminated string */ +#if SECUREC_HAVE_WCHART + wchar_t *wStr; +#endif +} SecFormatBuf; + +typedef struct { + const char *digits; /* Point to the hexadecimal subset */ + SecFormatBuf text; /* Point to formated string */ + int textLen; /* Length of the text */ + int textIsWide; /* Flag for text is wide chars ; 0 is not wide char */ + unsigned int radix; /* Use for output number , default set to 10 */ + unsigned int flags; + int fldWidth; + int precision; + int dynWidth; /* %* 1 width from variable parameter ;0 not */ + int dynPrecision; /* %.* 1 precision from variable parameter ;0 not */ + int padding; /* Padding len */ + int prefixLen; /* Length of prefix, 0 or 1 or 2 */ + SecChar prefix[SECUREC_PREFIX_LEN]; /* Prefix is 0 or 0x */ + SecBuffer buffer; +} SecFormatAttr; + +#if SECUREC_ENABLE_SPRINTF_FLOAT +#ifdef SECUREC_STACK_SIZE_LESS_THAN_1K +#define SECUREC_FMT_STR_LEN 8 +#else +#define SECUREC_FMT_STR_LEN 16 +#endif +typedef struct { + char buffer[SECUREC_FMT_STR_LEN]; + char *fmtStr; /* Initialization must point to buffer */ + char *allocatedFmtStr; /* Initialization must be NULL to store alloced point */ + char *floatBuffer; /* Use heap memory if the SecFormatAttr.buffer is not enough */ + int bufferSize; /* The size of floatBuffer */ +} SecFloatAdapt; +#endif + +/* Use 20 to Align the data */ +#define SECUREC_DIGITS_BUF_SIZE 20 +/* Some systems can not use pointers to point to string literals, but can use string arrays. */ +/* For example, when handling code under uboot, there is a problem with the pointer */ +static const char g_itoaUpperDigits[SECUREC_DIGITS_BUF_SIZE] = "0123456789ABCDEFX"; +static const char g_itoaLowerDigits[SECUREC_DIGITS_BUF_SIZE] = "0123456789abcdefx"; + +#if SECUREC_ENABLE_SPRINTF_FLOAT +/* Call system sprintf to format float value */ +SECUREC_INLINE int SecFormatFloat(char *strDest, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + SECUREC_MASK_MSVC_CRT_WARNING + ret = vsprintf(strDest, format, argList); + SECUREC_END_MASK_MSVC_CRT_WARNING + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} + +#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && SECUREC_ENABLE_SPRINTF_LONG_DOUBLE +/* Out put long double value to dest */ +SECUREC_INLINE void SecFormatLongDouble(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, long double ldValue) +{ + int fldWidth = (((attr->flags & SECUREC_FLAG_LEFT) != 0) ? (-attr->fldWidth) : attr->fldWidth); + if (attr->dynWidth != 0 && attr->dynPrecision != 0) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, ldValue); + } else if (attr->dynWidth != 0) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, ldValue); + } else if (attr->dynPrecision != 0) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, ldValue); + } else { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, ldValue); + } + if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) { + attr->textLen = 0; + } +} +#endif + +/* Out put double value to dest */ +SECUREC_INLINE void SecFormatDouble(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, double dValue) +{ + int fldWidth = (((attr->flags & SECUREC_FLAG_LEFT) != 0) ? (-attr->fldWidth) : attr->fldWidth); + if (attr->dynWidth != 0 && attr->dynPrecision != 0) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, dValue); + } else if (attr->dynWidth != 0) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, dValue); + } else if (attr->dynPrecision != 0) { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, dValue); + } else { + attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, dValue); + } + if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) { + attr->textLen = 0; + } +} +#endif + +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +/* To clear e506 warning */ +SECUREC_INLINE int SecIsSameSize(size_t sizeA, size_t sizeB) +{ + return (int)(sizeA == sizeB); +} +#endif + +#ifndef SECUREC_ON_64BITS +/* + * Compiler Optimized Division 8. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber32ToOctalString(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + SecUnsignedInt32 val32 = number; + do { + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_OCTAL]; + val32 /= SECUREC_RADIX_OCTAL; + } while (val32 != 0); +} + +#ifdef _AIX +/* + * Compiler Optimized Division 10. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber32ToDecString(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + SecUnsignedInt32 val32 = number; + do { + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL]; + val32 /= SECUREC_RADIX_DECIMAL; + } while (val32 != 0); +} +#endif +/* + * Compiler Optimized Division 16. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber32ToHexString(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + SecUnsignedInt32 val32 = number; + do { + --attr->text.str; + *(attr->text.str) = attr->digits[val32 % SECUREC_RADIX_HEX]; + val32 /= SECUREC_RADIX_HEX; + } while (val32 != 0); +} + +#ifndef _AIX +/* Use fast div 10 */ +SECUREC_INLINE void SecNumber32ToDecStringFast(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + SecUnsignedInt32 val32 = number; + do { + SecUnsignedInt32 quotient; + SecUnsignedInt32 remain; + --attr->text.str; + *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL]; + quotient = (val32 >> 1U) + (val32 >> 2U); /* Fast div magic 2 */ + quotient = quotient + (quotient >> 4U); /* Fast div magic 4 */ + quotient = quotient + (quotient >> 8U); /* Fast div magic 8 */ + quotient = quotient + (quotient >> 16U); /* Fast div magic 16 */ + quotient = quotient >> 3U; /* Fast div magic 3 */ + remain = val32 - SECUREC_MUL_TEN(quotient); + val32 = (remain > 9U) ? (quotient + 1U) : quotient; /* Fast div magic 9 */ + } while (val32 != 0); +} +#endif + +SECUREC_INLINE void SecNumber32ToString(SecUnsignedInt32 number, SecFormatAttr *attr) +{ + switch (attr->radix) { + case SECUREC_RADIX_HEX: + SecNumber32ToHexString(number, attr); + break; + case SECUREC_RADIX_OCTAL: + SecNumber32ToOctalString(number, attr); + break; + case SECUREC_RADIX_DECIMAL: +#ifdef _AIX + /* The compiler will optimize div 10 */ + SecNumber32ToDecString(number, attr); +#else + SecNumber32ToDecStringFast(number, attr); +#endif + break; + default: + /* Do nothing */ + break; + } +} +#endif + +#if defined(SECUREC_USE_SPECIAL_DIV64) || (defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)) +/* + * This function just to clear warning, on sume vxworks compiler shift 32 bit make warnigs + */ +SECUREC_INLINE SecUnsignedInt64 SecU64Shr32(SecUnsignedInt64 number) +{ + return (((number) >> 16U) >> 16U); /* Two shifts of 16 bits to realize shifts of 32 bits */ +} +/* + * Fast divide by 10 algorithm. + * Calculation divisor multiply 0xcccccccccccccccdULL, resultHi64 >> 3 as quotient + */ +SECUREC_INLINE void SecU64Div10(SecUnsignedInt64 divisor, SecUnsignedInt64 *quotient, SecUnsignedInt32 *residue) +{ + SecUnsignedInt64 mask = 0xffffffffULL; /* Use 0xffffffffULL as 32 bit mask */ + SecUnsignedInt64 magicHi = 0xccccccccULL; /* Fast divide 10 magic numbers high 32bit 0xccccccccULL */ + SecUnsignedInt64 magicLow = 0xcccccccdULL; /* Fast divide 10 magic numbers low 32bit 0xcccccccdULL */ + SecUnsignedInt64 divisorHi = (SecUnsignedInt64)(SecU64Shr32(divisor)); /* High 32 bit use */ + SecUnsignedInt64 divisorLow = (SecUnsignedInt64)(divisor & mask); /* Low 32 bit mask */ + SecUnsignedInt64 factorHi = divisorHi * magicHi; + SecUnsignedInt64 factorLow1 = divisorHi * magicLow; + SecUnsignedInt64 factorLow2 = divisorLow * magicHi; + SecUnsignedInt64 factorLow3 = divisorLow * magicLow; + SecUnsignedInt64 carry = (factorLow1 & mask) + (factorLow2 & mask) + SecU64Shr32(factorLow3); + SecUnsignedInt64 resultHi64 = factorHi + SecU64Shr32(factorLow1) + SecU64Shr32(factorLow2) + SecU64Shr32(carry); + + *quotient = resultHi64 >> 3U; /* Fast divide 10 magic numbers 3 */ + *residue = (SecUnsignedInt32)(divisor - ((*quotient) * 10)); /* Quotient mul 10 */ + return; +} +#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS) +/* + * Divide function for VXWORKS + */ +SECUREC_INLINE int SecU64Div32(SecUnsignedInt64 divisor, SecUnsignedInt32 radix, + SecUnsignedInt64 *quotient, SecUnsignedInt32 *residue) +{ + switch (radix) { + case SECUREC_RADIX_DECIMAL: + SecU64Div10(divisor, quotient, residue); + break; + case SECUREC_RADIX_HEX: + *quotient = SECUREC_DIV_QUOTIENT_HEX(divisor); + *residue = (SecUnsignedInt32)SECUREC_DIV_RESIDUE_HEX(divisor); + break; + case SECUREC_RADIX_OCTAL: + *quotient = SECUREC_DIV_QUOTIENT_OCTAL(divisor); + *residue = (SecUnsignedInt32)SECUREC_DIV_RESIDUE_OCTAL(divisor); + break; + default: + return -1; /* This does not happen in the current file */ + } + return 0; +} +SECUREC_INLINE void SecNumber64ToStringSpecial(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + SecUnsignedInt32 digit = 0; /* Ascii value of digit */ + SecUnsignedInt64 quotient = 0; + if (SecU64Div32(val64, (SecUnsignedInt32)attr->radix, "ient, &digit) != 0) { + /* Just break, when enter this function, no error is returned */ + break; + } + --attr->text.str; + *(attr->text.str) = attr->digits[digit]; + val64 = quotient; + } while (val64 != 0); +} +#endif +#endif + +#if defined(SECUREC_ON_64BITS) || !defined(SECUREC_VXWORKS_VERSION_5_4) +#if defined(SECUREC_USE_SPECIAL_DIV64) +/* The compiler does not provide 64 bit division problems */ +SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + SecUnsignedInt64 quotient = 0; + SecUnsignedInt32 digit = 0; + SecU64Div10(val64, "ient, &digit); + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[digit]; + val64 = quotient; + } while (val64 != 0); +} +#else +/* + * Compiler Optimized Division 10. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_DECIMAL]; + val64 /= SECUREC_RADIX_DECIMAL; + } while (val64 != 0); +} +#endif + +/* + * Compiler Optimized Division 8. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber64ToOctalString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + --attr->text.str; + /* Just use lowerDigits for 0 - 9 */ + *(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_OCTAL]; + val64 /= SECUREC_RADIX_OCTAL; + } while (val64 != 0); +} +/* + * Compiler Optimized Division 16. + * The text.str point to buffer end, must be Large enough + */ +SECUREC_INLINE void SecNumber64ToHexString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + SecUnsignedInt64 val64 = number; + do { + --attr->text.str; + *(attr->text.str) = attr->digits[val64 % SECUREC_RADIX_HEX]; + val64 /= SECUREC_RADIX_HEX; + } while (val64 != 0); +} + +SECUREC_INLINE void SecNumber64ToString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ + switch (attr->radix) { + /* The compiler will optimize div 10 */ + case SECUREC_RADIX_DECIMAL: + SecNumber64ToDecString(number, attr); + break; + case SECUREC_RADIX_OCTAL: + SecNumber64ToOctalString(number, attr); + break; + case SECUREC_RADIX_HEX: + SecNumber64ToHexString(number, attr); + break; + default: + /* Do nothing */ + break; + } +} +#endif + +/* + * Converting integers to string + */ +SECUREC_INLINE void SecNumberToString(SecUnsignedInt64 number, SecFormatAttr *attr) +{ +#ifdef SECUREC_ON_64BITS + SecNumber64ToString(number, attr); +#else /* For 32 bits system */ + if (number <= 0xffffffffUL) { /* Use 0xffffffffUL to check if the value is in the 32-bit range */ + /* In most case, the value to be converted is small value */ + SecUnsignedInt32 n32Tmp = (SecUnsignedInt32)number; + SecNumber32ToString(n32Tmp, attr); + } else { + /* The value to be converted is greater than 4G */ +#if defined(SECUREC_VXWORKS_VERSION_5_4) + SecNumber64ToStringSpecial(number, attr); +#else + SecNumber64ToString(number, attr); +#endif + } +#endif +} + +SECUREC_INLINE int SecIsNumberNeedTo32Bit(const SecFormatAttr *attr) +{ + return (int)(((attr->flags & SECUREC_FLAG_I64) == 0) && +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + ((attr->flags & SECUREC_FLAG_INTMAX) == 0) && +#endif +#ifdef SECUREC_ON_64BITS + ((attr->flags & SECUREC_FLAG_PTRDIFF) == 0) && + ((attr->flags & SECUREC_FLAG_SIZE) == 0) && +#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT) /* on window 64 system sizeof long is 32bit */ + ((attr->flags & SECUREC_FLAG_LONG) == 0) && +#endif +#endif + ((attr->flags & SECUREC_FLAG_LONGLONG) == 0)); +} + +SECUREC_INLINE void SecNumberToBuffer(SecFormatAttr *attr, SecInt64 num64) +{ + SecUnsignedInt64 number; + /* Check for negative; copy into number */ + if ((attr->flags & SECUREC_FLAG_SIGNED) != 0 && num64 < 0) { + number = (SecUnsignedInt64)(0 - (SecUnsignedInt64)num64); /* Wrap with unsigned int64 numbers */ + attr->flags |= SECUREC_FLAG_NEGATIVE; + } else { + number = (SecUnsignedInt64)num64; + } + if (SecIsNumberNeedTo32Bit(attr) != 0) { + number = (number & (SecUnsignedInt64)0xffffffffUL); /* Use 0xffffffff as 32 bit mask */ + } + + /* The text.str must be point to buffer.str, this pointer is used outside the function */ + attr->text.str = &attr->buffer.str[SECUREC_BUFFER_SIZE]; + + if (number == 0) { + /* Turn off hex prefix default, and textLen is zero */ + attr->prefixLen = 0; + attr->textLen = 0; + return; + } + + /* Convert integer to string. It must be invoked when number > 0, otherwise the following logic is incorrect */ + SecNumberToString(number, attr); + /* Compute length of number, text.str must be in buffer.str */ + attr->textLen = (int)(size_t)((char *)&attr->buffer.str[SECUREC_BUFFER_SIZE] - attr->text.str); +} + +/* Use loop copy char or wchar_t string */ +SECUREC_INLINE void SecWriteStringToStreamOpt(SecPrintfStream *stream, const SecChar *str, int len) +{ + int i; + const SecChar *tmp = str; + for (i = 0; i < len; ++i) { + *((SecChar *)(void *)(stream->cur)) = *(const SecChar *)(tmp); + stream->cur += sizeof(SecChar); + tmp = tmp + 1; + } + stream->count -= len * (int)(sizeof(SecChar)); +} + +SECUREC_INLINE void SecWriteStringToStream(SecPrintfStream *stream, const SecChar *str, int len) +{ + if (len < 12) { /* Performance optimization for mobile number length 12 */ + SecWriteStringToStreamOpt(stream, str, len); + } else { + size_t count = (size_t)(unsigned int)len * (sizeof(SecChar)); + SECUREC_MEMCPY_WARP_OPT(stream->cur, str, count); + stream->cur += (size_t)((size_t)(unsigned int)len * (sizeof(SecChar))); + stream->count -= len * (int)(sizeof(SecChar)); + } +} + +/* + * Return if buffer length is enough + * The count variable can be reduced to 0, and the external function complements the \0 terminator. + */ +SECUREC_INLINE int SecIsStreamBufEnough(const SecPrintfStream *stream, int needLen) +{ + return ((int)(stream->count - (needLen * (int)(sizeof(SecChar)))) >= 0); +} + +#ifdef SECUREC_FOR_WCHAR +SECUREC_INLINE void SecWriteMultiCharW(wchar_t ch, int num, SecPrintfStream *f, int *pnumwritten); +SECUREC_INLINE void SecWriteStringW(const wchar_t *string, int len, SecPrintfStream *f, int *pnumwritten); +#define SECUREC_WRITE_MULTI_CHAR SecWriteMultiCharW +#define SECUREC_WRITE_STRING SecWriteStringW +#else +SECUREC_INLINE void SecWriteMultiChar(char ch, int num, SecPrintfStream *f, int *pnumwritten); +SECUREC_INLINE void SecWriteString(const char *string, int len, SecPrintfStream *f, int *pnumwritten); +#define SECUREC_WRITE_MULTI_CHAR SecWriteMultiChar +#define SECUREC_WRITE_STRING SecWriteString +#endif + +/* Write left padding */ +SECUREC_INLINE void SecWriteLeftPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + if ((attr->flags & (SECUREC_FLAG_LEFT | SECUREC_FLAG_LEADZERO)) == 0 && attr->padding > 0) { + /* Pad on left with blanks */ + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR(' '), attr->padding, stream, charsOut); + } +} + +/* Write prefix */ +SECUREC_INLINE void SecWritePrefix(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + if (attr->prefixLen > 0) { + if (SecIsStreamBufEnough(stream, attr->prefixLen) != 0) { + /* Max prefix len is 2, use loop copy */ + SecWriteStringToStreamOpt(stream, attr->prefix, attr->prefixLen); + *charsOut += attr->prefixLen; + } else { + SECUREC_WRITE_STRING(attr->prefix, attr->prefixLen, stream, charsOut); + } + } +} + +/* Write leading zeros */ +SECUREC_INLINE void SecWriteLeadingZero(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + if ((attr->flags & SECUREC_FLAG_LEADZERO) != 0 && (attr->flags & SECUREC_FLAG_LEFT) == 0 && + attr->padding > 0) { + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR('0'), attr->padding, stream, charsOut); + } +} + +/* Write right padding */ +SECUREC_INLINE void SecWriteRightPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + if (*charsOut >= 0 && (attr->flags & SECUREC_FLAG_LEFT) != 0 && attr->padding > 0) { + /* Pad on right with blanks */ + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR(' '), attr->padding, stream, charsOut); + } +} + +/* Write text string */ +SECUREC_INLINE void SecWriteStringChk(SecPrintfStream *stream, const SecChar *str, int len, int *charsOut) +{ + if (SecIsStreamBufEnough(stream, len) != 0) { + SecWriteStringToStream(stream, str, len); + *charsOut += len; + } else { + SECUREC_WRITE_STRING(str, len, stream, charsOut); + } +} + +#ifdef SECUREC_FOR_WCHAR +#if SECUREC_HAVE_MBTOWC +SECUREC_INLINE void SecWriteTextAfterMbtowc(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + const char *p = attr->text.str; + int count = attr->textLen; + while (count > 0) { + wchar_t wChar = L'\0'; + int retVal = mbtowc(&wChar, p, (size_t)MB_CUR_MAX); + if (retVal <= 0) { + *charsOut = -1; + break; + } + SecWriteCharW(wChar, stream, charsOut); + if (*charsOut == -1) { + break; + } + p += retVal; + count -= retVal; + } +} +#endif +#else /* Not SECUREC_FOR_WCHAR */ +#if SECUREC_HAVE_WCTOMB +SECUREC_INLINE void SecWriteTextAfterWctomb(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ + const wchar_t *p = attr->text.wStr; + int count = attr->textLen; + while (count > 0) { + char tmpBuf[SECUREC_MB_LEN + 1]; + SECUREC_MASK_MSVC_CRT_WARNING + int retVal = wctomb(tmpBuf, *p); + SECUREC_END_MASK_MSVC_CRT_WARNING + if (retVal <= 0) { + *charsOut = -1; + break; + } + SecWriteString(tmpBuf, retVal, stream, charsOut); + if (*charsOut == -1) { + break; + } + --count; + ++p; + } +} +#endif +#endif + +#if SECUREC_ENABLE_SPRINTF_FLOAT +/* + * Write text of float + * Using independent functions to optimize the expansion of inline functions by the compiler + */ +SECUREC_INLINE void SecWriteFloatText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ +#ifdef SECUREC_FOR_WCHAR +#if SECUREC_HAVE_MBTOWC + SecWriteTextAfterMbtowc(stream, attr, charsOut); +#else + *charsOut = -1; + (void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + (void)attr; /* To clear e438 last value assigned not used , the compiler will optimize this code */ +#endif +#else /* Not SECUREC_FOR_WCHAR */ + SecWriteString(attr->text.str, attr->textLen, stream, charsOut); +#endif +} +#endif + +/* Write text of integer or string ... */ +SECUREC_INLINE void SecWriteText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut) +{ +#ifdef SECUREC_FOR_WCHAR + if (attr->textIsWide != 0) { + SecWriteStringChk(stream, attr->text.wStr, attr->textLen, charsOut); + } else { +#if SECUREC_HAVE_MBTOWC + SecWriteTextAfterMbtowc(stream, attr, charsOut); +#else + *charsOut = -1; +#endif + } + +#else /* Not SECUREC_FOR_WCHAR */ + if (attr->textIsWide != 0) { +#if SECUREC_HAVE_WCTOMB + SecWriteTextAfterWctomb(stream, attr, charsOut); +#else + *charsOut = -1; +#endif + } else { + SecWriteStringChk(stream, attr->text.str, attr->textLen, charsOut); + } +#endif +} + +#define SECUREC_FMT_STATE_OFFSET 256 + +SECUREC_INLINE SecFmtState SecDecodeState(SecChar ch, SecFmtState lastState) +{ + static const unsigned char stateTable[SECUREC_STATE_TABLE_SIZE] = { + /* + * Type + * 0: nospecial meanin; + * 1: '%' + * 2: '.' + * 3: '*' + * 4: '0' + * 5: '1' ... '9' + * 6: ' ', '+', '-', '#' + * 7: 'h', 'l', 'L', 'w' , 'N', 'z', 'q', 't', 'j' + * 8: 'd', 'o', 'u', 'i', 'x', 'X', 'e', 'f', 'g', 'E', 'F', 'G', 's', 'c', '[', 'p' + */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x00, + 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x07, 0x00, 0x07, 0x00, 0x00, 0x08, + 0x08, 0x07, 0x00, 0x08, 0x07, 0x08, 0x00, 0x07, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Fill zero for normal char 128 byte for 0x80 - 0xff */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* + * State + * 0: normal + * 1: percent + * 2: flag + * 3: width + * 4: dot + * 5: precis + * 6: size + * 7: type + * 8: invalid + */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x01, 0x00, 0x00, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, 0x08, 0x05, + 0x08, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, + 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, + 0x00 + }; + +#ifdef SECUREC_FOR_WCHAR + /* Convert to unsigned char to clear gcc 4.3.4 warning */ + unsigned char fmtType = (unsigned char)((((unsigned int)(int)(ch)) <= (unsigned int)(int)(L'~')) ? \ + (stateTable[(unsigned char)(ch)]) : 0); + return (SecFmtState)(stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) + + (unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]); +#else + unsigned char fmtType = stateTable[(unsigned char)(ch)]; + return (SecFmtState)(stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) + + (unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]); +#endif +} + +SECUREC_INLINE void SecDecodeFlags(SecChar ch, SecFormatAttr *attr) +{ + switch (ch) { + case SECUREC_CHAR(' '): + attr->flags |= SECUREC_FLAG_SIGN_SPACE; + break; + case SECUREC_CHAR('+'): + attr->flags |= SECUREC_FLAG_SIGN; + break; + case SECUREC_CHAR('-'): + attr->flags |= SECUREC_FLAG_LEFT; + break; + case SECUREC_CHAR('0'): + attr->flags |= SECUREC_FLAG_LEADZERO; /* Add zero th the front */ + break; + case SECUREC_CHAR('#'): + attr->flags |= SECUREC_FLAG_ALTERNATE; /* Output %x with 0x */ + break; + default: + /* Do nothing */ + break; + } + return; +} + +/* + * Decoded size identifier in format string to Reduce the number of lines of function code + */ +SECUREC_INLINE int SecDecodeSizeI(SecFormatAttr *attr, const SecChar **format) +{ +#ifdef SECUREC_ON_64BITS + attr->flags |= SECUREC_FLAG_I64; /* %I to INT64 */ +#endif + if ((**format == SECUREC_CHAR('6')) && (*((*format) + 1) == SECUREC_CHAR('4'))) { + (*format) += 2; /* Add 2 to skip I64 */ + attr->flags |= SECUREC_FLAG_I64; /* %I64 to INT64 */ + } else if ((**format == SECUREC_CHAR('3')) && (*((*format) + 1) == SECUREC_CHAR('2'))) { + (*format) += 2; /* Add 2 to skip I32 */ + attr->flags &= ~SECUREC_FLAG_I64; /* %I64 to INT32 */ + } else if ((**format == SECUREC_CHAR('d')) || (**format == SECUREC_CHAR('i')) || + (**format == SECUREC_CHAR('o')) || (**format == SECUREC_CHAR('u')) || + (**format == SECUREC_CHAR('x')) || (**format == SECUREC_CHAR('X'))) { + /* Do nothing */ + } else { + /* Compatibility code for "%I" just print I */ + return -1; + } + return 0; +} +/* + * Decoded size identifier in format string, and skip format to next charater + */ +SECUREC_INLINE int SecDecodeSize(SecChar ch, SecFormatAttr *attr, const SecChar **format) +{ + switch (ch) { + case SECUREC_CHAR('l'): + if (**format == SECUREC_CHAR('l')) { + *format = *format + 1; + attr->flags |= SECUREC_FLAG_LONGLONG; /* For long long */ + } else { + attr->flags |= SECUREC_FLAG_LONG; /* For long int or wchar_t */ + } + break; +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + case SECUREC_CHAR('z'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('Z'): + attr->flags |= SECUREC_FLAG_SIZE; + break; + case SECUREC_CHAR('j'): + attr->flags |= SECUREC_FLAG_INTMAX; + break; +#endif + case SECUREC_CHAR('t'): + attr->flags |= SECUREC_FLAG_PTRDIFF; + break; + case SECUREC_CHAR('q'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('L'): + attr->flags |= (SECUREC_FLAG_LONGLONG | SECUREC_FLAG_LONG_DOUBLE); + break; + case SECUREC_CHAR('I'): + if (SecDecodeSizeI(attr, format) != 0) { + /* Compatibility code for "%I" just print I */ + return -1; + } + break; + case SECUREC_CHAR('h'): + if (**format == SECUREC_CHAR('h')) { + *format = *format + 1; + attr->flags |= SECUREC_FLAG_CHAR; /* For char */ + } else { + attr->flags |= SECUREC_FLAG_SHORT; /* For short int */ + } + break; + case SECUREC_CHAR('w'): + attr->flags |= SECUREC_FLAG_WIDECHAR; /* For wide char */ + break; + default: + /* Do nothing */ + break; + } + return 0; +} + +/* + * Decoded char type identifier + */ +SECUREC_INLINE void SecDecodeTypeC(SecFormatAttr *attr, unsigned int c) +{ + attr->textLen = 1; /* Only 1 wide character */ + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && !(defined(__hpux)) && !(defined(SECUREC_ON_SOLARIS)) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#endif + +#ifdef SECUREC_FOR_WCHAR + if ((attr->flags & SECUREC_FLAG_SHORT) != 0) { + /* Get multibyte character from argument */ + attr->buffer.str[0] = (char)c; + attr->text.str = attr->buffer.str; + attr->textIsWide = 0; + } else { + attr->buffer.wStr[0] = (wchar_t)c; + attr->text.wStr = attr->buffer.wStr; + attr->textIsWide = 1; + } +#else /* Not SECUREC_FOR_WCHAR */ + if ((attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) != 0) { +#if SECUREC_HAVE_WCHART + attr->buffer.wStr[0] = (wchar_t)c; + attr->text.wStr = attr->buffer.wStr; + attr->textIsWide = 1; +#else + attr->textLen = 0; /* Ignore unsupported characters */ + attr->fldWidth = 0; /* No paddings */ +#endif + } else { + /* Get multibyte character from argument */ + attr->buffer.str[0] = (char)c; + attr->text.str = attr->buffer.str; + attr->textIsWide = 0; + } +#endif +} + +SECUREC_INLINE void SecDecodeTypeSchar(SecFormatAttr *attr) +{ + if (attr->text.str == NULL) { + /* + * Literal string to print null ptr, define it as array rather than const text area + * To avoid gcc warning with pointing const text with variable + */ + static char strNullString[SECUREC_NULL_STRING_SIZE] = "(null)"; + attr->text.str = strNullString; + } + if (attr->precision == -1) { + /* Precision NOT assigned */ + /* The strlen performance is high when the string length is greater than 32 */ + attr->textLen = (int)strlen(attr->text.str); + } else { + /* Precision assigned */ + size_t textLen; + SECUREC_CALC_STR_LEN(attr->text.str, (size_t)(unsigned int)attr->precision, &textLen); + attr->textLen = (int)textLen; + } +} + +SECUREC_INLINE void SecDecodeTypeSwchar(SecFormatAttr *attr) +{ +#if SECUREC_HAVE_WCHART + size_t textLen; + attr->textIsWide = 1; + if (attr->text.wStr == NULL) { + /* + * Literal string to print null ptr, define it as array rather than const text area + * To avoid gcc warning with pointing const text with variable + */ + static wchar_t wStrNullString[SECUREC_NULL_STRING_SIZE] = { L'(', L'n', L'u', L'l', L'l', L')', L'\0', L'\0' }; + attr->text.wStr = wStrNullString; + } + /* The textLen in wchar_t,when precision is -1, it is unlimited */ + SECUREC_CALC_WSTR_LEN(attr->text.wStr, (size_t)(unsigned int)attr->precision, &textLen); + attr->textLen = (int)textLen; +#else + attr->textLen = 0; +#endif +} + +/* + * Decoded string identifier + */ +SECUREC_INLINE void SecDecodeTypeS(SecFormatAttr *attr, char *argPtr) +{ +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && (!defined(SECUREC_ON_UNIX)) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#endif + attr->text.str = argPtr; +#ifdef SECUREC_FOR_WCHAR +#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) + if ((attr->flags & SECUREC_FLAG_LONG) == 0) { + attr->flags |= SECUREC_FLAG_SHORT; + } +#endif + if ((attr->flags & SECUREC_FLAG_SHORT) != 0) { + /* The textLen now contains length in multibyte chars */ + SecDecodeTypeSchar(attr); + } else { + /* The textLen now contains length in wide chars */ + SecDecodeTypeSwchar(attr); + } +#else /* SECUREC_FOR_WCHAR */ + if ((attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) != 0) { + /* The textLen now contains length in wide chars */ + SecDecodeTypeSwchar(attr); + } else { + /* The textLen now contains length in multibyte chars */ + SecDecodeTypeSchar(attr); + } +#endif /* SECUREC_FOR_WCHAR */ + if (attr->textLen < 0) { + attr->textLen = 0; + } +} + +/* + * Write one character to dest buffer + */ +SECUREC_INLINE void SecOutputOneChar(SecChar ch, SecPrintfStream *stream, int *counter) +{ + /* Count must be reduced first, In order to identify insufficient length */ + stream->count -= (int)(sizeof(SecChar)); + if (stream->count >= 0) { + *((SecChar *)(void *)(stream->cur)) = (SecChar)ch; + stream->cur += sizeof(SecChar); + *counter = *(counter) + 1; + return; + } + /* No enough length */ + *counter = -1; +} + +/* + * Check precison in format + */ +SECUREC_INLINE int SecDecodePrecision(SecChar ch, SecFormatAttr *attr) +{ + if (attr->dynPrecision == 0) { + /* Add digit to current precision */ + if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->precision)) { + return -1; + } + attr->precision = (int)SECUREC_MUL_TEN((unsigned int)attr->precision) + + (unsigned char)(ch - SECUREC_CHAR('0')); + } else { + if (attr->precision < 0) { + attr->precision = -1; + } + if (attr->precision > SECUREC_MAX_WIDTH_LEN) { + return -1; + } + } + return 0; +} + +/* + * Check width in format + */ +SECUREC_INLINE int SecDecodeWidth(SecChar ch, SecFormatAttr *attr, SecFmtState lastState) +{ + if (attr->dynWidth == 0) { + if (lastState != STAT_WIDTH) { + attr->fldWidth = 0; + } + if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->fldWidth)) { + return -1; + } + attr->fldWidth = (int)SECUREC_MUL_TEN((unsigned int)attr->fldWidth) + + (unsigned char)(ch - SECUREC_CHAR('0')); + } else { + if (attr->fldWidth < 0) { + attr->flags |= SECUREC_FLAG_LEFT; + attr->fldWidth = (-attr->fldWidth); + if (attr->fldWidth > SECUREC_MAX_WIDTH_LEN) { + return -1; + } + } + } + return 0; +} + +/* + * The sprintf_s function processes the wide character as a parameter for %C + * The swprintf_s function processes the multiple character as a parameter for %C + */ +SECUREC_INLINE void SecUpdateWcharFlags(SecFormatAttr *attr) +{ + if ((attr->flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) == 0) { +#ifdef SECUREC_FOR_WCHAR + attr->flags |= SECUREC_FLAG_SHORT; +#else + attr->flags |= SECUREC_FLAG_WIDECHAR; +#endif + } +} +/* + * When encountering %S, current just same as %C + */ +SECUREC_INLINE void SecUpdateWstringFlags(SecFormatAttr *attr) +{ + SecUpdateWcharFlags(attr); +} + +#if SECUREC_IN_KERNEL +SECUREC_INLINE void SecUpdatePointFlagsForKernel(SecFormatAttr *attr) +{ + /* Width is not set */ + if (attr->fldWidth <= 0) { + attr->flags |= SECUREC_FLAG_LEADZERO; + attr->fldWidth = 2 * sizeof(void *); /* 2 x byte number is the length of hex */ + } + if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) { + /* Alternate form means '0x' prefix */ + attr->prefix[0] = SECUREC_CHAR('0'); + attr->prefix[1] = SECUREC_CHAR('x'); + attr->prefixLen = SECUREC_PREFIX_LEN; + } + attr->flags |= SECUREC_FLAG_LONG; /* Converting a long */ +} +#endif + +SECUREC_INLINE void SecUpdatePointFlags(SecFormatAttr *attr) +{ + attr->flags |= SECUREC_FLAG_POINTER; +#if SECUREC_IN_KERNEL + SecUpdatePointFlagsForKernel(attr); +#else +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) && (!defined(SECUREC_ON_UNIX)) +#if defined(SECUREC_VXWORKS_PLATFORM) + attr->precision = 1; +#else + attr->precision = 0; +#endif + attr->flags |= SECUREC_FLAG_ALTERNATE; /* "0x" is not default prefix in UNIX */ + attr->digits = g_itoaLowerDigits; +#else /* On unix or win */ +#if defined(_AIX) || defined(SECUREC_ON_SOLARIS) + attr->precision = 1; +#else + attr->precision = 2 * sizeof(void *); /* 2 x byte number is the length of hex */ +#endif +#if defined(SECUREC_ON_UNIX) + attr->digits = g_itoaLowerDigits; +#else + attr->digits = g_itoaUpperDigits; +#endif +#endif + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#endif + +#ifdef SECUREC_ON_64BITS + attr->flags |= SECUREC_FLAG_I64; /* Converting an int64 */ +#else + attr->flags |= SECUREC_FLAG_LONG; /* Converting a long */ +#endif + /* Set up for %#p on different system */ + if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) { + /* Alternate form means '0x' prefix */ + attr->prefix[0] = SECUREC_CHAR('0'); +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) + attr->prefix[1] = SECUREC_CHAR('x'); +#else + attr->prefix[1] = (SecChar)(attr->digits[16]); /* 16 for 'x' or 'X' */ +#endif +#if defined(_AIX) || defined(SECUREC_ON_SOLARIS) + attr->prefixLen = 0; +#else + attr->prefixLen = SECUREC_PREFIX_LEN; +#endif + } +#endif +} + +SECUREC_INLINE void SecUpdateXpxFlags(SecFormatAttr *attr, SecChar ch) +{ + /* Use unsigned lower hex output for 'x' */ + attr->digits = g_itoaLowerDigits; + attr->radix = SECUREC_RADIX_HEX; + switch (ch) { + case SECUREC_CHAR('p'): + /* Print a pointer */ + SecUpdatePointFlags(attr); + break; + case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */ + /* Unsigned upper hex output */ + attr->digits = g_itoaUpperDigits; + /* fall-through */ /* FALLTHRU */ + default: + /* For %#x or %#X */ + if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) { + /* Alternate form means '0x' prefix */ + attr->prefix[0] = SECUREC_CHAR('0'); + attr->prefix[1] = (SecChar)(attr->digits[16]); /* 16 for 'x' or 'X' */ + attr->prefixLen = SECUREC_PREFIX_LEN; + } + break; + } +} +SECUREC_INLINE void SecUpdateOudiFlags(SecFormatAttr *attr, SecChar ch) +{ + /* Do not set digits here */ + switch (ch) { + case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */ + /* For signed decimal output */ + attr->flags |= SECUREC_FLAG_SIGNED; + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('u'): + attr->radix = SECUREC_RADIX_DECIMAL; + attr->digits = g_itoaLowerDigits; + break; + case SECUREC_CHAR('o'): + /* For unsigned octal output */ + attr->radix = SECUREC_RADIX_OCTAL; + attr->digits = g_itoaLowerDigits; + if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) { + /* Alternate form means force a leading 0 */ + attr->flags |= SECUREC_FLAG_FORCE_OCTAL; + } + break; + default: + /* Do nothing */ + break; + } +} + +#if SECUREC_ENABLE_SPRINTF_FLOAT +SECUREC_INLINE void SecFreeFloatBuffer(SecFloatAdapt *floatAdapt) +{ + if (floatAdapt->floatBuffer != NULL) { + SECUREC_FREE(floatAdapt->floatBuffer); + } + if (floatAdapt->allocatedFmtStr != NULL) { + SECUREC_FREE(floatAdapt->allocatedFmtStr); + } + floatAdapt->floatBuffer = NULL; + floatAdapt->allocatedFmtStr = NULL; + floatAdapt->fmtStr = NULL; + floatAdapt->bufferSize = 0; +} + +SECUREC_INLINE void SecSeekToFrontPercent(const SecChar **format) +{ + const SecChar *fmt = *format; + while (*fmt != SECUREC_CHAR('%')) { /* Must meet '%' */ + --fmt; + } + *format = fmt; +} + +/* Init float format, return 0 is OK */ +SECUREC_INLINE int SecInitFloatFmt(SecFloatAdapt *floatFmt, const SecChar *format) +{ + const SecChar *fmt = format - 2; /* Sub 2 to the position before 'f' or 'g' */ + int fmtStrLen; + int i; + + SecSeekToFrontPercent(&fmt); + /* Now fmt point to '%' */ + fmtStrLen = (int)(size_t)(format - fmt) + 1; /* With ending terminator */ + if (fmtStrLen > (int)sizeof(floatFmt->buffer)) { + /* When buffer is NOT enough, alloc a new buffer */ + floatFmt->allocatedFmtStr = (char *)SECUREC_MALLOC((size_t)((unsigned int)fmtStrLen)); + if (floatFmt->allocatedFmtStr == NULL) { + return -1; + } + floatFmt->fmtStr = floatFmt->allocatedFmtStr; + } else { + floatFmt->fmtStr = floatFmt->buffer; + floatFmt->allocatedFmtStr = NULL; /* Must set to NULL, later code free memory based on this identity */ + } + + for (i = 0; i < fmtStrLen - 1; ++i) { + /* Convert wchar to char */ + floatFmt->fmtStr[i] = (char)(fmt[i]); /* Copy the format string */ + } + floatFmt->fmtStr[fmtStrLen - 1] = '\0'; + + return 0; +} + +/* Init float buffer and format, return 0 is OK */ +SECUREC_INLINE int SecInitFloatBuffer(SecFloatAdapt *floatAdapt, const SecChar *format, SecFormatAttr *attr) +{ + floatAdapt->allocatedFmtStr = NULL; + floatAdapt->fmtStr = NULL; + floatAdapt->floatBuffer = NULL; + /* Compute the precision value */ + if (attr->precision < 0) { + attr->precision = SECUREC_FLOAT_DEFAULT_PRECISION; + } + /* + * Calc buffer size to store double value + * The maximum length of SECUREC_MAX_WIDTH_LEN is enough + */ + if ((attr->flags & SECUREC_FLAG_LONG_DOUBLE) != 0) { + if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE_LB)) { + return -1; + } + /* Long double needs to meet the basic print length */ + floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE_LB + attr->precision + SECUREC_FLOAT_BUF_EXT; + } else { + if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE)) { + return -1; + } + /* Double needs to meet the basic print length */ + floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE + attr->precision + SECUREC_FLOAT_BUF_EXT; + } + if (attr->fldWidth > floatAdapt->bufferSize) { + floatAdapt->bufferSize = attr->fldWidth + SECUREC_FLOAT_BUF_EXT; + } + + if (floatAdapt->bufferSize > SECUREC_BUFFER_SIZE) { + /* The current vlaue of SECUREC_BUFFER_SIZE could NOT store the formatted float string */ + floatAdapt->floatBuffer = (char *)SECUREC_MALLOC(((size_t)(unsigned int)floatAdapt->bufferSize)); + if (floatAdapt->floatBuffer == NULL) { + return -1; + } + attr->text.str = floatAdapt->floatBuffer; + } else { + attr->text.str = attr->buffer.str; /* Output buffer for float string with default size */ + } + + if (SecInitFloatFmt(floatAdapt, format) != 0) { + if (floatAdapt->floatBuffer != NULL) { + SECUREC_FREE(floatAdapt->floatBuffer); + floatAdapt->floatBuffer = NULL; + } + return -1; + } + return 0; +} +#endif + +SECUREC_INLINE SecInt64 SecUpdateNegativeChar(SecFormatAttr *attr, char ch) +{ + SecInt64 num64 = ch; /* Sign extend */ + if (num64 >= 128) { /* 128 on some platform, char is always unsigned */ + unsigned char tmp = (unsigned char)(~((unsigned char)ch)); + num64 = tmp + 1; + attr->flags |= SECUREC_FLAG_NEGATIVE; + } + return num64; +} + +/* + * If the precision is not satisfied, zero is added before the string + */ +SECUREC_INLINE void SecNumberSatisfyPrecision(SecFormatAttr *attr) +{ + int precision; + if (attr->precision < 0) { + precision = 1; /* Default precision 1 */ + } else { +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#else + if ((attr->flags & SECUREC_FLAG_POINTER) == 0) { + attr->flags &= ~SECUREC_FLAG_LEADZERO; + } +#endif + if (attr->precision > SECUREC_MAX_PRECISION) { + attr->precision = SECUREC_MAX_PRECISION; + } + precision = attr->precision; + } + while (attr->textLen < precision) { + --attr->text.str; + *(attr->text.str) = '0'; + ++attr->textLen; + } +} + +/* + * Add leading zero for %#o + */ +SECUREC_INLINE void SecNumberForceOctal(SecFormatAttr *attr) +{ + /* Force a leading zero if FORCEOCTAL flag set */ + if ((attr->flags & SECUREC_FLAG_FORCE_OCTAL) != 0 && + (attr->textLen == 0 || attr->text.str[0] != '0')) { + --attr->text.str; + *(attr->text.str) = '0'; + ++attr->textLen; + } +} + +SECUREC_INLINE void SecUpdateSignedNumberPrefix(SecFormatAttr *attr) +{ + if ((attr->flags & SECUREC_FLAG_SIGNED) == 0) { + return; + } + if ((attr->flags & SECUREC_FLAG_NEGATIVE) != 0) { + /* Prefix is '-' */ + attr->prefix[0] = SECUREC_CHAR('-'); + attr->prefixLen = 1; + return; + } + if ((attr->flags & SECUREC_FLAG_SIGN) != 0) { + /* Prefix is '+' */ + attr->prefix[0] = SECUREC_CHAR('+'); + attr->prefixLen = 1; + return; + } + if ((attr->flags & SECUREC_FLAG_SIGN_SPACE) != 0) { + /* Prefix is ' ' */ + attr->prefix[0] = SECUREC_CHAR(' '); + attr->prefixLen = 1; + return; + } + return; +} + +SECUREC_INLINE void SecNumberCompatZero(SecFormatAttr *attr) +{ +#if SECUREC_IN_KERNEL + if ((attr->flags & SECUREC_FLAG_POINTER) != 0) { + static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(null)"; + attr->text.str = strNullPointer; + attr->textLen = 6; /* Length of (null) is 6 */ + attr->flags &= ~SECUREC_FLAG_LEADZERO; + attr->prefixLen = 0; + if (attr->precision >= 0 && attr->precision < attr->textLen) { + attr->textLen = attr->precision; + } + } + if ((attr->flags & SECUREC_FLAG_POINTER) == 0 && attr->radix == SECUREC_RADIX_HEX && + (attr->flags & SECUREC_FLAG_ALTERNATE) != 0) { + /* Add 0x prefix for %x or %X, the prefix string has been set before */ + attr->prefixLen = SECUREC_PREFIX_LEN; + } +#elif defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && (!defined(SECUREC_ON_UNIX)) + if ((attr->flags & SECUREC_FLAG_POINTER) != 0) { + static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(nil)"; + attr->text.str = strNullPointer; + attr->textLen = 5; /* Length of (nil) is 5 */ + attr->flags &= ~SECUREC_FLAG_LEADZERO; + } +#elif defined(SECUREC_VXWORKS_PLATFORM) || defined(__hpux) + if ((attr->flags & SECUREC_FLAG_POINTER) != 0 && (attr->flags & SECUREC_FLAG_ALTERNATE) != 0) { + /* Add 0x prefix for %p, the prefix string has been set before */ + attr->prefixLen = SECUREC_PREFIX_LEN; + } +#endif + (void)attr; /* To clear e438 last value assigned not used , the compiler will optimize this code */ +} + +#ifdef SECUREC_FOR_WCHAR +/* + * Formatting output core functions for wchar version.Called by a function such as vswprintf_s + * The argList must not be declare as const + */ +SECUREC_INLINE int SecOutputSW(SecPrintfStream *stream, const wchar_t *cFormat, va_list argList) +#else +/* + * Formatting output core functions for char version.Called by a function such as vsnprintf_s + */ +SECUREC_INLINE int SecOutputS(SecPrintfStream *stream, const char *cFormat, va_list argList) +#endif +{ + const SecChar *format = cFormat; + int charsOut; /* Characters written */ + int noOutput = 0; /* Must be initialized or compiler alerts */ + SecFmtState state; + SecFormatAttr formatAttr; + + formatAttr.flags = 0; + formatAttr.textIsWide = 0; /* Flag for buffer contains wide chars */ + formatAttr.fldWidth = 0; + formatAttr.precision = 0; + formatAttr.dynWidth = 0; + formatAttr.dynPrecision = 0; + formatAttr.digits = g_itoaUpperDigits; + formatAttr.radix = SECUREC_RADIX_DECIMAL; + formatAttr.padding = 0; + formatAttr.textLen = 0; + formatAttr.text.str = NULL; + formatAttr.prefixLen = 0; + formatAttr.prefix[0] = SECUREC_CHAR('\0'); + formatAttr.prefix[1] = SECUREC_CHAR('\0'); + charsOut = 0; + state = STAT_NORMAL; /* Starting state */ + + /* Loop each format character */ + while (*format != SECUREC_CHAR('\0') && charsOut >= 0) { + SecFmtState lastState = state; + SecChar ch = *format; /* Currently read character */ + ++format; + state = SecDecodeState(ch, lastState); + switch (state) { + case STAT_NORMAL: + SecOutputOneChar(ch, stream, &charsOut); + continue; + case STAT_PERCENT: + /* Set default values */ + noOutput = 0; + formatAttr.prefixLen = 0; + formatAttr.textLen = 0; + formatAttr.flags = 0; + formatAttr.fldWidth = 0; + formatAttr.precision = -1; + formatAttr.textIsWide = 0; + formatAttr.dynWidth = 0; + formatAttr.dynPrecision = 0; + break; + case STAT_FLAG: + /* Set flag based on which flag character */ + SecDecodeFlags(ch, &formatAttr); + break; + case STAT_WIDTH: + /* Update width value */ + if (ch == SECUREC_CHAR('*')) { + /* get width from arg list */ + formatAttr.fldWidth = (int)va_arg(argList, int); + formatAttr.dynWidth = 1; + } + if (SecDecodeWidth(ch, &formatAttr, lastState) != 0) { + return -1; + } + break; + case STAT_DOT: + formatAttr.precision = 0; + break; + case STAT_PRECIS: + /* Update precison value */ + if (ch == SECUREC_CHAR('*')) { + /* Get precision from arg list */ + formatAttr.precision = (int)va_arg(argList, int); + formatAttr.dynPrecision = 1; + } + if (SecDecodePrecision(ch, &formatAttr) != 0) { + return -1; + } + break; + case STAT_SIZE: + /* Read a size specifier, set the formatAttr.flags based on it, and skip format to next charater */ + if (SecDecodeSize(ch, &formatAttr, &format) != 0) { + /* Compatibility code for "%I" just print I */ + SecOutputOneChar(ch, stream, &charsOut); + state = STAT_NORMAL; + continue; + } + break; + case STAT_TYPE: + switch (ch) { + case SECUREC_CHAR('C'): /* Wide char */ + SecUpdateWcharFlags(&formatAttr); + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('c'): { + unsigned int cValue = (unsigned int)va_arg(argList, int); + SecDecodeTypeC(&formatAttr, cValue); + break; + } + case SECUREC_CHAR('S'): /* Wide char string */ + SecUpdateWstringFlags(&formatAttr); + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('s'): { + char *argPtr = (char *)va_arg(argList, char *); + SecDecodeTypeS(&formatAttr, argPtr); + break; + } + case SECUREC_CHAR('G'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('g'): /* fall-through */ /* FALLTHRU */ + /* Default precision is 1 for g or G */ + if (formatAttr.precision == 0) { + formatAttr.precision = 1; + } + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('E'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('e'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('f'): { +#if SECUREC_ENABLE_SPRINTF_FLOAT + /* Add following code to call system sprintf API for float number */ + SecFloatAdapt floatAdapt; + noOutput = 1; /* It's no more data needs to be written */ + + /* Now format is pointer to the next character of 'f' */ + if (SecInitFloatBuffer(&floatAdapt, format, &formatAttr) != 0) { + break; + } + + if ((formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) != 0) { +#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && SECUREC_ENABLE_SPRINTF_LONG_DOUBLE + long double tmp = (long double)va_arg(argList, long double); + SecFormatLongDouble(&formatAttr, &floatAdapt, tmp); +#else + double tmp = (double)va_arg(argList, double); + SecFormatDouble(&formatAttr, &floatAdapt, tmp); +#endif + } else { + double tmp = (double)va_arg(argList, double); + SecFormatDouble(&formatAttr, &floatAdapt, tmp); + } + + /* Only need write formated float string */ + SecWriteFloatText(stream, &formatAttr, &charsOut); + SecFreeFloatBuffer(&floatAdapt); + break; +#else + return -1; +#endif + } + case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('p'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('x'): /* fall-through */ /* FALLTHRU */ + SecUpdateXpxFlags(&formatAttr, ch); + /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('u'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('o'): { + SecInt64 num64; + SecUpdateOudiFlags(&formatAttr, ch); + /* Read argument into variable num64. Be careful, depend on the order of judgment */ + if ((formatAttr.flags & SECUREC_FLAG_I64) != 0 || + (formatAttr.flags & SECUREC_FLAG_LONGLONG) != 0) { + num64 = (SecInt64)va_arg(argList, SecInt64); /* Maximum Bit Width sign bit unchanged */ + } else if ((formatAttr.flags & SECUREC_FLAG_LONG) != 0) { + num64 = SECUREC_GET_LONG_FROM_ARG(formatAttr); + } else if ((formatAttr.flags & SECUREC_FLAG_CHAR) != 0) { + num64 = SECUREC_GET_CHAR_FROM_ARG(formatAttr); + } else if ((formatAttr.flags & SECUREC_FLAG_SHORT) != 0) { + num64 = SECUREC_GET_SHORT_FROM_ARG(formatAttr); +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + } else if ((formatAttr.flags & SECUREC_FLAG_PTRDIFF) != 0) { + num64 = (ptrdiff_t)va_arg(argList, ptrdiff_t); /* Sign extend */ + } else if ((formatAttr.flags & SECUREC_FLAG_SIZE) != 0) { + num64 = SECUREC_GET_SIZE_FROM_ARG(formatAttr); + } else if ((formatAttr.flags & SECUREC_FLAG_INTMAX) != 0) { + num64 = (SecInt64)va_arg(argList, SecInt64); +#endif + } else { + num64 = SECUREC_GET_INT_FROM_ARG(formatAttr); + } + + /* The order of the following calls must be correct */ + SecNumberToBuffer(&formatAttr, num64); + SecNumberSatisfyPrecision(&formatAttr); + SecNumberForceOctal(&formatAttr); + SecUpdateSignedNumberPrefix(&formatAttr); + if (num64 == 0) { + SecNumberCompatZero(&formatAttr); + } + break; + } + default: + /* Do nothing */ + break; + } + + if (noOutput == 0) { + /* Calculate amount of padding */ + formatAttr.padding = (formatAttr.fldWidth - formatAttr.textLen) - formatAttr.prefixLen; + + /* Put out the padding, prefix, and text, in the correct order */ + SecWriteLeftPadding(stream, &formatAttr, &charsOut); + SecWritePrefix(stream, &formatAttr, &charsOut); + SecWriteLeadingZero(stream, &formatAttr, &charsOut); + SecWriteText(stream, &formatAttr, &charsOut); + SecWriteRightPadding(stream, &formatAttr, &charsOut); + } + break; + case STAT_INVALID: /* fall-through */ /* FALLTHRU */ + default: + return -1; /* Input format is wrong(STAT_INVALID), directly return */ + } + } + + if (state != STAT_NORMAL && state != STAT_TYPE) { + return -1; + } + + return charsOut; /* The number of characters written */ +} + +/* + * Output one zero character zero into the SecPrintfStream structure + * If there is not enough space, make sure f->count is less than 0 + */ +SECUREC_INLINE int SecPutZeroChar(SecPrintfStream *str) +{ + --str->count; + if (str->count >= 0) { + *(str->cur) = '\0'; + str->cur = str->cur + 1; + return 0; + } + return -1; +} + +#endif /* OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 */ + diff --git a/third_party/bounds_checking_function/src/scanf_s.c b/third_party/bounds_checking_function/src/scanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..0ae200e682e4a65bc9c2771c69ccf49a3f0a35b4 --- /dev/null +++ b/third_party/bounds_checking_function/src/scanf_s.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: scanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +/* + * + * The scanf_s function is equivalent to fscanf_s with the argument stdin interposed before the arguments to scanf_s + * The scanf_s function reads data from the standard input stream stdin and + * writes the data into the location that's given by argument. Each argument + * must be a pointer to a variable of a type that corresponds to a type specifier + * in format. If copying occurs between strings that overlap, the behavior is + * undefined. + * + * + * format Format control string. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * Returns the number of fields successfully converted and assigned; + * the return value does not include fields that were read but not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int scanf_s(const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vscanf_s(format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} + diff --git a/third_party/bounds_checking_function/src/secinput.h b/third_party/bounds_checking_function/src/secinput.h new file mode 100644 index 0000000000000000000000000000000000000000..15c10451a1112723d884b47b871ad7ffed455a25 --- /dev/null +++ b/third_party/bounds_checking_function/src/secinput.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: Define macro, data struct, and declare function prototype, + * which is used by input.inl, secureinput_a.c and secureinput_w.c. + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SEC_INPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C +#define SEC_INPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C +#include "securecutil.h" + +#define SECUREC_SCANF_EINVAL (-1) +#define SECUREC_SCANF_ERROR_PARA (-2) + +/* For internal stream flag */ +#define SECUREC_MEM_STR_FLAG 0x01U +#define SECUREC_FILE_STREAM_FLAG 0x02U +#define SECUREC_PIPE_STREAM_FLAG 0x04U +#define SECUREC_LOAD_FILE_TO_MEM_FLAG 0x08U + +#define SECUREC_UCS_BOM_HEADER_SIZE 2U +#define SECUREC_UCS_BOM_HEADER_BE_1ST 0xfeU +#define SECUREC_UCS_BOM_HEADER_BE_2ST 0xffU +#define SECUREC_UCS_BOM_HEADER_LE_1ST 0xffU +#define SECUREC_UCS_BOM_HEADER_LE_2ST 0xfeU +#define SECUREC_UTF8_BOM_HEADER_SIZE 3U +#define SECUREC_UTF8_BOM_HEADER_1ST 0xefU +#define SECUREC_UTF8_BOM_HEADER_2ND 0xbbU +#define SECUREC_UTF8_BOM_HEADER_3RD 0xbfU +#define SECUREC_UTF8_LEAD_1ST 0xe0U +#define SECUREC_UTF8_LEAD_2ND 0x80U + +#define SECUREC_BEGIN_WITH_UCS_BOM(s, len) ((len) >= SECUREC_UCS_BOM_HEADER_SIZE && \ + (((unsigned char)((s)[0]) == SECUREC_UCS_BOM_HEADER_LE_1ST && \ + (unsigned char)((s)[1]) == SECUREC_UCS_BOM_HEADER_LE_2ST) || \ + ((unsigned char)((s)[0]) == SECUREC_UCS_BOM_HEADER_BE_1ST && \ + (unsigned char)((s)[1]) == SECUREC_UCS_BOM_HEADER_BE_2ST))) + +#define SECUREC_BEGIN_WITH_UTF8_BOM(s, len) ((len) >= SECUREC_UTF8_BOM_HEADER_SIZE && \ + (unsigned char)((s)[0]) == SECUREC_UTF8_BOM_HEADER_1ST && \ + (unsigned char)((s)[1]) == SECUREC_UTF8_BOM_HEADER_2ND && \ + (unsigned char)((s)[2]) == SECUREC_UTF8_BOM_HEADER_3RD) + +#ifdef SECUREC_FOR_WCHAR +#define SECUREC_BOM_HEADER_SIZE SECUREC_UCS_BOM_HEADER_SIZE +#define SECUREC_BEGIN_WITH_BOM(s, len) SECUREC_BEGIN_WITH_UCS_BOM((s), (len)) +#else +#define SECUREC_BOM_HEADER_SIZE SECUREC_UTF8_BOM_HEADER_SIZE +#define SECUREC_BEGIN_WITH_BOM(s, len) SECUREC_BEGIN_WITH_UTF8_BOM((s), (len)) +#endif + +typedef struct { + unsigned int flag; /* Mark the properties of input stream */ + char *base; /* The pointer to the header of buffered string */ + const char *cur; /* The pointer to next read position */ + size_t count; /* The size of buffered string in bytes */ +#if SECUREC_ENABLE_SCANF_FILE + FILE *pf; /* The file pointer */ + size_t fileRealRead; + long oriFilePos; /* The original position of file offset when fscanf is called */ +#if !SECUREC_USE_STD_UNGETC + unsigned int lastChar; /* The char code of last input */ + int fUnGet; /* The boolean flag of pushing a char back to read stream */ +#endif +#endif +} SecFileStream; + +#if SECUREC_ENABLE_SCANF_FILE && !SECUREC_USE_STD_UNGETC +#define SECUREC_FILE_STREAM_INIT_FILE(stream, fp) do { \ + (stream)->pf = (fp); \ + (stream)->fileRealRead = 0; \ + (stream)->oriFilePos = 0; \ + (stream)->lastChar = 0; \ + (stream)->fUnGet = 0; \ +} SECUREC_WHILE_ZERO +#elif SECUREC_ENABLE_SCANF_FILE && SECUREC_USE_STD_UNGETC +#define SECUREC_FILE_STREAM_INIT_FILE(stream, fp) do { \ + (stream)->pf = (fp); \ + (stream)->fileRealRead = 0; \ + (stream)->oriFilePos = 0; \ +} SECUREC_WHILE_ZERO +#else +/* Disable file */ +#define SECUREC_FILE_STREAM_INIT_FILE(stream, fp) +#endif + +/* This initialization for eliminating redundant initialization. */ +#define SECUREC_FILE_STREAM_FROM_STRING(stream, buf, cnt) do { \ + (stream)->flag = SECUREC_MEM_STR_FLAG; \ + (stream)->base = NULL; \ + (stream)->cur = (buf); \ + (stream)->count = (cnt); \ + SECUREC_FILE_STREAM_INIT_FILE((stream), NULL); \ +} SECUREC_WHILE_ZERO + +/* This initialization for eliminating redundant initialization. */ +#define SECUREC_FILE_STREAM_FROM_FILE(stream, fp) do { \ + (stream)->flag = SECUREC_FILE_STREAM_FLAG; \ + (stream)->base = NULL; \ + (stream)->cur = NULL; \ + (stream)->count = 0; \ + SECUREC_FILE_STREAM_INIT_FILE((stream), (fp)); \ +} SECUREC_WHILE_ZERO + +/* This initialization for eliminating redundant initialization. */ +#define SECUREC_FILE_STREAM_FROM_STDIN(stream) do { \ + (stream)->flag = SECUREC_PIPE_STREAM_FLAG; \ + (stream)->base = NULL; \ + (stream)->cur = NULL; \ + (stream)->count = 0; \ + SECUREC_FILE_STREAM_INIT_FILE((stream), SECUREC_STREAM_STDIN); \ +} SECUREC_WHILE_ZERO + +#ifdef __cplusplus +extern "C" { +#endif + int SecInputS(SecFileStream *stream, const char *cFormat, va_list argList); + void SecClearDestBuf(const char *buffer, const char *format, va_list argList); +#ifdef SECUREC_FOR_WCHAR + int SecInputSW(SecFileStream *stream, const wchar_t *cFormat, va_list argList); + void SecClearDestBufW(const wchar_t *buffer, const wchar_t *format, va_list argList); +#endif + +/* 20150105 For software and hardware decoupling,such as UMG */ +#ifdef SECUREC_SYSAPI4VXWORKS +#ifdef feof +#undef feof +#endif + extern int feof(FILE *stream); +#endif + +#if defined(SECUREC_SYSAPI4VXWORKS) || defined(SECUREC_CTYPE_MACRO_ADAPT) +#ifndef isspace +#define isspace(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n')) +#endif +#ifndef iswspace +#define iswspace(c) (((c) == L' ') || ((c) == L'\t') || ((c) == L'\r') || ((c) == L'\n')) +#endif +#ifndef isascii +#define isascii(c) (((unsigned char)(c)) <= 0x7f) +#endif +#ifndef isupper +#define isupper(c) ((c) >= 'A' && (c) <= 'Z') +#endif +#ifndef islower +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#endif +#ifndef isalpha +#define isalpha(c) (isupper(c) || (islower(c))) +#endif +#ifndef isdigit +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#endif +#ifndef isxupper +#define isxupper(c) ((c) >= 'A' && (c) <= 'F') +#endif +#ifndef isxlower +#define isxlower(c) ((c) >= 'a' && (c) <= 'f') +#endif +#ifndef isxdigit +#define isxdigit(c) (isdigit(c) || isxupper(c) || isxlower(c)) +#endif +#endif + +#ifdef __cplusplus +} +#endif +/* Reserved file operation macro interface, s is FILE *, i is fileno zero. */ +#ifndef SECUREC_LOCK_FILE +#define SECUREC_LOCK_FILE(s) +#endif + +#ifndef SECUREC_UNLOCK_FILE +#define SECUREC_UNLOCK_FILE(s) +#endif + +#ifndef SECUREC_LOCK_STDIN +#define SECUREC_LOCK_STDIN(i, s) +#endif + +#ifndef SECUREC_UNLOCK_STDIN +#define SECUREC_UNLOCK_STDIN(i, s) +#endif +#endif + diff --git a/third_party/bounds_checking_function/src/securecutil.c b/third_party/bounds_checking_function/src/securecutil.c new file mode 100644 index 0000000000000000000000000000000000000000..70774b25b8f39b3b61e3d0b77d776ba1b38b0a23 --- /dev/null +++ b/third_party/bounds_checking_function/src/securecutil.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: Provides internal functions used by this library, such as memory + * copy and memory move. Besides, include some helper function for + * printf family API, such as SecVsnprintfImpl + * Author: lishunda + * Create: 2014-02-25 + */ + +/* Avoid duplicate header files,not include securecutil.h */ +#include "securecutil.h" + +#if defined(ANDROID) && (SECUREC_HAVE_WCTOMB || SECUREC_HAVE_MBTOWC) +#include +#if SECUREC_HAVE_WCTOMB +/* + * Convert wide characters to narrow multi-bytes + */ +int wctomb(char *s, wchar_t wc) +{ + return wcrtomb(s, wc, NULL); +} +#endif + +#if SECUREC_HAVE_MBTOWC +/* + * Converting narrow multi-byte characters to wide characters + */ +int mbtowc(wchar_t *pwc, const char *s, size_t n) +{ + return mbrtowc(pwc, s, n, NULL); +} +#endif +#endif + diff --git a/third_party/bounds_checking_function/src/securecutil.h b/third_party/bounds_checking_function/src/securecutil.h new file mode 100644 index 0000000000000000000000000000000000000000..38cbd3e61ee3341bbf905402899ad37c6abe7181 --- /dev/null +++ b/third_party/bounds_checking_function/src/securecutil.h @@ -0,0 +1,559 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: Define macro, data struct, and declare internal used function prototype, + * which is used by secure functions. + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SECURECUTIL_H_46C86578_F8FF_4E49_8E64_9B175241761F +#define SECURECUTIL_H_46C86578_F8FF_4E49_8E64_9B175241761F +#include "securec.h" + +#if (defined(_MSC_VER)) && (_MSC_VER >= 1400) +/* Shield compilation alerts using discarded functions and Constant expression to maximize code compatibility */ +#define SECUREC_MASK_MSVC_CRT_WARNING __pragma(warning(push)) \ + __pragma(warning(disable : 4996 4127)) +#define SECUREC_END_MASK_MSVC_CRT_WARNING __pragma(warning(pop)) +#else +#define SECUREC_MASK_MSVC_CRT_WARNING +#define SECUREC_END_MASK_MSVC_CRT_WARNING +#endif +#define SECUREC_WHILE_ZERO SECUREC_MASK_MSVC_CRT_WARNING while (0) SECUREC_END_MASK_MSVC_CRT_WARNING + +/* Automatically identify the platform that supports strnlen function, and use this function to improve performance */ +#ifndef SECUREC_HAVE_STRNLEN +#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L) +#if SECUREC_IN_KERNEL +#define SECUREC_HAVE_STRNLEN 0 +#else +#if defined(__GLIBC__) && __GLIBC__ >= 2 && defined(__GLIBC_MINOR__) && __GLIBC_MINOR__ >= 10 +#define SECUREC_HAVE_STRNLEN 1 +#else +#define SECUREC_HAVE_STRNLEN 0 +#endif +#endif +#else +#define SECUREC_HAVE_STRNLEN 0 +#endif +#endif + +#if SECUREC_IN_KERNEL +/* In kernel disbale functions */ +#ifndef SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF_FILE 0 +#endif +#ifndef SECUREC_ENABLE_SCANF_FLOAT +#define SECUREC_ENABLE_SCANF_FLOAT 0 +#endif +#ifndef SECUREC_ENABLE_SPRINTF_FLOAT +#define SECUREC_ENABLE_SPRINTF_FLOAT 0 +#endif +#ifndef SECUREC_HAVE_MBTOWC +#define SECUREC_HAVE_MBTOWC 0 +#endif +#ifndef SECUREC_HAVE_WCTOMB +#define SECUREC_HAVE_WCTOMB 0 +#endif +#ifndef SECUREC_HAVE_WCHART +#define SECUREC_HAVE_WCHART 0 +#endif +#else /* Not in kernel */ +/* Systems that do not support file, can define this macro to 0. */ +#ifndef SECUREC_ENABLE_SCANF_FILE +#define SECUREC_ENABLE_SCANF_FILE 1 +#endif +#ifndef SECUREC_ENABLE_SCANF_FLOAT +#define SECUREC_ENABLE_SCANF_FLOAT 1 +#endif +/* Systems that do not support float, can define this macro to 0. */ +#ifndef SECUREC_ENABLE_SPRINTF_FLOAT +#define SECUREC_ENABLE_SPRINTF_FLOAT 1 +#endif +#ifndef SECUREC_HAVE_MBTOWC +#define SECUREC_HAVE_MBTOWC 1 +#endif +#ifndef SECUREC_HAVE_WCTOMB +#define SECUREC_HAVE_WCTOMB 1 +#endif +#ifndef SECUREC_HAVE_WCHART +#define SECUREC_HAVE_WCHART 1 +#endif +#endif + +#ifndef SECUREC_USE_STD_UNGETC +#define SECUREC_USE_STD_UNGETC 1 +#endif + +#ifndef SECUREC_ENABLE_INLINE +#define SECUREC_ENABLE_INLINE 0 +#endif + +#ifndef SECUREC_INLINE +#if SECUREC_ENABLE_INLINE +#define SECUREC_INLINE static inline +#else +#define SECUREC_INLINE static +#endif +#endif + +#ifndef SECUREC_WARP_OUTPUT +#if SECUREC_IN_KERNEL +#define SECUREC_WARP_OUTPUT 1 +#else +#define SECUREC_WARP_OUTPUT 0 +#endif +#endif + +#ifndef SECUREC_STREAM_STDIN +#define SECUREC_STREAM_STDIN stdin +#endif + +#define SECUREC_MUL_SIXTEEN(x) ((x) << 4U) +#define SECUREC_MUL_EIGHT(x) ((x) << 3U) +#define SECUREC_MUL_TEN(x) ((((x) << 2U) + (x)) << 1U) +/* Limited format input and output width, use signed integer */ +#define SECUREC_MAX_WIDTH_LEN_DIV_TEN 21474836 +#define SECUREC_MAX_WIDTH_LEN (SECUREC_MAX_WIDTH_LEN_DIV_TEN * 10) +/* Is the x multiplied by 10 greater than */ +#define SECUREC_MUL_TEN_ADD_BEYOND_MAX(x) (((x) > SECUREC_MAX_WIDTH_LEN_DIV_TEN)) + +#define SECUREC_FLOAT_BUFSIZE (309 + 40) /* Max length of double value */ +#define SECUREC_FLOAT_BUFSIZE_LB (4932 + 40) /* Max length of long double value */ +#define SECUREC_FLOAT_DEFAULT_PRECISION 6 + +/* This macro does not handle pointer equality or integer overflow */ +#define SECUREC_MEMORY_NO_OVERLAP(dest, src, count) \ + (((src) < (dest) && ((const char *)(src) + (count)) <= (char *)(dest)) || \ + ((dest) < (src) && ((char *)(dest) + (count)) <= (const char *)(src))) + +#define SECUREC_MEMORY_IS_OVERLAP(dest, src, count) \ + (((src) < (dest) && ((const char *)(src) + (count)) > (char *)(dest)) || \ + ((dest) < (src) && ((char *)(dest) + (count)) > (const char *)(src))) + +/* + * Check whether the strings overlap, len is the length of the string not include terminator + * Length is related to data type char or wchar , do not force conversion of types + */ +#define SECUREC_STRING_NO_OVERLAP(dest, src, len) \ + (((src) < (dest) && ((src) + (len)) < (dest)) || \ + ((dest) < (src) && ((dest) + (len)) < (src))) + +/* + * Check whether the strings overlap for strcpy wcscpy function, dest len and src Len are not include terminator + * Length is related to data type char or wchar , do not force conversion of types + */ +#define SECUREC_STRING_IS_OVERLAP(dest, src, len) \ + (((src) < (dest) && ((src) + (len)) >= (dest)) || \ + ((dest) < (src) && ((dest) + (len)) >= (src))) + +/* + * Check whether the strings overlap for strcat wcscat function, dest len and src Len are not include terminator + * Length is related to data type char or wchar , do not force conversion of types + */ +#define SECUREC_CAT_STRING_IS_OVERLAP(dest, destLen, src, srcLen) \ + (((dest) < (src) && ((dest) + (destLen) + (srcLen)) >= (src)) || \ + ((src) < (dest) && ((src) + (srcLen)) >= (dest))) + +#if SECUREC_HAVE_STRNLEN +#define SECUREC_CALC_STR_LEN(str, maxLen, outLen) do { \ + *(outLen) = strnlen((str), (maxLen)); \ +} SECUREC_WHILE_ZERO +#define SECUREC_CALC_STR_LEN_OPT(str, maxLen, outLen) do { \ + if ((maxLen) > 8) { \ + /* Optimization or len less then 8 */ \ + if (*((str) + 0) == '\0') { \ + *(outLen) = 0; \ + } else if (*((str) + 1) == '\0') { \ + *(outLen) = 1; \ + } else if (*((str) + 2) == '\0') { \ + *(outLen) = 2; \ + } else if (*((str) + 3) == '\0') { \ + *(outLen) = 3; \ + } else if (*((str) + 4) == '\0') { \ + *(outLen) = 4; \ + } else if (*((str) + 5) == '\0') { \ + *(outLen) = 5; \ + } else if (*((str) + 6) == '\0') { \ + *(outLen) = 6; \ + } else if (*((str) + 7) == '\0') { \ + *(outLen) = 7; \ + } else if (*((str) + 8) == '\0') { \ + /* Optimization with a length of 8 */ \ + *(outLen) = 8; \ + } else { \ + /* The offset is 8 because the performance of 8 byte alignment is high */ \ + *(outLen) = 8 + strnlen((str) + 8, (maxLen) - 8); \ + } \ + } else { \ + SECUREC_CALC_STR_LEN((str), (maxLen), (outLen)); \ + } \ +} SECUREC_WHILE_ZERO +#else +#define SECUREC_CALC_STR_LEN(str, maxLen, outLen) do { \ + const char *strEnd_ = (const char *)(str); \ + size_t availableSize_ = (size_t)(maxLen); \ + while (availableSize_ > 0 && *strEnd_ != '\0') { \ + --availableSize_; \ + ++strEnd_; \ + } \ + *(outLen) = (size_t)(strEnd_ - (str)); \ +} SECUREC_WHILE_ZERO +#define SECUREC_CALC_STR_LEN_OPT SECUREC_CALC_STR_LEN +#endif + +#define SECUREC_CALC_WSTR_LEN(str, maxLen, outLen) do { \ + const wchar_t *strEnd_ = (const wchar_t *)(str); \ + size_t len_ = 0; \ + while (len_ < (maxLen) && *strEnd_ != L'\0') { \ + ++len_; \ + ++strEnd_; \ + } \ + *(outLen) = len_; \ +} SECUREC_WHILE_ZERO + +/* + * Performance optimization, product may disable inline function. + * Using function pointer for MEMSET to prevent compiler optimization when cleaning up memory. + */ +#ifdef SECUREC_USE_ASM +#define SECUREC_MEMSET_FUNC_OPT memset_opt +#define SECUREC_MEMCPY_FUNC_OPT memcpy_opt +#else +#define SECUREC_MEMSET_FUNC_OPT memset +#define SECUREC_MEMCPY_FUNC_OPT memcpy +#endif + +#define SECUREC_MEMCPY_WARP_OPT(dest, src, count) (void)SECUREC_MEMCPY_FUNC_OPT((dest), (src), (count)) + +#ifndef SECUREC_MEMSET_INDIRECT_USE +/* Can be turned off for scenarios that do not allow pointer calls */ +#define SECUREC_MEMSET_INDIRECT_USE 1 +#endif + +#if SECUREC_MEMSET_INDIRECT_USE +#define SECUREC_MEMSET_WARP_OPT(dest, value, count) do { \ + void *(* const volatile fn_)(void *s_, int c_, size_t n_) = SECUREC_MEMSET_FUNC_OPT; \ + (void)(*fn_)((dest), (value), (count)); \ +} SECUREC_WHILE_ZERO +#else +#define SECUREC_MEMSET_WARP_OPT(dest, value, count) (void)SECUREC_MEMSET_FUNC_OPT((dest), (value), (count)) +#endif + +#ifdef SECUREC_FORMAT_OUTPUT_INPUT +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) || defined(__ARMCC_VERSION) +typedef __int64 SecInt64; +typedef unsigned __int64 SecUnsignedInt64; +#if defined(__ARMCC_VERSION) +typedef unsigned int SecUnsignedInt32; +#else +typedef unsigned __int32 SecUnsignedInt32; +#endif +#else +typedef unsigned int SecUnsignedInt32; +typedef long long SecInt64; +typedef unsigned long long SecUnsignedInt64; +#endif + +#ifdef SECUREC_FOR_WCHAR +#if defined(SECUREC_VXWORKS_PLATFORM) && !defined(__WINT_TYPE__) +typedef wchar_t wint_t; +#endif +#ifndef WEOF +#define WEOF ((wchar_t)(-1)) +#endif +#define SECUREC_CHAR(x) L ## x +typedef wchar_t SecChar; +typedef wchar_t SecUnsignedChar; +typedef wint_t SecInt; +typedef wint_t SecUnsignedInt; +#else /* no SECUREC_FOR_WCHAR */ +#define SECUREC_CHAR(x) (x) +typedef char SecChar; +typedef unsigned char SecUnsignedChar; +typedef int SecInt; +typedef unsigned int SecUnsignedInt; +#endif +#endif + +/* + * Determine whether the address is 8-byte aligned + * Some systems do not have uintptr_t type, so use NULL to clear tool alarm 507 + */ +#define SECUREC_ADDR_ALIGNED_8(addr) ((((size_t)(addr)) & 7U) == 0) /* Use 7 to check aligned 8 */ + +/* + * If you define the memory allocation function, you need to define the function prototype. + * You can define this macro as a header file. + */ +#if defined(SECUREC_MALLOC_PROTOTYPE) +SECUREC_MALLOC_PROTOTYPE +#endif + +#ifndef SECUREC_MALLOC +#define SECUREC_MALLOC(x) malloc((size_t)(x)) +#endif + +#ifndef SECUREC_FREE +#define SECUREC_FREE(x) free((void *)(x)) +#endif + +/* Improve performance with struct assignment, buf1 is not defined to avoid tool false positive */ +#define SECUREC_COPY_VALUE_BY_STRUCT(dest, src, n) do { \ + *(SecStrBuf##n *)(void *)(dest) = *(const SecStrBuf##n *)(const void *)(src); \ +} SECUREC_WHILE_ZERO + +typedef struct { + unsigned char buf[2]; /* Performance optimization code structure assignment length 2 bytes */ +} SecStrBuf2; +typedef struct { + unsigned char buf[3]; /* Performance optimization code structure assignment length 3 bytes */ +} SecStrBuf3; +typedef struct { + unsigned char buf[4]; /* Performance optimization code structure assignment length 4 bytes */ +} SecStrBuf4; +typedef struct { + unsigned char buf[5]; /* Performance optimization code structure assignment length 5 bytes */ +} SecStrBuf5; +typedef struct { + unsigned char buf[6]; /* Performance optimization code structure assignment length 6 bytes */ +} SecStrBuf6; +typedef struct { + unsigned char buf[7]; /* Performance optimization code structure assignment length 7 bytes */ +} SecStrBuf7; +typedef struct { + unsigned char buf[8]; /* Performance optimization code structure assignment length 8 bytes */ +} SecStrBuf8; +typedef struct { + unsigned char buf[9]; /* Performance optimization code structure assignment length 9 bytes */ +} SecStrBuf9; +typedef struct { + unsigned char buf[10]; /* Performance optimization code structure assignment length 10 bytes */ +} SecStrBuf10; +typedef struct { + unsigned char buf[11]; /* Performance optimization code structure assignment length 11 bytes */ +} SecStrBuf11; +typedef struct { + unsigned char buf[12]; /* Performance optimization code structure assignment length 12 bytes */ +} SecStrBuf12; +typedef struct { + unsigned char buf[13]; /* Performance optimization code structure assignment length 13 bytes */ +} SecStrBuf13; +typedef struct { + unsigned char buf[14]; /* Performance optimization code structure assignment length 14 bytes */ +} SecStrBuf14; +typedef struct { + unsigned char buf[15]; /* Performance optimization code structure assignment length 15 bytes */ +} SecStrBuf15; +typedef struct { + unsigned char buf[16]; /* Performance optimization code structure assignment length 16 bytes */ +} SecStrBuf16; +typedef struct { + unsigned char buf[17]; /* Performance optimization code structure assignment length 17 bytes */ +} SecStrBuf17; +typedef struct { + unsigned char buf[18]; /* Performance optimization code structure assignment length 18 bytes */ +} SecStrBuf18; +typedef struct { + unsigned char buf[19]; /* Performance optimization code structure assignment length 19 bytes */ +} SecStrBuf19; +typedef struct { + unsigned char buf[20]; /* Performance optimization code structure assignment length 20 bytes */ +} SecStrBuf20; +typedef struct { + unsigned char buf[21]; /* Performance optimization code structure assignment length 21 bytes */ +} SecStrBuf21; +typedef struct { + unsigned char buf[22]; /* Performance optimization code structure assignment length 22 bytes */ +} SecStrBuf22; +typedef struct { + unsigned char buf[23]; /* Performance optimization code structure assignment length 23 bytes */ +} SecStrBuf23; +typedef struct { + unsigned char buf[24]; /* Performance optimization code structure assignment length 24 bytes */ +} SecStrBuf24; +typedef struct { + unsigned char buf[25]; /* Performance optimization code structure assignment length 25 bytes */ +} SecStrBuf25; +typedef struct { + unsigned char buf[26]; /* Performance optimization code structure assignment length 26 bytes */ +} SecStrBuf26; +typedef struct { + unsigned char buf[27]; /* Performance optimization code structure assignment length 27 bytes */ +} SecStrBuf27; +typedef struct { + unsigned char buf[28]; /* Performance optimization code structure assignment length 28 bytes */ +} SecStrBuf28; +typedef struct { + unsigned char buf[29]; /* Performance optimization code structure assignment length 29 bytes */ +} SecStrBuf29; +typedef struct { + unsigned char buf[30]; /* Performance optimization code structure assignment length 30 bytes */ +} SecStrBuf30; +typedef struct { + unsigned char buf[31]; /* Performance optimization code structure assignment length 31 bytes */ +} SecStrBuf31; +typedef struct { + unsigned char buf[32]; /* Performance optimization code structure assignment length 32 bytes */ +} SecStrBuf32; +typedef struct { + unsigned char buf[33]; /* Performance optimization code structure assignment length 33 bytes */ +} SecStrBuf33; +typedef struct { + unsigned char buf[34]; /* Performance optimization code structure assignment length 34 bytes */ +} SecStrBuf34; +typedef struct { + unsigned char buf[35]; /* Performance optimization code structure assignment length 35 bytes */ +} SecStrBuf35; +typedef struct { + unsigned char buf[36]; /* Performance optimization code structure assignment length 36 bytes */ +} SecStrBuf36; +typedef struct { + unsigned char buf[37]; /* Performance optimization code structure assignment length 37 bytes */ +} SecStrBuf37; +typedef struct { + unsigned char buf[38]; /* Performance optimization code structure assignment length 38 bytes */ +} SecStrBuf38; +typedef struct { + unsigned char buf[39]; /* Performance optimization code structure assignment length 39 bytes */ +} SecStrBuf39; +typedef struct { + unsigned char buf[40]; /* Performance optimization code structure assignment length 40 bytes */ +} SecStrBuf40; +typedef struct { + unsigned char buf[41]; /* Performance optimization code structure assignment length 41 bytes */ +} SecStrBuf41; +typedef struct { + unsigned char buf[42]; /* Performance optimization code structure assignment length 42 bytes */ +} SecStrBuf42; +typedef struct { + unsigned char buf[43]; /* Performance optimization code structure assignment length 43 bytes */ +} SecStrBuf43; +typedef struct { + unsigned char buf[44]; /* Performance optimization code structure assignment length 44 bytes */ +} SecStrBuf44; +typedef struct { + unsigned char buf[45]; /* Performance optimization code structure assignment length 45 bytes */ +} SecStrBuf45; +typedef struct { + unsigned char buf[46]; /* Performance optimization code structure assignment length 46 bytes */ +} SecStrBuf46; +typedef struct { + unsigned char buf[47]; /* Performance optimization code structure assignment length 47 bytes */ +} SecStrBuf47; +typedef struct { + unsigned char buf[48]; /* Performance optimization code structure assignment length 48 bytes */ +} SecStrBuf48; +typedef struct { + unsigned char buf[49]; /* Performance optimization code structure assignment length 49 bytes */ +} SecStrBuf49; +typedef struct { + unsigned char buf[50]; /* Performance optimization code structure assignment length 50 bytes */ +} SecStrBuf50; +typedef struct { + unsigned char buf[51]; /* Performance optimization code structure assignment length 51 bytes */ +} SecStrBuf51; +typedef struct { + unsigned char buf[52]; /* Performance optimization code structure assignment length 52 bytes */ +} SecStrBuf52; +typedef struct { + unsigned char buf[53]; /* Performance optimization code structure assignment length 53 bytes */ +} SecStrBuf53; +typedef struct { + unsigned char buf[54]; /* Performance optimization code structure assignment length 54 bytes */ +} SecStrBuf54; +typedef struct { + unsigned char buf[55]; /* Performance optimization code structure assignment length 55 bytes */ +} SecStrBuf55; +typedef struct { + unsigned char buf[56]; /* Performance optimization code structure assignment length 56 bytes */ +} SecStrBuf56; +typedef struct { + unsigned char buf[57]; /* Performance optimization code structure assignment length 57 bytes */ +} SecStrBuf57; +typedef struct { + unsigned char buf[58]; /* Performance optimization code structure assignment length 58 bytes */ +} SecStrBuf58; +typedef struct { + unsigned char buf[59]; /* Performance optimization code structure assignment length 59 bytes */ +} SecStrBuf59; +typedef struct { + unsigned char buf[60]; /* Performance optimization code structure assignment length 60 bytes */ +} SecStrBuf60; +typedef struct { + unsigned char buf[61]; /* Performance optimization code structure assignment length 61 bytes */ +} SecStrBuf61; +typedef struct { + unsigned char buf[62]; /* Performance optimization code structure assignment length 62 bytes */ +} SecStrBuf62; +typedef struct { + unsigned char buf[63]; /* Performance optimization code structure assignment length 63 bytes */ +} SecStrBuf63; +typedef struct { + unsigned char buf[64]; /* Performance optimization code structure assignment length 64 bytes */ +} SecStrBuf64; + +/* + * User can change the error handler by modify the following definition, + * such as logging the detail error in file. + */ +#if defined(_DEBUG) || defined(DEBUG) +#if defined(SECUREC_ERROR_HANDLER_BY_ASSERT) +#define SECUREC_ERROR_INVALID_PARAMTER(msg) assert(msg "invalid argument" == NULL) +#define SECUREC_ERROR_INVALID_RANGE(msg) assert(msg "invalid dest buffer size" == NULL) +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) assert(msg "buffer overlap" == NULL) +#elif defined(SECUREC_ERROR_HANDLER_BY_PRINTF) +#if SECUREC_IN_KERNEL +#define SECUREC_ERROR_INVALID_PARAMTER(msg) printk("%s invalid argument\n", msg) +#define SECUREC_ERROR_INVALID_RANGE(msg) printk("%s invalid dest buffer size\n", msg) +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) printk("%s buffer overlap\n", msg) +#else +#define SECUREC_ERROR_INVALID_PARAMTER(msg) printf("%s invalid argument\n", msg) +#define SECUREC_ERROR_INVALID_RANGE(msg) printf("%s invalid dest buffer size\n", msg) +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) printf("%s buffer overlap\n", msg) +#endif +#elif defined(SECUREC_ERROR_HANDLER_BY_FILE_LOG) +#define SECUREC_ERROR_INVALID_PARAMTER(msg) LogSecureCRuntimeError(msg " EINVAL\n") +#define SECUREC_ERROR_INVALID_RANGE(msg) LogSecureCRuntimeError(msg " ERANGE\n") +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) LogSecureCRuntimeError(msg " EOVERLAP\n") +#endif +#endif + +/* Default handler is none */ +#ifndef SECUREC_ERROR_INVALID_PARAMTER +#define SECUREC_ERROR_INVALID_PARAMTER(msg) +#endif +#ifndef SECUREC_ERROR_INVALID_RANGE +#define SECUREC_ERROR_INVALID_RANGE(msg) +#endif +#ifndef SECUREC_ERROR_BUFFER_OVERLAP +#define SECUREC_ERROR_BUFFER_OVERLAP(msg) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Assembly language memory copy and memory set for X86 or MIPS ... */ +#ifdef SECUREC_USE_ASM + void *memcpy_opt(void *dest, const void *src, size_t n); + void *memset_opt(void *s, int c, size_t n); +#endif + +#if defined(SECUREC_ERROR_HANDLER_BY_FILE_LOG) + void LogSecureCRuntimeError(const char *errDetail); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif + diff --git a/third_party/bounds_checking_function/src/secureinput_a.c b/third_party/bounds_checking_function/src/secureinput_a.c new file mode 100644 index 0000000000000000000000000000000000000000..10b7f3571b8fc630e129ad7080c694439e3993d9 --- /dev/null +++ b/third_party/bounds_checking_function/src/secureinput_a.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: By defining data type for ANSI string and including "input.inl", + * this file generates real underlying function used by scanf family API. + * Author: lishunda + * Create: 2014-02-25 + */ + +#define SECUREC_FORMAT_OUTPUT_INPUT 1 +#ifdef SECUREC_FOR_WCHAR +#undef SECUREC_FOR_WCHAR +#endif + +#include "secinput.h" + +#include "input.inl" + +SECUREC_INLINE int SecIsDigit(SecInt ch) +{ + /* SecInt to unsigned char clear 571, use bit mask to clear negative return of ch */ + return isdigit((int)((unsigned int)(unsigned char)(ch) & 0xffU)); +} +SECUREC_INLINE int SecIsXdigit(SecInt ch) +{ + return isxdigit((int)((unsigned int)(unsigned char)(ch) & 0xffU)); +} +SECUREC_INLINE int SecIsSpace(SecInt ch) +{ + return isspace((int)((unsigned int)(unsigned char)(ch) & 0xffU)); +} + diff --git a/third_party/bounds_checking_function/src/secureinput_w.c b/third_party/bounds_checking_function/src/secureinput_w.c new file mode 100644 index 0000000000000000000000000000000000000000..5adc3c0a3cdce655a3a09d212a5e1555a4f7af34 --- /dev/null +++ b/third_party/bounds_checking_function/src/secureinput_w.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: By defining data type for UNICODE string and including "input.inl", + * this file generates real underlying function used by scanf family API. + * Author: lishunda + * Create: 2014-02-25 + */ + +/* If some platforms don't have wchar.h, dont't include it */ +#if !(defined(SECUREC_VXWORKS_PLATFORM)) +/* If there is no macro below, it will cause vs2010 compiling alarm */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#ifndef __STDC_WANT_SECURE_LIB__ +/* The order of adjustment is to eliminate alarm of Duplicate Block */ +#define __STDC_WANT_SECURE_LIB__ 0 +#endif +#ifndef _CRTIMP_ALTERNATIVE +#define _CRTIMP_ALTERNATIVE /* Comment microsoft *_s function */ +#endif +#endif +#include +#endif + +/* fix redefined */ +#undef SECUREC_ENABLE_WCHAR_FUNC +/* Disable wchar func to clear vs warning */ +#define SECUREC_ENABLE_WCHAR_FUNC 0 +#define SECUREC_FORMAT_OUTPUT_INPUT 1 + +#ifndef SECUREC_FOR_WCHAR +#define SECUREC_FOR_WCHAR +#endif + +#include "secinput.h" + +#include "input.inl" + +SECUREC_INLINE unsigned int SecWcharHighBits(SecInt ch) +{ + /* Convert int to unsigned int clear 571 */ + return ((unsigned int)(int)ch & (~0xffU)); +} + +SECUREC_INLINE unsigned char SecWcharLowByte(SecInt ch) +{ + /* Convert int to unsigned int clear 571 */ + return (unsigned char)((unsigned int)(int)ch & 0xffU); +} + +SECUREC_INLINE int SecIsDigit(SecInt ch) +{ + if (SecWcharHighBits(ch) != 0) { + return 0; /* Same as isdigit */ + } + return isdigit((int)SecWcharLowByte(ch)); +} + +SECUREC_INLINE int SecIsXdigit(SecInt ch) +{ + if (SecWcharHighBits(ch) != 0) { + return 0; /* Same as isxdigit */ + } + return isxdigit((int)SecWcharLowByte(ch)); +} + +SECUREC_INLINE int SecIsSpace(SecInt ch) +{ + return iswspace((wint_t)(int)(ch)); +} + diff --git a/third_party/bounds_checking_function/src/secureprintoutput.h b/third_party/bounds_checking_function/src/secureprintoutput.h new file mode 100644 index 0000000000000000000000000000000000000000..843217ae0f7b5304c7fd3efde78e5f909d187051 --- /dev/null +++ b/third_party/bounds_checking_function/src/secureprintoutput.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: Define macro, enum, data struct, and declare internal used function + * prototype, which is used by output.inl, secureprintoutput_w.c and + * secureprintoutput_a.c. + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SECUREPRINTOUTPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C +#define SECUREPRINTOUTPUT_H_E950DA2C_902F_4B15_BECD_948E99090D9C +#include "securecutil.h" + +/* + * Flag definitions. + * Using macros instead of enumerations is because some of the enumerated types under the compiler are 16bit. + */ +#define SECUREC_FLAG_SIGN 0x00001U +#define SECUREC_FLAG_SIGN_SPACE 0x00002U +#define SECUREC_FLAG_LEFT 0x00004U +#define SECUREC_FLAG_LEADZERO 0x00008U +#define SECUREC_FLAG_LONG 0x00010U +#define SECUREC_FLAG_SHORT 0x00020U +#define SECUREC_FLAG_SIGNED 0x00040U +#define SECUREC_FLAG_ALTERNATE 0x00080U +#define SECUREC_FLAG_NEGATIVE 0x00100U +#define SECUREC_FLAG_FORCE_OCTAL 0x00200U +#define SECUREC_FLAG_LONG_DOUBLE 0x00400U +#define SECUREC_FLAG_WIDECHAR 0x00800U +#define SECUREC_FLAG_LONGLONG 0x01000U +#define SECUREC_FLAG_CHAR 0x02000U +#define SECUREC_FLAG_POINTER 0x04000U +#define SECUREC_FLAG_I64 0x08000U +#define SECUREC_FLAG_PTRDIFF 0x10000U +#define SECUREC_FLAG_SIZE 0x20000U +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +#define SECUREC_FLAG_INTMAX 0x40000U +#endif + +/* State definitions. Identify the status of the current format */ +typedef enum { + STAT_NORMAL, + STAT_PERCENT, + STAT_FLAG, + STAT_WIDTH, + STAT_DOT, + STAT_PRECIS, + STAT_SIZE, + STAT_TYPE, + STAT_INVALID +} SecFmtState; + +/* Format output buffer pointer and available size */ +typedef struct { + int count; + char *cur; +} SecPrintfStream; + +#ifndef SECUREC_BUFFER_SIZE +#if SECUREC_IN_KERNEL +#define SECUREC_BUFFER_SIZE 32 +#elif defined(SECUREC_STACK_SIZE_LESS_THAN_1K) +/* + * SECUREC BUFFER SIZE Can not be less than 23 + * The length of the octal representation of 64-bit integers with zero lead + */ +#define SECUREC_BUFFER_SIZE 256 +#else +#define SECUREC_BUFFER_SIZE 512 +#endif +#endif +#if SECUREC_BUFFER_SIZE < 23 +#error SECUREC_BUFFER_SIZE Can not be less than 23 +#endif +/* Buffer size for wchar, use 4 to make the compiler aligns as 8 bytes as possible */ +#define SECUREC_WCHAR_BUFFER_SIZE 4 + +#define SECUREC_MAX_PRECISION SECUREC_BUFFER_SIZE +/* Max. # bytes in multibyte char ,see MB_LEN_MAX */ +#define SECUREC_MB_LEN 16 +/* The return value of the internal function, which is returned when truncated */ +#define SECUREC_PRINTF_TRUNCATE (-2) + +#define SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, maxLimit) \ + ((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit)) + +#define SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, maxLimit) do { \ + if ((strDest) != NULL && (destMax) > 0 && (destMax) <= (maxLimit)) { \ + *(strDest) = '\0'; \ + } \ +} SECUREC_WHILE_ZERO + +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT +#define SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, maxLimit) \ + (((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit)) || \ + ((count) > (SECUREC_STRING_MAX_LEN - 1) && (count) != (size_t)(-1))) + +#else +#define SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, maxLimit) \ + (((format) == NULL || (strDest) == NULL || (destMax) == 0 || (destMax) > (maxLimit)) || \ + ((count) > (SECUREC_STRING_MAX_LEN - 1))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList); +#ifdef SECUREC_FOR_WCHAR + int SecVswprintfImpl(wchar_t *string, size_t sizeInWchar, const wchar_t *format, va_list argList); +#endif +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/third_party/bounds_checking_function/src/secureprintoutput_a.c b/third_party/bounds_checking_function/src/secureprintoutput_a.c new file mode 100644 index 0000000000000000000000000000000000000000..64762c06775b760e278aee850081cf291f3b3255 --- /dev/null +++ b/third_party/bounds_checking_function/src/secureprintoutput_a.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: By defining corresponding macro for ANSI string and including "output.inl", + * this file generates real underlying function used by printf family API. + * Author: lishunda + * Create: 2014-02-25 + */ + +#define SECUREC_FORMAT_OUTPUT_INPUT 1 + +#ifdef SECUREC_FOR_WCHAR +#undef SECUREC_FOR_WCHAR +#endif + +#include "secureprintoutput.h" +#if SECUREC_WARP_OUTPUT +#define SECUREC_FORMAT_FLAG_TABLE_SIZE 128 +SECUREC_INLINE const char *SecSkipKnownFlags(const char *format) +{ + static const unsigned char flagTable[SECUREC_FORMAT_FLAG_TABLE_SIZE] = { + /* + * Known flag is "0123456789 +-#hlLwZzjqt*I$" + */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const char *fmt = format; + while (*fmt != '\0') { + char fmtChar = *fmt; + if ((unsigned char)fmtChar > 0x7f) { /* 0x7f is upper limit of format char value */ + break; + } + if (flagTable[(unsigned char)fmtChar] == 0) { + break; + } + ++fmt; + } + return fmt; +} + +SECUREC_INLINE int SecFormatContainN(const char *format) +{ + const char *fmt = format; + while (*fmt != '\0') { + ++fmt; + /* Skip normal char */ + if (*(fmt - 1) != '%') { + continue; + } + /* Meet %% */ + if (*fmt == '%') { + ++fmt; /* Point to the character after the %. Correct handling %%xx */ + continue; + } + /* Now parse %..., fmt point to the character after the % */ + fmt = SecSkipKnownFlags(fmt); + if (*fmt == 'n') { + return 1; + } + } + return 0; +} +/* + * Multi character formatted output implementation, the count include \0 character, must be greater than zero + */ +int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList) +{ + int retVal; + if (SecFormatContainN(format) != 0) { + string[0] = '\0'; + return -1; + } + retVal = vsnprintf(string, count, format, argList); + if (retVal >= (int)count) { /* The size_t to int is ok, count max is SECUREC_STRING_MAX_LEN */ + /* The buffer was too small; we return truncation */ + string[count - 1] = '\0'; + return SECUREC_PRINTF_TRUNCATE; + } + if (retVal < 0) { + string[0] = '\0'; /* Empty the dest strDest */ + return -1; + } + return retVal; +} +#else +#if SECUREC_IN_KERNEL +#include +#endif + +#ifndef EOF +#define EOF (-1) +#endif + +#include "output.inl" + +/* + * Multi character formatted output implementation + */ +int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList) +{ + SecPrintfStream str; + int retVal; + + str.count = (int)count; /* The count include \0 character, must be greater than zero */ + str.cur = string; + + retVal = SecOutputS(&str, format, argList); + if (retVal >= 0) { + if (SecPutZeroChar(&str) == 0) { + return retVal; + } + } + if (str.count < 0) { + /* The buffer was too small, then truncate */ + string[count - 1] = '\0'; + return SECUREC_PRINTF_TRUNCATE; + } + string[0] = '\0'; /* Empty the dest string */ + return -1; +} + +/* + * Write a wide character + */ +SECUREC_INLINE void SecWriteMultiChar(char ch, int num, SecPrintfStream *f, int *pnumwritten) +{ + int count; + for (count = num; count > 0; --count) { + --f->count; /* f -> count may be negative,indicating insufficient space */ + if (f->count < 0) { + *pnumwritten = -1; + return; + } + *(f->cur) = ch; + ++f->cur; + *pnumwritten = *pnumwritten + 1; + } +} + +/* + * Write string function, where this function is called, make sure that len is greater than 0 + */ +SECUREC_INLINE void SecWriteString(const char *string, int len, SecPrintfStream *f, int *pnumwritten) +{ + const char *str = string; + int count; + for (count = len; count > 0; --count) { + --f->count; /* f -> count may be negative,indicating insufficient space */ + if (f->count < 0) { + *pnumwritten = -1; + return; + } + *(f->cur) = *str; + ++f->cur; + ++str; + } + *pnumwritten = *pnumwritten + (int)(size_t)(str - string); +} +#endif + diff --git a/third_party/bounds_checking_function/src/secureprintoutput_w.c b/third_party/bounds_checking_function/src/secureprintoutput_w.c new file mode 100644 index 0000000000000000000000000000000000000000..753d465ea5773180e6c977d9502b592f70b12954 --- /dev/null +++ b/third_party/bounds_checking_function/src/secureprintoutput_w.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: By defining corresponding macro for UNICODE string and including "output.inl", + * this file generates real underlying function used by printf family API. + * Author: lishunda + * Create: 2014-02-25 + */ + +/* If some platforms don't have wchar.h, dont't include it */ +#if !(defined(SECUREC_VXWORKS_PLATFORM)) +/* If there is no macro above, it will cause compiling alarm */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#ifndef _CRTIMP_ALTERNATIVE +#define _CRTIMP_ALTERNATIVE /* Comment microsoft *_s function */ +#endif +#ifndef __STDC_WANT_SECURE_LIB__ +#define __STDC_WANT_SECURE_LIB__ 0 +#endif +#endif +#include +#endif + +/* fix redefined */ +#undef SECUREC_ENABLE_WCHAR_FUNC +/* Disable wchar func to clear vs warning */ +#define SECUREC_ENABLE_WCHAR_FUNC 0 +#define SECUREC_FORMAT_OUTPUT_INPUT 1 + +#ifndef SECUREC_FOR_WCHAR +#define SECUREC_FOR_WCHAR +#endif + +#if defined(SECUREC_WARP_OUTPUT) && SECUREC_WARP_OUTPUT +#undef SECUREC_WARP_OUTPUT +#define SECUREC_WARP_OUTPUT 0 +#endif + +#include "secureprintoutput.h" + +SECUREC_INLINE void SecWriteCharW(wchar_t ch, SecPrintfStream *f, int *pnumwritten); +SECUREC_INLINE int SecPutWcharStrEndingZero(SecPrintfStream *str, int zeroCount); + +#include "output.inl" + +/* + * Wide character formatted output implementation + */ +int SecVswprintfImpl(wchar_t *string, size_t sizeInWchar, const wchar_t *format, va_list argList) +{ + SecPrintfStream str; + int retVal; /* If initialization causes e838 */ + + str.cur = (char *)string; + /* This count include \0 character, Must be greater than zero */ + str.count = (int)(sizeInWchar * sizeof(wchar_t)); + + retVal = SecOutputSW(&str, format, argList); + if (retVal >= 0) { + if (SecPutWcharStrEndingZero(&str, (int)sizeof(wchar_t)) == 0) { + return retVal; + } + } + if (str.count < 0) { + /* The buffer was too small, then truncate */ + string[sizeInWchar - 1] = L'\0'; + return SECUREC_PRINTF_TRUNCATE; + } + string[0] = L'\0'; /* Empty the dest string */ + return -1; +} + +/* + * Output a wide character zero end into the SecPrintfStream structure + */ +SECUREC_INLINE int SecPutWcharStrEndingZero(SecPrintfStream *str, int zeroCount) +{ + int count; + for (count = zeroCount; count > 0; --count) { + if (SecPutZeroChar(str) != 0) { + return -1; + } + } + return 0; +} + +/* + * Output a wide character into the SecPrintfStream structure + */ +SECUREC_INLINE int SecPutCharW(wchar_t ch, SecPrintfStream *f) +{ + f->count -= (int)sizeof(wchar_t); /* f -> count may be negative,indicating insufficient space */ + if (f->count >= 0) { + *(wchar_t *)(void *)(f->cur) = ch; + f->cur += sizeof(wchar_t); + return 0; + } + return -1; +} + +/* + * Output a wide character into the SecPrintfStream structure, returns the number of characters written + */ +SECUREC_INLINE void SecWriteCharW(wchar_t ch, SecPrintfStream *f, int *pnumwritten) +{ + if (SecPutCharW(ch, f) == 0) { + *pnumwritten = *pnumwritten + 1; + } else { + *pnumwritten = -1; + } +} + +/* + * Output multiple wide character into the SecPrintfStream structure, returns the number of characters written + */ +SECUREC_INLINE void SecWriteMultiCharW(wchar_t ch, int num, SecPrintfStream *f, int *pnumwritten) +{ + int count; + for (count = num; count > 0; --count) { + SecWriteCharW(ch, f, pnumwritten); + if (*pnumwritten == -1) { + break; + } + } +} + +/* + * Output a wide string into the SecPrintfStream structure, returns the number of characters written + */ +SECUREC_INLINE void SecWriteStringW(const wchar_t *string, int len, SecPrintfStream *f, int *pnumwritten) +{ + const wchar_t *str = string; + int count; + for (count = len; count > 0; --count) { + SecWriteCharW(*str, f, pnumwritten); + ++str; + if (*pnumwritten == -1) { + break; + } + } +} + diff --git a/third_party/bounds_checking_function/src/snprintf_s.c b/third_party/bounds_checking_function/src/snprintf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..491c0a8d27ab0eeb201a29603801bcd4bf89c851 --- /dev/null +++ b/third_party/bounds_checking_function/src/snprintf_s.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: snprintf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +#if SECUREC_ENABLE_SNPRINTF +/* + * + * The snprintf_s function is equivalent to the snprintf function + * except for the parameter destMax/count and the explicit runtime-constraints violation + * The snprintf_s function formats and stores count or fewer characters in + * strDest and appends a terminating null. Each argument (if any) is converted + * and output according to the corresponding format specification in format. + * The formatting is consistent with the printf family of functions; If copying + * occurs between strings that overlap, the behavior is undefined. + * + * + * strDest Storage location for the output. + * destMax The size of the storage location for output. Size + * in bytes for snprintf_s or size in words for snwprintf_s. + * count Maximum number of character to store. + * format Format-control string. + * ... Optional arguments. + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null + * return -1 if an error occurs. + * return -1 if count < destMax and the output string has been truncated + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + * + */ +int snprintf_s(char *strDest, size_t destMax, size_t count, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vsnprintf_s(strDest, destMax, count, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(snprintf_s); +#endif +#endif + +#if SECUREC_SNPRINTF_TRUNCATED +/* + * + * The snprintf_truncated_s function is equivalent to the snprintf function + * except for the parameter destMax/count and the explicit runtime-constraints violation + * The snprintf_truncated_s function formats and stores count or fewer characters in + * strDest and appends a terminating null. Each argument (if any) is converted + * and output according to the corresponding format specification in format. + * The formatting is consistent with the printf family of functions; If copying + * occurs between strings that overlap, the behavior is undefined. + * + * + * strDest Storage location for the output. + * destMax The size of the storage location for output. Size + * in bytes for snprintf_truncated_s or size in words for snwprintf_s. + * format Format-control string. + * ... Optional arguments. + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null + * return -1 if an error occurs. + * return destMax-1 if output string has been truncated + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + * + */ +int snprintf_truncated_s(char *strDest, size_t destMax, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vsnprintf_truncated_s(strDest, destMax, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(snprintf_truncated_s); +#endif + +#endif + diff --git a/third_party/bounds_checking_function/src/sprintf_s.c b/third_party/bounds_checking_function/src/sprintf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..95b448586c5c265d7ce9c55d4f1b6bbba249f521 --- /dev/null +++ b/third_party/bounds_checking_function/src/sprintf_s.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: sprintf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +/* + * + * The sprintf_s function is equivalent to the sprintf function + * except for the parameter destMax and the explicit runtime-constraints violation + * The sprintf_s function formats and stores a series of characters and values + * in strDest. Each argument (if any) is converted and output according to + * the corresponding format specification in format. The format consists of + * ordinary characters and has the same form and function as the format argument + * for printf. A null character is appended after the last character written. + * If copying occurs between strings that overlap, the behavior is undefined. + * + * + * strDest Storage location for output. + * destMax Maximum number of characters to store. + * format Format-control string. + * ... Optional arguments + * + * + * strDest is updated + * + * + * return the number of bytes stored in strDest, not counting the terminating null character. + * return -1 if an error occurred. + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int sprintf_s(char *strDest, size_t destMax, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vsprintf_s(strDest, destMax, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(sprintf_s); +#endif + diff --git a/third_party/bounds_checking_function/src/sscanf_s.c b/third_party/bounds_checking_function/src/sscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..ba5680f03329f9dfd4471e76e99baa38b1655088 --- /dev/null +++ b/third_party/bounds_checking_function/src/sscanf_s.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: sscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +/* + * + * The sscanf_s function is equivalent to fscanf_s, + * except that input is obtained from a string (specified by the argument buffer) rather than from a stream + * The sscanf function reads data from buffer into the location given by each + * argument. Every argument must be a pointer to a variable with a type that + * corresponds to a type specifier in format. The format argument controls the + * interpretation of the input fields and has the same form and function as + * the format argument for the scanf function. + * If copying takes place between strings that overlap, the behavior is undefined. + * + * + * buffer Stored data. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... The converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int sscanf_s(const char *buffer, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vsscanf_s(buffer, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(sscanf_s); +#endif + diff --git a/third_party/bounds_checking_function/src/strcat_s.c b/third_party/bounds_checking_function/src/strcat_s.c new file mode 100644 index 0000000000000000000000000000000000000000..05c1c3230f6c8375ddfa4e64ad094bae0e1342c4 --- /dev/null +++ b/third_party/bounds_checking_function/src/strcat_s.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: strcat_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +/* + * Befor this function, the basic parameter checking has been done + */ +SECUREC_INLINE errno_t SecDoCat(char *strDest, size_t destMax, const char *strSrc) +{ + size_t destLen; + size_t srcLen; + size_t maxSrcLen; + SECUREC_CALC_STR_LEN(strDest, destMax, &destLen); + /* Only optimize strSrc, do not apply this function to strDest */ + maxSrcLen = destMax - destLen; + SECUREC_CALC_STR_LEN_OPT(strSrc, maxSrcLen, &srcLen); + + if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) { + strDest[0] = '\0'; + if (strDest + destLen <= strSrc && destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("strcat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_BUFFER_OVERLAP("strcat_s"); + return EOVERLAP_AND_RESET; + } + if (srcLen + destLen >= destMax || strDest == strSrc) { + strDest[0] = '\0'; + if (destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("strcat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_INVALID_RANGE("strcat_s"); + return ERANGE_AND_RESET; + } + SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen + 1); /* Single character length include \0 */ + return EOK; +} + +/* + * + * The strcat_s function appends a copy of the string pointed to by strSrc (including the terminating null character) + * to the end of the string pointed to by strDest. + * The initial character of strSrc overwrites the terminating null character of strDest. + * strcat_s will return EOVERLAP_AND_RESET if the source and destination strings overlap. + * + * Note that the second parameter is the total size of the buffer, not the + * remaining size. + * + * + * strDest Null-terminated destination string buffer. + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid) or + * (strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN) + * ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t strcat_s(char *strDest, size_t destMax, const char *strSrc) +{ + if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("strcat_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("strcat_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + return SecDoCat(strDest, destMax, strSrc); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strcat_s); +#endif + diff --git a/third_party/bounds_checking_function/src/strcpy_s.c b/third_party/bounds_checking_function/src/strcpy_s.c new file mode 100644 index 0000000000000000000000000000000000000000..e7921eae1b4ff857a81806b5938de414fcdcc672 --- /dev/null +++ b/third_party/bounds_checking_function/src/strcpy_s.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: strcpy_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +#ifndef SECUREC_STRCPY_WITH_PERFORMANCE +#define SECUREC_STRCPY_WITH_PERFORMANCE 1 +#endif + +#define SECUREC_STRCPY_PARAM_OK(strDest, destMax, strSrc) ((destMax) > 0 && \ + (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && (strDest) != (strSrc)) + +#if (!SECUREC_IN_KERNEL) && SECUREC_STRCPY_WITH_PERFORMANCE +#ifndef SECUREC_STRCOPY_THRESHOLD_SIZE +#define SECUREC_STRCOPY_THRESHOLD_SIZE 32UL +#endif +/* The purpose of converting to void is to clean up the alarm */ +#define SECUREC_SMALL_STR_COPY(strDest, strSrc, lenWithTerm) do { \ + if (SECUREC_ADDR_ALIGNED_8(strDest) && SECUREC_ADDR_ALIGNED_8(strSrc)) { \ + /* Use struct assignment */ \ + switch (lenWithTerm) { \ + case 1: \ + *(strDest) = *(strSrc); \ + break; \ + case 2: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 2); \ + break; \ + case 3: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 3); \ + break; \ + case 4: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 4); \ + break; \ + case 5: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 5); \ + break; \ + case 6: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 6); \ + break; \ + case 7: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 7); \ + break; \ + case 8: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 8); \ + break; \ + case 9: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 9); \ + break; \ + case 10: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 10); \ + break; \ + case 11: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 11); \ + break; \ + case 12: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 12); \ + break; \ + case 13: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 13); \ + break; \ + case 14: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 14); \ + break; \ + case 15: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 15); \ + break; \ + case 16: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 16); \ + break; \ + case 17: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 17); \ + break; \ + case 18: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 18); \ + break; \ + case 19: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 19); \ + break; \ + case 20: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 20); \ + break; \ + case 21: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 21); \ + break; \ + case 22: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 22); \ + break; \ + case 23: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 23); \ + break; \ + case 24: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 24); \ + break; \ + case 25: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 25); \ + break; \ + case 26: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 26); \ + break; \ + case 27: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 27); \ + break; \ + case 28: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 28); \ + break; \ + case 29: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 29); \ + break; \ + case 30: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 30); \ + break; \ + case 31: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 31); \ + break; \ + case 32: \ + SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 32); \ + break; \ + default: \ + /* Do nothing */ \ + break; \ + } /* END switch */ \ + } else { \ + char *tmpStrDest_ = (char *)(strDest); \ + const char *tmpStrSrc_ = (const char *)(strSrc); \ + switch (lenWithTerm) { \ + case 32: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 31: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 30: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 29: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 28: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 27: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 26: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 25: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 24: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 23: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 22: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 21: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 20: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 19: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 18: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 17: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 16: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 15: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 14: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 13: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 12: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 11: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 10: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 9: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 8: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 7: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 6: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 5: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 4: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 3: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 2: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + case 1: \ + *(tmpStrDest_++) = *(tmpStrSrc_++); \ + /* fall-through */ /* FALLTHRU */ \ + default: \ + /* Do nothing */ \ + break; \ + } \ + } \ +} SECUREC_WHILE_ZERO +#endif + +#if SECUREC_IN_KERNEL || (!SECUREC_STRCPY_WITH_PERFORMANCE) +#define SECUREC_STRCPY_OPT(dest, src, lenWithTerm) SECUREC_MEMCPY_WARP_OPT((dest), (src), (lenWithTerm)) +#else +/* + * Performance optimization. lenWithTerm include '\0' + */ +#define SECUREC_STRCPY_OPT(dest, src, lenWithTerm) do { \ + if ((lenWithTerm) > SECUREC_STRCOPY_THRESHOLD_SIZE) { \ + SECUREC_MEMCPY_WARP_OPT((dest), (src), (lenWithTerm)); \ + } else { \ + SECUREC_SMALL_STR_COPY((dest), (src), (lenWithTerm)); \ + } \ +} SECUREC_WHILE_ZERO +#endif + +/* + * Check Src Range + */ +SECUREC_INLINE errno_t CheckSrcRange(char *strDest, size_t destMax, const char *strSrc) +{ + size_t tmpDestMax = destMax; + const char *tmpSrc = strSrc; + /* Use destMax as boundary checker and destMax must be greater than zero */ + while (*tmpSrc != '\0' && tmpDestMax > 0) { + ++tmpSrc; + --tmpDestMax; + } + if (tmpDestMax == 0) { + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("strcpy_s"); + return ERANGE_AND_RESET; + } + return EOK; +} + +/* + * Handling errors + */ +errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc) +{ + if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("strcpy_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("strcpy_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + return CheckSrcRange(strDest, destMax, strSrc); +} + +/* + * + * The strcpy_s function copies the string pointed to strSrc + * (including the terminating null character) into the array pointed to by strDest + * The destination string must be large enough to hold the source string, + * including the terminating null character. strcpy_s will return EOVERLAP_AND_RESET + * if the source and destination strings overlap. + * + * + * strDest Location of destination string buffer + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated. + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * EINVAL_AND_RESET strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc) +{ + if (SECUREC_STRCPY_PARAM_OK(strDest, destMax, strSrc)) { + size_t srcStrLen; + SECUREC_CALC_STR_LEN(strSrc, destMax, &srcStrLen); + ++srcStrLen; /* The length include '\0' */ + + if (srcStrLen <= destMax) { + /* Use mem overlap check include '\0' */ + if (SECUREC_MEMORY_NO_OVERLAP(strDest, strSrc, srcStrLen)) { + /* Performance optimization srcStrLen include '\0' */ + SECUREC_STRCPY_OPT(strDest, strSrc, srcStrLen); + return EOK; + } else { + strDest[0] = '\0'; + SECUREC_ERROR_BUFFER_OVERLAP("strcpy_s"); + return EOVERLAP_AND_RESET; + } + } + } + return strcpy_error(strDest, destMax, strSrc); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strcpy_s); +#endif + diff --git a/third_party/bounds_checking_function/src/strncat_s.c b/third_party/bounds_checking_function/src/strncat_s.c new file mode 100644 index 0000000000000000000000000000000000000000..3baf9bf242e3fdc279adf34540b82d6b519763e1 --- /dev/null +++ b/third_party/bounds_checking_function/src/strncat_s.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: strncat_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +/* + * Befor this function, the basic parameter checking has been done + */ +SECUREC_INLINE errno_t SecDoCatLimit(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + size_t destLen; + size_t srcLen; + SECUREC_CALC_STR_LEN(strDest, destMax, &destLen); + /* + * The strSrc is no longer optimized. The reason is that when count is small, + * the efficiency of strnlen is higher than that of self realization. + */ + SECUREC_CALC_STR_LEN(strSrc, count, &srcLen); + + if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) { + strDest[0] = '\0'; + if (strDest + destLen <= strSrc && destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("strncat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_BUFFER_OVERLAP("strncat_s"); + return EOVERLAP_AND_RESET; + } + if (srcLen + destLen >= destMax || strDest == strSrc) { + strDest[0] = '\0'; + if (destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("strncat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_INVALID_RANGE("strncat_s"); + return ERANGE_AND_RESET; + } + SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen); /* No terminator */ + *(strDest + destLen + srcLen) = '\0'; + return EOK; +} + +/* + * + * The strncat_s function appends not more than n successive characters + * (not including the terminating null character) + * from the array pointed to by strSrc to the end of the string pointed to by strDest + * The strncat_s function try to append the first D characters of strSrc to + * the end of strDest, where D is the lesser of count and the length of strSrc. + * If appending those D characters will fit within strDest (whose size is given + * as destMax) and still leave room for a null terminator, then those characters + * are appended, starting at the original terminating null of strDest, and a + * new terminating null is appended; otherwise, strDest[0] is set to the null + * character. + * + * + * strDest Null-terminated destination string. + * destMax Size of the destination buffer. + * strSrc Null-terminated source string. + * count Number of character to append, or truncate. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid)or + * (strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN) + * ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("strncat_s"); + return ERANGE; + } + + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("strncat_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > SECUREC_STRING_MAX_LEN) { +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (count == (size_t)(-1)) { + /* Windows internal functions may pass in -1 when calling this function */ + return SecDoCatLimit(strDest, destMax, strSrc, destMax); + } +#endif + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("strncat_s"); + return ERANGE_AND_RESET; + } + return SecDoCatLimit(strDest, destMax, strSrc, count); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strncat_s); +#endif + diff --git a/third_party/bounds_checking_function/src/strncpy_s.c b/third_party/bounds_checking_function/src/strncpy_s.c new file mode 100644 index 0000000000000000000000000000000000000000..5bbf0814563f12d84aa42307b1bb7933f14b1248 --- /dev/null +++ b/third_party/bounds_checking_function/src/strncpy_s.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: strncpy_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) +#define SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count) \ + (((destMax) > 0 && (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && \ + ((count) <= SECUREC_STRING_MAX_LEN || (count) == ((size_t)(-1))) && (count) > 0)) +#else +#define SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count) \ + (((destMax) > 0 && (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && \ + (count) <= SECUREC_STRING_MAX_LEN && (count) > 0)) +#endif + +/* + * Check Src Count Range + */ +SECUREC_INLINE errno_t CheckSrcCountRange(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + size_t tmpDestMax = destMax; + size_t tmpCount = count; + const char *endPos = strSrc; + + /* Use destMax and count as boundary checker and destMax must be greater than zero */ + while (*(endPos) != '\0' && tmpDestMax > 0 && tmpCount > 0) { + ++endPos; + --tmpCount; + --tmpDestMax; + } + if (tmpDestMax == 0) { + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("strncpy_s"); + return ERANGE_AND_RESET; + } + return EOK; +} + +/* + * Handling errors, when dest euqal src return EOK + */ +errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("strncpy_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("strncpy_s"); + if (strDest != NULL) { + strDest[0] = '\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > SECUREC_STRING_MAX_LEN) { + strDest[0] = '\0'; /* Clear dest string */ + SECUREC_ERROR_INVALID_RANGE("strncpy_s"); + return ERANGE_AND_RESET; + } + if (count == 0) { + strDest[0] = '\0'; + return EOK; + } + return CheckSrcCountRange(strDest, destMax, strSrc, count); +} + +/* + * + * The strncpy_s function copies not more than n successive characters (not including the terminating null character) + * from the array pointed to by strSrc to the array pointed to by strDest. + * + * + * strDest Destination string. + * destMax The size of the destination string, in characters. + * strSrc Source string. + * count Number of characters to be copied. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * EINVAL_AND_RESET strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN + * ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count) +{ + if (SECUREC_STRNCPY_PARAM_OK(strDest, destMax, strSrc, count)) { + size_t minCpLen; /* Use it to store the maxi length limit */ + if (count < destMax) { + SECUREC_CALC_STR_LEN(strSrc, count, &minCpLen); /* No ending terminator */ + } else { + size_t tmpCount = destMax; +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (count == ((size_t)(-1))) { + tmpCount = destMax - 1; + } +#endif + SECUREC_CALC_STR_LEN(strSrc, tmpCount, &minCpLen); /* No ending terminator */ + if (minCpLen == destMax) { + strDest[0] = '\0'; + SECUREC_ERROR_INVALID_RANGE("strncpy_s"); + return ERANGE_AND_RESET; + } + } + if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, minCpLen) || strDest == strSrc) { + /* Not overlap */ + SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, minCpLen); /* Copy string without terminator */ + strDest[minCpLen] = '\0'; + return EOK; + } else { + strDest[0] = '\0'; + SECUREC_ERROR_BUFFER_OVERLAP("strncpy_s"); + return EOVERLAP_AND_RESET; + } + } + return strncpy_error(strDest, destMax, strSrc, count); +} + +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strncpy_s); +#endif + diff --git a/third_party/bounds_checking_function/src/strtok_s.c b/third_party/bounds_checking_function/src/strtok_s.c new file mode 100644 index 0000000000000000000000000000000000000000..b04793bcf667fc6687ead42a7d744cbd80e222d4 --- /dev/null +++ b/third_party/bounds_checking_function/src/strtok_s.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: strtok_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +SECUREC_INLINE int SecIsInDelimit(char ch, const char *strDelimit) +{ + const char *ctl = strDelimit; + while (*ctl != '\0' && *ctl != ch) { + ++ctl; + } + return (int)(*ctl != '\0'); +} + +/* + * Find beginning of token (skip over leading delimiters). + * Note that there is no token if this loop sets string to point to the terminal null. + */ +SECUREC_INLINE char *SecFindBegin(char *strToken, const char *strDelimit) +{ + char *token = strToken; + while (*token != '\0') { + if (SecIsInDelimit(*token, strDelimit) != 0) { + ++token; + continue; + } + /* Don't find any delimiter in string header, break the loop */ + break; + } + return token; +} + +/* + * Find rest of token + */ +SECUREC_INLINE char *SecFindRest(char *strToken, const char *strDelimit) +{ + /* Find the rest of the token. If it is not the end of the string, put a null there */ + char *token = strToken; + while (*token != '\0') { + if (SecIsInDelimit(*token, strDelimit) != 0) { + /* Find a delimiter, set string termintor */ + *token = '\0'; + ++token; + break; + } + ++token; + } + return token; +} + +/* + * Find the final position pointer + */ +SECUREC_INLINE char *SecUpdateToken(char *strToken, const char *strDelimit, char **context) +{ + /* Point to updated position. Record string position for next search in the context */ + *context = SecFindRest(strToken, strDelimit); + /* Determine if a token has been found. */ + if (*context == strToken) { + return NULL; + } + return strToken; +} + +/* + * + * The strtok_s function parses a string into a sequence of strToken, + * replace all characters in strToken string that match to strDelimit set with 0. + * On the first call to strtok_s the string to be parsed should be specified in strToken. + * In each subsequent call that should parse the same string, strToken should be NULL + * + * strToken String containing token or tokens. + * strDelimit Set of delimiter characters. + * context Used to store position information between calls + * to strtok_s + * + * context is updated + * + * On the first call returns the address of the first non \0 character, otherwise NULL is returned. + * In subsequent calls, the strtoken is set to NULL, and the context set is the same as the previous call, + * return NULL if the *context string length is equal 0, otherwise return *context. + */ +char *strtok_s(char *strToken, const char *strDelimit, char **context) +{ + char *orgToken = strToken; + /* Validate delimiter and string context */ + if (context == NULL || strDelimit == NULL) { + return NULL; + } + /* Valid input string and string pointer from where to search */ + if (orgToken == NULL && *context == NULL) { + return NULL; + } + /* If string is null, continue searching from previous string position stored in context */ + if (orgToken == NULL) { + orgToken = *context; + } + orgToken = SecFindBegin(orgToken, strDelimit); + return SecUpdateToken(orgToken, strDelimit, context); +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(strtok_s); +#endif + diff --git a/third_party/bounds_checking_function/src/swprintf_s.c b/third_party/bounds_checking_function/src/swprintf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..2d2ad42b19d3ce766277d4ee1f51561c7bbe861f --- /dev/null +++ b/third_party/bounds_checking_function/src/swprintf_s.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: swprintf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +/* + * + * The swprintf_s function is the wide-character equivalent of the sprintf_s function + * + * + * strDest Storage location for the output. + * destMax Maximum number of characters to store. + * format Format-control string. + * ... Optional arguments + * + * + * strDest is updated + * + * + * return the number of wide characters stored in strDest, not counting the terminating null wide character. + * return -1 if an error occurred. + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int swprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vswprintf_s(strDest, destMax, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} + diff --git a/third_party/bounds_checking_function/src/swscanf_s.c b/third_party/bounds_checking_function/src/swscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..987b6893d66ebd7db2f84d06902b16f138cb07ce --- /dev/null +++ b/third_party/bounds_checking_function/src/swscanf_s.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: swscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +/* + * + * The swscanf_s function is the wide-character equivalent of the sscanf_s function + * The swscanf_s function reads data from buffer into the location given by + * each argument. Every argument must be a pointer to a variable with a type + * that corresponds to a type specifier in format. The format argument controls + * the interpretation of the input fields and has the same form and function + * as the format argument for the scanf function. If copying takes place between + * strings that overlap, the behavior is undefined. + * + * + * buffer Stored data. + * format Format control string, see Format Specifications. + * ... Optional arguments. + * + * + * ... the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; The return value does not include fields that were read but not + * assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int swscanf_s(const wchar_t *buffer, const wchar_t *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vswscanf_s(buffer, format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} + diff --git a/third_party/bounds_checking_function/src/vfscanf_s.c b/third_party/bounds_checking_function/src/vfscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..96aee67fa9b0b8ab8de3353bebc48aff6725c462 --- /dev/null +++ b/third_party/bounds_checking_function/src/vfscanf_s.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vfscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "secinput.h" + +/* + * + * The vfscanf_s function is equivalent to fscanf_s, with the variable argument list replaced by argList + * The vfscanf_s function reads data from the current position of stream into + * the locations given by argument (if any). Each argument must be a pointer + * to a variable of a type that corresponds to a type specifier in format. + * format controls the interpretation of the input fields and has the same + * form and function as the format argument for scanf. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vfscanf_s(FILE *stream, const char *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + SecFileStream fStr; + + if (stream == NULL || format == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vfscanf_s"); + return SECUREC_SCANF_EINVAL; + } + if (stream == SECUREC_STREAM_STDIN) { + return vscanf_s(format, argList); + } + + SECUREC_LOCK_FILE(stream); + SECUREC_FILE_STREAM_FROM_FILE(&fStr, stream); + retVal = SecInputS(&fStr, format, argList); + SECUREC_UNLOCK_FILE(stream); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vfscanf_s"); + return SECUREC_SCANF_EINVAL; + } + + return retVal; +} + diff --git a/third_party/bounds_checking_function/src/vfwscanf_s.c b/third_party/bounds_checking_function/src/vfwscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..0fd0c350cd3ecb825191e2066ce83c51b9c1aae2 --- /dev/null +++ b/third_party/bounds_checking_function/src/vfwscanf_s.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vfwscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SECUREC_FOR_WCHAR +#define SECUREC_FOR_WCHAR +#endif + +#include "secinput.h" + +/* + * + * The vfwscanf_s function is the wide-character equivalent of the vfscanf_s function + * The vfwscanf_s function reads data from the current position of stream into + * the locations given by argument (if any). Each argument must be a pointer + * to a variable of a type that corresponds to a type specifier in format. + * format controls the interpretation of the input fields and has the same form + * and function as the format argument for scanf. + * + * + * stream Pointer to FILE structure. + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vfwscanf_s(FILE *stream, const wchar_t *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + SecFileStream fStr; + + if (stream == NULL || format == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vfwscanf_s"); + return SECUREC_SCANF_EINVAL; + } + if (stream == SECUREC_STREAM_STDIN) { + return vwscanf_s(format, argList); + } + + SECUREC_LOCK_FILE(stream); + SECUREC_FILE_STREAM_FROM_FILE(&fStr, stream); + retVal = SecInputSW(&fStr, format, argList); + SECUREC_UNLOCK_FILE(stream); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vfwscanf_s"); + return SECUREC_SCANF_EINVAL; + } + return retVal; +} + diff --git a/third_party/bounds_checking_function/src/vscanf_s.c b/third_party/bounds_checking_function/src/vscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..02e84f43f5e97c63967c38b0abc195a7c079809a --- /dev/null +++ b/third_party/bounds_checking_function/src/vscanf_s.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "secinput.h" + +/* + * + * The vscanf_s function is equivalent to scanf_s, with the variable argument list replaced by argList, + * The vscanf_s function reads data from the standard input stream stdin and + * writes the data into the location that's given by argument. Each argument + * must be a pointer to a variable of a type that corresponds to a type specifier + * in format. If copying occurs between strings that overlap, the behavior is + * undefined. + * + * + * format Format control string. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Returns the number of fields successfully converted and assigned; + * the return value does not include fields that were read but not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vscanf_s(const char *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + SecFileStream fStr; + SECUREC_FILE_STREAM_FROM_STDIN(&fStr); + /* + * The "va_list" has different definition on different platform, so we can't use argList == NULL + * To determine it's invalid. If you has fixed platform, you can check some fields to validate it, + * such as "argList == NULL" or argList.xxx != NULL or *(size_t *)&argList != 0. + */ +#if SECUREC_ENABLE_SCANF_FILE + if (format == NULL || fStr.pf == NULL) { +#else + if (format == NULL) { +#endif + SECUREC_ERROR_INVALID_PARAMTER("vscanf_s"); + return SECUREC_SCANF_EINVAL; + } + +#if SECUREC_ENABLE_SCANF_FILE + SECUREC_LOCK_STDIN(0, fStr.pf); +#endif + retVal = SecInputS(&fStr, format, argList); +#if SECUREC_ENABLE_SCANF_FILE + SECUREC_UNLOCK_STDIN(0, fStr.pf); +#endif + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vscanf_s"); + return SECUREC_SCANF_EINVAL; + } + return retVal; +} + diff --git a/third_party/bounds_checking_function/src/vsnprintf_s.c b/third_party/bounds_checking_function/src/vsnprintf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..36619d87afac42ba914ce2475f68a2cfbcb5c980 --- /dev/null +++ b/third_party/bounds_checking_function/src/vsnprintf_s.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vsnprintf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "secureprintoutput.h" + +#if SECUREC_ENABLE_VSNPRINTF +/* + * + * The vsnprintf_s function is equivalent to the vsnprintf function + * except for the parameter destMax/count and the explicit runtime-constraints violation + * The vsnprintf_s function takes a pointer to an argument list, then formats + * and writes up to count characters of the given data to the memory pointed + * to by strDest and appends a terminating null. + * + * + * strDest Storage location for the output. + * destMax The size of the strDest for output. + * count Maximum number of character to write(not including + * the terminating NULL) + * format Format-control string. + * argList pointer to list of arguments. + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null + * return -1 if an error occurs. + * return -1 if count < destMax and the output string has been truncated + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int vsnprintf_s(char *strDest, size_t destMax, size_t count, const char *format, va_list argList) +{ + int retVal; + + if (SECUREC_VSNPRINTF_PARAM_ERROR(format, strDest, destMax, count, SECUREC_STRING_MAX_LEN)) { + SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN); + SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_s"); + return -1; + } + + if (destMax > count) { + retVal = SecVsnprintfImpl(strDest, count + 1, format, argList); + if (retVal == SECUREC_PRINTF_TRUNCATE) { /* To keep dest buffer not destroyed 2014.2.18 */ + /* The string has been truncated, return -1 */ + return -1; /* To skip error handler, return strlen(strDest) or -1 */ + } + } else { + retVal = SecVsnprintfImpl(strDest, destMax, format, argList); +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (retVal == SECUREC_PRINTF_TRUNCATE && count == (size_t)(-1)) { + return -1; + } +#endif + } + + if (retVal < 0) { + strDest[0] = '\0'; /* Empty the dest strDest */ + if (retVal == SECUREC_PRINTF_TRUNCATE) { + /* Buffer too small */ + SECUREC_ERROR_INVALID_RANGE("vsnprintf_s"); + } + SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_s"); + return -1; + } + + return retVal; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(vsnprintf_s); +#endif +#endif + +#if SECUREC_SNPRINTF_TRUNCATED +/* + * + * The vsnprintf_truncated_s function is equivalent to the vsnprintf function + * except for the parameter destMax/count and the explicit runtime-constraints violation + * The vsnprintf_truncated_s function takes a pointer to an argument list, then formats + * and writes up to count characters of the given data to the memory pointed + * to by strDest and appends a terminating null. + * + * + * strDest Storage location for the output. + * destMax The size of the strDest for output. + * the terminating NULL) + * format Format-control string. + * argList pointer to list of arguments. + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null + * return -1 if an error occurs. + * return destMax-1 if output string has been truncated + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int vsnprintf_truncated_s(char *strDest, size_t destMax, const char *format, va_list argList) +{ + int retVal; + + if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_STRING_MAX_LEN)) { + SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN); + SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_truncated_s"); + return -1; + } + + retVal = SecVsnprintfImpl(strDest, destMax, format, argList); + if (retVal < 0) { + if (retVal == SECUREC_PRINTF_TRUNCATE) { + return (int)(destMax - 1); /* To skip error handler, return strlen(strDest) */ + } + strDest[0] = '\0'; /* Empty the dest strDest */ + SECUREC_ERROR_INVALID_PARAMTER("vsnprintf_truncated_s"); + return -1; + } + + return retVal; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(vsnprintf_truncated_s); +#endif +#endif + diff --git a/third_party/bounds_checking_function/src/vsprintf_s.c b/third_party/bounds_checking_function/src/vsprintf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..012f522c4987d99a448a5f4b6a157a5d3a271e9f --- /dev/null +++ b/third_party/bounds_checking_function/src/vsprintf_s.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vsprintf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "secureprintoutput.h" + +/* + * + * The vsprintf_s function is equivalent to the vsprintf function + * except for the parameter destMax and the explicit runtime-constraints violation + * The vsprintf_s function takes a pointer to an argument list, and then formats + * and writes the given data to the memory pointed to by strDest. + * The function differ from the non-secure versions only in that the secure + * versions support positional parameters. + * + * + * strDest Storage location for the output. + * destMax Size of strDest + * format Format specification. + * argList pointer to list of arguments + * + * + * strDest is updated + * + * + * return the number of characters written, not including the terminating null character, + * return -1 if an error occurs. + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int vsprintf_s(char *strDest, size_t destMax, const char *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + + if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_STRING_MAX_LEN)) { + SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_STRING_MAX_LEN); + SECUREC_ERROR_INVALID_PARAMTER("vsprintf_s"); + return -1; + } + + retVal = SecVsnprintfImpl(strDest, destMax, format, argList); + if (retVal < 0) { + strDest[0] = '\0'; + if (retVal == SECUREC_PRINTF_TRUNCATE) { + /* Buffer is too small */ + SECUREC_ERROR_INVALID_RANGE("vsprintf_s"); + } + SECUREC_ERROR_INVALID_PARAMTER("vsprintf_s"); + return -1; + } + + return retVal; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(vsprintf_s); +#endif + diff --git a/third_party/bounds_checking_function/src/vsscanf_s.c b/third_party/bounds_checking_function/src/vsscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..6612d2fa0098cdb7db2162b48f85674d4ab0c5d1 --- /dev/null +++ b/third_party/bounds_checking_function/src/vsscanf_s.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vsscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "secinput.h" +#if defined(SECUREC_VXWORKS_PLATFORM) && !SECUREC_IN_KERNEL && \ + (!defined(SECUREC_SYSAPI4VXWORKS) && !defined(SECUREC_CTYPE_MACRO_ADAPT)) +#include +#endif + +/* + * + * vsscanf_s + * + * + * + * The vsscanf_s function is equivalent to sscanf_s, with the variable argument list replaced by argList + * The vsscanf_s function reads data from buffer into the location given by + * each argument. Every argument must be a pointer to a variable with a type + * that corresponds to a type specifier in format. The format argument controls + * the interpretation of the input fields and has the same form and function + * as the format argument for the scanf function. + * If copying takes place between strings that overlap, the behavior is undefined. + * + * + * buffer Stored data + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vsscanf_s(const char *buffer, const char *format, va_list argList) +{ + size_t count; /* If initialization causes e838 */ + int retVal; + SecFileStream fStr; + + /* Validation section */ + if (buffer == NULL || format == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s"); + return SECUREC_SCANF_EINVAL; + } + count = strlen(buffer); + if (count == 0 || count > SECUREC_STRING_MAX_LEN) { + SecClearDestBuf(buffer, format, argList); + SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s"); + return SECUREC_SCANF_EINVAL; + } +#if defined(SECUREC_VXWORKS_PLATFORM) && !SECUREC_IN_KERNEL + /* + * On vxworks platform when buffer is white string, will set first %s argument tu zero.like following useage: + * " \v\f\t\r\n", "%s", str, strSize + * Do not check all character, just first and last character then consider it is white string + */ + if (isspace((int)(unsigned char)buffer[0]) != 0 && isspace((int)(unsigned char)buffer[count - 1]) != 0) { + SecClearDestBuf(buffer, format, argList); + } +#endif + SECUREC_FILE_STREAM_FROM_STRING(&fStr, buffer, count); + retVal = SecInputS(&fStr, format, argList); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vsscanf_s"); + return SECUREC_SCANF_EINVAL; + } + return retVal; +} +#if SECUREC_IN_KERNEL +EXPORT_SYMBOL(vsscanf_s); +#endif + diff --git a/third_party/bounds_checking_function/src/vswprintf_s.c b/third_party/bounds_checking_function/src/vswprintf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..38b0b4045fd49e2788607ad984e399a74586eb8d --- /dev/null +++ b/third_party/bounds_checking_function/src/vswprintf_s.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vswprintf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SECUREC_FOR_WCHAR +#define SECUREC_FOR_WCHAR +#endif + +#include "secureprintoutput.h" + +/* + * + * The vswprintf_s function is the wide-character equivalent of the vsprintf_s function + * + * + * strDest Storage location for the output. + * destMax Maximum number of characters to store + * format Format specification. + * argList pointer to list of arguments + * + * + * strDest is updated + * + * + * return the number of wide characters stored in strDest, not counting the terminating null wide character. + * return -1 if an error occurred. + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +int vswprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + if (SECUREC_VSPRINTF_PARAM_ERROR(format, strDest, destMax, SECUREC_WCHAR_STRING_MAX_LEN)) { + SECUREC_VSPRINTF_CLEAR_DEST(strDest, destMax, SECUREC_WCHAR_STRING_MAX_LEN); + SECUREC_ERROR_INVALID_PARAMTER("vswprintf_s"); + return -1; + } + + retVal = SecVswprintfImpl(strDest, destMax, format, argList); + if (retVal < 0) { + strDest[0] = L'\0'; + if (retVal == SECUREC_PRINTF_TRUNCATE) { + /* Buffer too small */ + SECUREC_ERROR_INVALID_RANGE("vswprintf_s"); + } + SECUREC_ERROR_INVALID_PARAMTER("vswprintf_s"); + return -1; + } + + return retVal; +} + diff --git a/third_party/bounds_checking_function/src/vswscanf_s.c b/third_party/bounds_checking_function/src/vswscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..d416b96c7f4f440524aa6eb8517803775aba75cc --- /dev/null +++ b/third_party/bounds_checking_function/src/vswscanf_s.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vswscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SECUREC_FOR_WCHAR +#define SECUREC_FOR_WCHAR +#endif + +#include "secinput.h" + +SECUREC_INLINE size_t SecWcslen(const wchar_t *s) +{ + const wchar_t *end = s; + while (*end != L'\0') { + ++end; + } + return ((size_t)((end - s))); +} + +/* + * + * The vswscanf_s function is the wide-character equivalent of the vsscanf_s function + * The vsscanf_s function reads data from buffer into the location given by + * each argument. Every argument must be a pointer to a variable with a type + * that corresponds to a type specifier in format. + * The format argument controls the interpretation of the input fields and + * has the same form and function as the format argument for the scanf function. + * If copying takes place between strings that overlap, the behavior is undefined. + * + * + * buffer Stored data + * format Format control string, see Format Specifications. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Each of these functions returns the number of fields successfully converted + * and assigned; the return value does not include fields that were read but + * not assigned. A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vswscanf_s(const wchar_t *buffer, const wchar_t *format, va_list argList) +{ + size_t count; /* If initialization causes e838 */ + SecFileStream fStr; + int retVal; + + /* Validation section */ + if (buffer == NULL || format == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s"); + return SECUREC_SCANF_EINVAL; + } + count = SecWcslen(buffer); + if (count == 0 || count > SECUREC_WCHAR_STRING_MAX_LEN) { + SecClearDestBufW(buffer, format, argList); + SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s"); + return SECUREC_SCANF_EINVAL; + } + SECUREC_FILE_STREAM_FROM_STRING(&fStr, (const char *)buffer, count * sizeof(wchar_t)); + retVal = SecInputSW(&fStr, format, argList); + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vswscanf_s"); + return SECUREC_SCANF_EINVAL; + } + return retVal; +} + diff --git a/third_party/bounds_checking_function/src/vwscanf_s.c b/third_party/bounds_checking_function/src/vwscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..634abc22b190e73bf0ee746db444f4d0053bdc79 --- /dev/null +++ b/third_party/bounds_checking_function/src/vwscanf_s.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: vwscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#ifndef SECUREC_FOR_WCHAR +#define SECUREC_FOR_WCHAR +#endif + +#include "secinput.h" + +/* + * + * The vwscanf_s function is the wide-character equivalent of the vscanf_s function + * The vwscanf_s function is the wide-character version of vscanf_s. The + * function reads data from the standard input stream stdin and writes the + * data into the location that's given by argument. Each argument must be a + * pointer to a variable of a type that corresponds to a type specifier in + * format. If copying occurs between strings that overlap, the behavior is + * undefined. + * + * + * format Format control string. + * argList pointer to list of arguments + * + * + * argList the converted value stored in user assigned address + * + * + * Returns the number of fields successfully converted and assigned; + * the return value does not include fields that were read but not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int vwscanf_s(const wchar_t *format, va_list argList) +{ + int retVal; /* If initialization causes e838 */ + SecFileStream fStr; + SECUREC_FILE_STREAM_FROM_STDIN(&fStr); +#if SECUREC_ENABLE_SCANF_FILE + if (format == NULL || fStr.pf == NULL) { +#else + if (format == NULL) { +#endif + SECUREC_ERROR_INVALID_PARAMTER("vwscanf_s"); + return SECUREC_SCANF_EINVAL; + } + +#if SECUREC_ENABLE_SCANF_FILE + SECUREC_LOCK_STDIN(0, fStr.pf); +#endif + retVal = SecInputSW(&fStr, format, argList); +#if SECUREC_ENABLE_SCANF_FILE + SECUREC_UNLOCK_STDIN(0, fStr.pf); +#endif + if (retVal < 0) { + SECUREC_ERROR_INVALID_PARAMTER("vwscanf_s"); + return SECUREC_SCANF_EINVAL; + } + + return retVal; +} + diff --git a/third_party/bounds_checking_function/src/wcscat_s.c b/third_party/bounds_checking_function/src/wcscat_s.c new file mode 100644 index 0000000000000000000000000000000000000000..780907bf3d85a0e1fbf74b535e0bc761ba2dce4c --- /dev/null +++ b/third_party/bounds_checking_function/src/wcscat_s.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: wcscat_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +/* + * Befor this function, the basic parameter checking has been done + */ +SECUREC_INLINE errno_t SecDoCatW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc) +{ + size_t destLen; + size_t srcLen; + size_t maxCount; /* Store the maximum available count */ + + /* To calculate the length of a wide character, the parameter must be a wide character */ + SECUREC_CALC_WSTR_LEN(strDest, destMax, &destLen); + maxCount = destMax - destLen; + SECUREC_CALC_WSTR_LEN(strSrc, maxCount, &srcLen); + + if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) { + strDest[0] = L'\0'; + if (strDest + destLen <= strSrc && destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wcscat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_BUFFER_OVERLAP("wcscat_s"); + return EOVERLAP_AND_RESET; + } + if (srcLen + destLen >= destMax || strDest == strSrc) { + strDest[0] = L'\0'; + if (destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wcscat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_INVALID_RANGE("wcscat_s"); + return ERANGE_AND_RESET; + } + /* Copy single character length include \0 */ + SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, (srcLen + 1) * sizeof(wchar_t)); + return EOK; +} + +/* + * + * The wcscat_s function appends a copy of the wide string pointed to by strSrc +* (including the terminating null wide character) + * to the end of the wide string pointed to by strDest. + * The arguments and return value of wcscat_s are wide-character strings. + * + * The wcscat_s function appends strSrc to strDest and terminates the resulting + * string with a null character. The initial character of strSrc overwrites the + * terminating null character of strDest. wcscat_s will return EOVERLAP_AND_RESET if the + * source and destination strings overlap. + * + * Note that the second parameter is the total size of the buffer, not the + * remaining size. + * + * + * strDest Null-terminated destination string buffer. + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid) or + * (strDest != NULL and strSrc is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN) + * ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t wcscat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("wcscat_s"); + return ERANGE; + } + + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("wcscat_s"); + if (strDest != NULL) { + strDest[0] = L'\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + + return SecDoCatW(strDest, destMax, strSrc); +} + diff --git a/third_party/bounds_checking_function/src/wcscpy_s.c b/third_party/bounds_checking_function/src/wcscpy_s.c new file mode 100644 index 0000000000000000000000000000000000000000..89c281df6bf5f58a4596725787462e8559ce76c0 --- /dev/null +++ b/third_party/bounds_checking_function/src/wcscpy_s.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: wcscpy_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +SECUREC_INLINE errno_t SecDoCpyW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc) +{ + size_t srcStrLen; + SECUREC_CALC_WSTR_LEN(strSrc, destMax, &srcStrLen); + + if (srcStrLen == destMax) { + strDest[0] = L'\0'; + SECUREC_ERROR_INVALID_RANGE("wcscpy_s"); + return ERANGE_AND_RESET; + } + if (strDest == strSrc) { + return EOK; + } + + if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, srcStrLen)) { + /* Performance optimization, srcStrLen is single character length include '\0' */ + SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, (srcStrLen + 1) * sizeof(wchar_t)); + return EOK; + } else { + strDest[0] = L'\0'; + SECUREC_ERROR_BUFFER_OVERLAP("wcscpy_s"); + return EOVERLAP_AND_RESET; + } +} + +/* + * + * The wcscpy_s function copies the wide string pointed to by strSrc + * (including theterminating null wide character) into the array pointed to by strDest + + * + * strDest Destination string buffer + * destMax Size of the destination string buffer. + * strSrc Null-terminated source string buffer. + * + * + * strDest is updated. + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * EINVAL_AND_RESET strDest != NULL and strSrc is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET destMax <= length of strSrc and strDest != strSrc + * and strDest != NULL and strSrc != NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * and strDest != NULL and strSrc !=NULL and strDest != strSrc + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t wcscpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("wcscpy_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("wcscpy_s"); + if (strDest != NULL) { + strDest[0] = L'\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + return SecDoCpyW(strDest, destMax, strSrc); +} + diff --git a/third_party/bounds_checking_function/src/wcsncat_s.c b/third_party/bounds_checking_function/src/wcsncat_s.c new file mode 100644 index 0000000000000000000000000000000000000000..6151da4425553a73bc016a09dcf33fc8cea91675 --- /dev/null +++ b/third_party/bounds_checking_function/src/wcsncat_s.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: wcsncat_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +/* + * Befor this function, the basic parameter checking has been done + */ +SECUREC_INLINE errno_t SecDoCatLimitW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count) +{ + /* To calculate the length of a wide character, the parameter must be a wide character */ + size_t destLen; + size_t srcLen; + SECUREC_CALC_WSTR_LEN(strDest, destMax, &destLen); + SECUREC_CALC_WSTR_LEN(strSrc, count, &srcLen); + + if (SECUREC_CAT_STRING_IS_OVERLAP(strDest, destLen, strSrc, srcLen)) { + strDest[0] = L'\0'; + if (strDest + destLen <= strSrc && destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_BUFFER_OVERLAP("wcsncat_s"); + return EOVERLAP_AND_RESET; + } + if (srcLen + destLen >= destMax || strDest == strSrc) { + strDest[0] = L'\0'; + if (destLen == destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s"); + return EINVAL_AND_RESET; + } + SECUREC_ERROR_INVALID_RANGE("wcsncat_s"); + return ERANGE_AND_RESET; + } + SECUREC_MEMCPY_WARP_OPT(strDest + destLen, strSrc, srcLen * sizeof(wchar_t)); /* no terminator */ + *(strDest + destLen + srcLen) = L'\0'; + return EOK; +} + +/* + * + * The wcsncat_s function appends not more than n successive wide characters + * (not including the terminating null wide character) + * from the array pointed to by strSrc to the end of the wide string pointed to by strDest. + * + * The wcsncat_s function try to append the first D characters of strSrc to + * the end of strDest, where D is the lesser of count and the length of strSrc. + * If appending those D characters will fit within strDest (whose size is + * given as destMax) and still leave room for a null terminator, then those + * characters are appended, starting at the original terminating null of + * strDest, and a new terminating null is appended; otherwise, strDest[0] is + * set to the null character. + * + * + * strDest Null-terminated destination string. + * destMax Size of the destination buffer. + * strSrc Null-terminated source string. + * count Number of character to append, or truncate. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid) or + * (strDest != NULL and strSrc is NULLL and destMax != 0 and + * destMax <= SECUREC_WCHAR_STRING_MAX_LEN) + * ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t wcsncat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("wcsncat_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s"); + if (strDest != NULL) { + strDest[0] = L'\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > SECUREC_WCHAR_STRING_MAX_LEN) { +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (count == ((size_t)(-1))) { + /* Windows internal functions may pass in -1 when calling this function */ + return SecDoCatLimitW(strDest, destMax, strSrc, destMax); + } +#endif + strDest[0] = L'\0'; + SECUREC_ERROR_INVALID_RANGE("wcsncat_s"); + return ERANGE_AND_RESET; + } + return SecDoCatLimitW(strDest, destMax, strSrc, count); +} + diff --git a/third_party/bounds_checking_function/src/wcsncpy_s.c b/third_party/bounds_checking_function/src/wcsncpy_s.c new file mode 100644 index 0000000000000000000000000000000000000000..8bd5737bbc46cbfe4a59d6307293f7803069e373 --- /dev/null +++ b/third_party/bounds_checking_function/src/wcsncpy_s.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: wcsncpy_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +SECUREC_INLINE errno_t SecDoCpyLimitW(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count) +{ + size_t srcStrLen; + if (count < destMax) { + SECUREC_CALC_WSTR_LEN(strSrc, count, &srcStrLen); + } else { + SECUREC_CALC_WSTR_LEN(strSrc, destMax, &srcStrLen); + } + if (srcStrLen == destMax) { + strDest[0] = L'\0'; + SECUREC_ERROR_INVALID_RANGE("wcsncpy_s"); + return ERANGE_AND_RESET; + } + if (strDest == strSrc) { + return EOK; + } + if (SECUREC_STRING_NO_OVERLAP(strDest, strSrc, srcStrLen)) { + /* Performance optimization srcStrLen not include '\0' */ + SECUREC_MEMCPY_WARP_OPT(strDest, strSrc, srcStrLen * sizeof(wchar_t)); + *(strDest + srcStrLen) = L'\0'; + return EOK; + } else { + strDest[0] = L'\0'; + SECUREC_ERROR_BUFFER_OVERLAP("wcsncpy_s"); + return EOVERLAP_AND_RESET; + } +} + +/* + * + * The wcsncpy_s function copies not more than n successive wide characters + * (not including the terminating null wide character) + * from the array pointed to by strSrc to the array pointed to by strDest + * + * + * strDest Destination string. + * destMax The size of the destination string, in characters. + * strSrc Source string. + * count Number of characters to be copied. + * + * + * strDest is updated + * + * + * EOK Success + * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * EINVAL_AND_RESET strDest != NULL and strSrc is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_STRING_MAX_LEN + * ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0 + * ERANGE_AND_RESET count > SECUREC_WCHAR_STRING_MAX_LEN or + * (destMax <= length of strSrc and destMax <= count and strDest != strSrc + * and strDest != NULL and strSrc != NULL and destMax != 0 and + * destMax <= SECUREC_WCHAR_STRING_MAX_LEN and not overlap) + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid + * + * + * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid + */ +errno_t wcsncpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) { + SECUREC_ERROR_INVALID_RANGE("wcsncpy_s"); + return ERANGE; + } + if (strDest == NULL || strSrc == NULL) { + SECUREC_ERROR_INVALID_PARAMTER("wcsncpy_s"); + if (strDest != NULL) { + strDest[0] = L'\0'; + return EINVAL_AND_RESET; + } + return EINVAL; + } + if (count > SECUREC_WCHAR_STRING_MAX_LEN) { +#ifdef SECUREC_COMPATIBLE_WIN_FORMAT + if (count == (size_t)(-1)) { + return SecDoCpyLimitW(strDest, destMax, strSrc, destMax - 1); + } +#endif + strDest[0] = L'\0'; /* Clear dest string */ + SECUREC_ERROR_INVALID_RANGE("wcsncpy_s"); + return ERANGE_AND_RESET; + } + + if (count == 0) { + strDest[0] = L'\0'; + return EOK; + } + + return SecDoCpyLimitW(strDest, destMax, strSrc, count); +} + diff --git a/third_party/bounds_checking_function/src/wcstok_s.c b/third_party/bounds_checking_function/src/wcstok_s.c new file mode 100644 index 0000000000000000000000000000000000000000..19284f334ed87aedf78a73860ddf2d7d92ff61f7 --- /dev/null +++ b/third_party/bounds_checking_function/src/wcstok_s.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: wcstok_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +SECUREC_INLINE int SecIsInDelimitW(wchar_t ch, const wchar_t *strDelimit) +{ + const wchar_t *ctl = strDelimit; + while (*ctl != L'\0' && *ctl != ch) { + ++ctl; + } + return (int)(*ctl != L'\0'); +} + +/* + * Find beginning of token (skip over leading delimiters). + * Note that there is no token if this loop sets string to point to the terminal null. + */ +SECUREC_INLINE wchar_t *SecFindBeginW(wchar_t *strToken, const wchar_t *strDelimit) +{ + wchar_t *token = strToken; + while (*token != L'\0') { + if (SecIsInDelimitW(*token, strDelimit) != 0) { + ++token; + continue; + } + /* Don't find any delimiter in string header, break the loop */ + break; + } + return token; +} + +/* + * Find the end of the token. If it is not the end of the string, put a null there. + */ +SECUREC_INLINE wchar_t *SecFindRestW(wchar_t *strToken, const wchar_t *strDelimit) +{ + wchar_t *token = strToken; + while (*token != L'\0') { + if (SecIsInDelimitW(*token, strDelimit) != 0) { + /* Find a delimiter, set string termintor */ + *token = L'\0'; + ++token; + break; + } + ++token; + } + return token; +} + +/* + * Update Token wide character function + */ +SECUREC_INLINE wchar_t *SecUpdateTokenW(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context) +{ + /* Point to updated position. Record string position for next search in the context */ + *context = SecFindRestW(strToken, strDelimit); + /* Determine if a token has been found */ + if (*context == strToken) { + return NULL; + } + return strToken; +} + +/* + * + * wcstok_s + * + * + * + * The wcstok_s function is the wide-character equivalent of the strtok_s function + * + * + * strToken String containing token or tokens. + * strDelimit Set of delimiter characters. + * context Used to store position information between calls to + * wcstok_s. + * + * + * context is updated + * + * The wcstok_s function is the wide-character equivalent of the strtok_s function + */ +wchar_t *wcstok_s(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context) +{ + wchar_t *orgToken = strToken; + /* Validation section */ + if (context == NULL || strDelimit == NULL) { + return NULL; + } + if (orgToken == NULL && *context == NULL) { + return NULL; + } + /* If string==NULL, continue with previous string */ + if (orgToken == NULL) { + orgToken = *context; + } + orgToken = SecFindBeginW(orgToken, strDelimit); + return SecUpdateTokenW(orgToken, strDelimit, context); +} + diff --git a/third_party/bounds_checking_function/src/wmemcpy_s.c b/third_party/bounds_checking_function/src/wmemcpy_s.c new file mode 100644 index 0000000000000000000000000000000000000000..99611809ff97c16567b016f244830db915633134 --- /dev/null +++ b/third_party/bounds_checking_function/src/wmemcpy_s.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: wmemcpy_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +/* + * + * The wmemcpy_s function copies n successive wide characters + * from the object pointed to by src into the object pointed to by dest.t. + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Buffer to copy from. + * count Number of characters to copy. + * + * + * dest buffer is uptdated. + * + * + * EOK Success + * EINVAL dest is NULL and destMax != 0 and count <= destMax + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN and count <= destMax + * ERANGE destMax > SECUREC_WCHAR_MEM_MAX_LEN or destMax is 0 or + * (count > destMax and dest is NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN) + * ERANGE_AND_RESET count > destMax and dest != NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and + * count <= destMax destMax != 0 and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * and dest != NULL and src != NULL and dest != src + * + * if an error occured, dest will be filled with 0 when dest and destMax valid . + * If the source and destination overlap, the behavior of wmemcpy_s is undefined. + * Use wmemmove_s to handle overlapping regions. + */ +errno_t wmemcpy_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_PARAMTER("wmemcpy_s"); + return ERANGE; + } + if (count > destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wmemcpy_s"); + if (dest != NULL) { + (void)memset(dest, 0, destMax * sizeof(wchar_t)); + return ERANGE_AND_RESET; + } + return ERANGE; + } + return memcpy_s(dest, destMax * sizeof(wchar_t), src, count * sizeof(wchar_t)); +} + diff --git a/third_party/bounds_checking_function/src/wmemmove_s.c b/third_party/bounds_checking_function/src/wmemmove_s.c new file mode 100644 index 0000000000000000000000000000000000000000..e66e29b7398ed9c75219a20a4b6338dc71badae8 --- /dev/null +++ b/third_party/bounds_checking_function/src/wmemmove_s.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: wmemmove_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securecutil.h" + +/* + * + * The wmemmove_s function copies n successive wide characters from the object pointed + * to by src into the object pointed to by dest. + * + * + * dest Destination buffer. + * destMax Size of the destination buffer. + * src Source object. + * count Number of bytes or character to copy. + * + * + * dest is updated. + * + * + * EOK Success + * EINVAL dest is NULL and destMax != 0 and count <= destMax + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN and count <= destMax + * ERANGE destMax > SECUREC_WCHAR_MEM_MAX_LEN or destMax is 0 or + * (count > destMax and dest is NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN) + * ERANGE_AND_RESET count > destMax and dest != NULL and destMax != 0 + * and destMax <= SECUREC_WCHAR_MEM_MAX_LEN + * + * + * If an error occured, dest will be filled with 0 when dest and destMax valid. + * If some regions of the source area and the destination overlap, wmemmove_s + * ensures that the original source bytes in the overlapping region are copied + * before being overwritten + */ +errno_t wmemmove_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count) +{ + if (destMax == 0 || destMax > SECUREC_WCHAR_MEM_MAX_LEN) { + SECUREC_ERROR_INVALID_PARAMTER("wmemmove_s"); + return ERANGE; + } + if (count > destMax) { + SECUREC_ERROR_INVALID_PARAMTER("wmemmove_s"); + if (dest != NULL) { + (void)memset(dest, 0, destMax * sizeof(wchar_t)); + return ERANGE_AND_RESET; + } + return ERANGE; + } + return memmove_s(dest, destMax * sizeof(wchar_t), src, count * sizeof(wchar_t)); +} + diff --git a/third_party/bounds_checking_function/src/wscanf_s.c b/third_party/bounds_checking_function/src/wscanf_s.c new file mode 100644 index 0000000000000000000000000000000000000000..0a3df7768b1ea6cc035b94a0378d6625b9a300c4 --- /dev/null +++ b/third_party/bounds_checking_function/src/wscanf_s.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved. + * Licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * Description: wscanf_s function + * Author: lishunda + * Create: 2014-02-25 + */ + +#include "securec.h" + +/* + * + * + * The wscanf_s function is the wide-character equivalent of the scanf_s function + * The wscanf_s function reads data from the standard input stream stdin and + * writes the data into the location that's given by argument. Each argument + * must be a pointer to a variable of a type that corresponds to a type specifier + * in format. If copying occurs between strings that overlap, the behavior is + * undefined. + * + * + * format Format control string. + * ... Optional arguments. + * + * + * ... the converted value stored in user assigned address + * + * + * Returns the number of fields successfully converted and assigned; + * the return value does not include fields that were read but not assigned. + * A return value of 0 indicates that no fields were assigned. + * return -1 if an error occurs. + */ +int wscanf_s(const wchar_t *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list argList; + + va_start(argList, format); + ret = vwscanf_s(format, argList); + va_end(argList); + (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} +