diff --git a/.azure-pipeline.yml b/.azure-pipeline.yml new file mode 100644 index 0000000000..6e6f377211 --- /dev/null +++ b/.azure-pipeline.yml @@ -0,0 +1,128 @@ +trigger: + branches: + include: + - master + +pr: + branches: + include: + - '*' + +strategy: + matrix: + Linux amd64 GCC: + VM_IMAGE: 'ubuntu-22.04' + SDK_PLATFORM: linux-amd64 + APT_PACKAGES: g++-10 + SCONS_BUILD_ARGS: platform=x86-64 --mode=opt-host,nacl --no-clang werror=0 + SCONS_TESTS: small_tests medium_tests large_tests + VPYTHON: pyenv/bin/python + Linux i686 GCC: + VM_IMAGE: 'ubuntu-22.04' + APT_ARCHITECTURE: i386 + SDK_PLATFORM: linux-amd64 + APT_PACKAGES: g++-i686-linux-gnu libc6:i386 + SCONS_BUILD_ARGS: platform=x86-32 --mode=opt-host,nacl --no-clang werror=0 + SCONS_TESTS: small_tests medium_tests large_tests + VPYTHON: pyenv/bin/python + Linux armhf GCC: + # There is an IO bug in qemu-arm from ubuntu-22.04. + VM_IMAGE: 'ubuntu-24.04' + SDK_PLATFORM: arm-xxx + APT_PACKAGES: g++-arm-linux-gnueabihf qemu-user + SCONS_BUILD_ARGS: platform=arm --mode=opt-host,nacl --no-clang werror=0 + SCONS_TESTS: no_gdb_tests=1 small_tests medium_tests + VPYTHON: pyenv/bin/python + Linux amd64 Clang: + VM_IMAGE: 'ubuntu-22.04' + SDK_PLATFORM: linux-amd64 + SCONS_BUILD_ARGS: platform=x86-64 --mode=opt-host,nacl --clang werror=1 + SCONS_TESTS: small_tests medium_tests large_tests + VPYTHON: pyenv/bin/python + macOS amd64 AppleClang: + VM_IMAGE: 'macOS-15' + SDK_PLATFORM: macos-amd64 + SCONS_BUILD_ARGS: platform=x86-64 --mode=opt-host,nacl --clang werror=1 + SCONS_TESTS: all_tests + VPYTHON: pyenv/bin/python + NPROC_COMMAND: sysctl -n hw.logicalcpu + Windows amd64 MSVC: + VM_IMAGE: 'windows-2025' + SDK_PLATFORM: windows-amd64 + SCONS_BUILD_ARGS: platform=x86-64 --mode=opt-host,nacl --no-clang werror=1 mingw_dir=mingw/mingw + SCONS_TESTS: small_tests medium_tests large_tests disable_tests=run_toolchain_python_tests + VPYTHON: pyenv/Scripts/python + PYTHON_PACKAGES: pywin32 + MINGW_URL: https://github.com/niXman/mingw-builds-binaries/releases/download/16.1.0-rt_v14-rev1/x86_64-16.1.0-release-posix-seh-msvcrt-rt_v14-rev1.7z + Windows i686 MSVC: + VM_IMAGE: 'windows-2025' + SDK_PLATFORM: windows-amd64 + SCONS_BUILD_ARGS: platform=x86-32 --mode=opt-host,nacl --no-clang werror=1 mingw_dir=mingw/mingw + VPYTHON: pyenv/Scripts/python + PYTHON_PACKAGES: pywin32 + MINGW_URL: https://github.com/niXman/mingw-builds-binaries/releases/download/16.1.0-rt_v14-rev1/i686-16.1.0-release-posix-dwarf-msvcrt-rt_v14-rev1.7z + Windows amd64 MinGW: + VM_IMAGE: 'windows-2025' + SDK_PLATFORM: windows-amd64 + SCONS_BUILD_ARGS: platform=x86-64 --mode=opt-host,nacl --no-clang mingw=1 werror=1 mingw_dir=mingw/mingw + SCONS_TESTS: small_tests medium_tests large_tests disable_tests=run_toolchain_python_tests + VPYTHON: pyenv/Scripts/python + PYTHON_PACKAGES: pywin32 + MINGW_URL: https://github.com/niXman/mingw-builds-binaries/releases/download/16.1.0-rt_v14-rev1/x86_64-16.1.0-release-posix-seh-msvcrt-rt_v14-rev1.7z + +pool: + vmImage: $(VM_IMAGE) + +steps: +- bash: | + set -xue + CURL() { + curl -fsSL --retry 8 "$@" + } + if [ -n "${APT_ARCHITECTURE:-}" ]; then + sudo dpkg --add-architecture "${APT_ARCHITECTURE}" + fi + if [ -n "${APT_PACKAGES:-}" ]; then + sudo apt-get update && sudo apt-get -y -q --no-install-recommends install ${APT_PACKAGES} + fi + python3 -m venv pyenv + # TODO pin scons to a specific version? + $(VPYTHON) -m pip install SCons ${PYTHON_PACKAGES:-} + mkdir sdk + ( + cd sdk + if [ "$(SDK_PLATFORM)" = "arm-xxx" ]; then + sdk_url='https://dl.illwieckz.net/b/saigo/preview/saigo_newlib_20241119.txz' + else + sdk_url='https://github.com/DaemonEngine/saigo-nacl-sdk/releases/download/v20260805/saigosdk-$(SDK_PLATFORM)_21.0-20260805.tar.xz' + fi + CURL "$sdk_url" -o sdk.tar.xz + tar -xJf sdk.tar.xz + rm sdk.tar.xz + mv * sdk # Rename the top-level dir to sdk + ) + if [ -n "${MINGW_URL:-}" ]; then + mkdir mingw + ( + cd mingw + CURL $(MINGW_URL) -o mingw.7z + 7z x mingw.7z + rm mingw.7z + mv * mingw # Rename the top-level dir to mingw + ) + fi + displayName: 'Setup' + +- bash: | + set -xue + parallelism="$(${NPROC_COMMAND:-nproc})" + echo "Build parallelism: ${parallelism}" + $(VPYTHON) -m SCons saigo=1 saigo_newlib_dir=sdk/sdk ${SCONS_BUILD_ARGS} all_programs -j${parallelism} --verbose + displayName: 'Build' + +- bash: | + set -xue + parallelism="$(${NPROC_COMMAND:-nproc})" + $(VPYTHON) -m SCons saigo=1 saigo_newlib_dir=sdk/sdk ${SCONS_BUILD_ARGS} ${SCONS_TESTS} -j${parallelism} --verbose --keep-going disable_flaky_tests=1 + condition: and(succeeded(), ne(variables['SCONS_TESTS'], '')) + displayName: 'Test' diff --git a/SConstruct b/SConstruct index a579737e29..dad2f644fb 100755 --- a/SConstruct +++ b/SConstruct @@ -388,7 +388,7 @@ def SetUpArgumentBits(env): 'to run the specified test(s) without actually running them. This ' 'argument is a counterpart to built_elsewhere.') - BitFromArgument(env, 'no_gdb_tests', default=True, + BitFromArgument(env, 'no_gdb_tests', default=env.Bit('host_mac_arm64'), desc='Prevents GDB tests from running. If GDB is not available, you can ' 'test everything else by specifying this flag.') @@ -637,7 +637,6 @@ nacl_glibc_skiplist = set([ 'run_abi_test', # Syscall wrappers not implemented yet. 'run_sysbasic_test', - 'run_sysbrk_test', # Fails because clock() is not hooked up. 'run_timefuncs_test', # Needs further investigation. @@ -2520,42 +2519,47 @@ def which(cmd, paths=os.environ.get('PATH', '').split(os.pathsep)): return True return False +def SetUpNoBuildEnv(env): + def FakeInstall(dest, source, env): + print('Not installing', dest) + # Replace build commands with no-ops + env.Replace(CC='true', CXX='true', LD='true', + AR='true', RANLIB='true', INSTALL=FakeInstall) + def SetUpLinuxEnvX86(env): if env.Bit('built_elsewhere'): - def FakeInstall(dest, source, env): - print('Not installing', dest) - # Replace build commands with no-ops - env.Replace(CC='true', CXX='true', LD='true', - AR='true', RANLIB='true', INSTALL=FakeInstall) + SetUpNoBuildEnv(env) else: - env.Prepend(CCFLAGS=sysroot_flags, - ASFLAGS=[], - ) + env.Prepend(CCFLAGS=sysroot_flags) if env.Bit('clang'): # TODO use --target=i386-linux-gnu or whetever? env.Prepend( - CCFLAGS = ['-m32'] + sysroot_flags, - LINKFLAGS = ['-m32'] + sysroot_flags, + CCFLAGS = ['-m32'], + LINKFLAGS = ['-m32'], ) else: env.Replace(CC='i686-linux-gnu-gcc', CXX='i686-linux-gnu-g++', LD='i686-linux-gnu-ld') +def SetUpLinuxEnvX8664(env): + if env.Bit('built_elsewhere'): + SetUpNoBuildEnv(env) + else: + # Assumes x86-64 is the native platform for now + env.Prepend( + CCFLAGS = ['-m64'] + sysroot_flags, + LINKFLAGS = ['-m64'] + sysroot_flags, + ) + def SetUpLinuxEnvArm(env): if not platform.machine().startswith('a'): # Allow emulation on non-ARM hosts. env.Replace(EMULATOR='qemu-armhf -L /usr/arm-linux-gnueabihf/ -cpu cortex-a9') if env.Bit('built_elsewhere'): - def FakeInstall(dest, source, env): - print('Not installing', dest) - # Replace build commands with no-ops - env.Replace(CC='true', CXX='true', LD='true', - AR='true', RANLIB='true', INSTALL=FakeInstall) + SetUpNoBuildEnv(env) else: - env.Prepend(CCFLAGS=sysroot_flags, - ASFLAGS=[], - ) + env.Prepend(CCFLAGS=sysroot_flags) if env.Bit('clang'): env.Prepend(CCFLAGS=['--target=arm-linux-gnueabihf']) env.Prepend(LINKFLAGS=['--target=arm-linux-gnueabihf']) @@ -2752,10 +2756,7 @@ def MakeGenericLinuxEnv(platform=None): if linux_env.Bit('build_x86_32'): SetUpLinuxEnvX86(linux_env) elif linux_env.Bit('build_x86_64'): - linux_env.Prepend( - CCFLAGS = ['-m64'] + sysroot_flags, - LINKFLAGS = ['-m64'] + sysroot_flags, - ) + SetUpLinuxEnvX8664(linux_env) elif linux_env.Bit('build_arm'): SetUpLinuxEnvArm(linux_env) elif linux_env.Bit('build_mips32'): @@ -3222,11 +3223,9 @@ irt_only_tests = [ #### ALPHABETICALLY SORTED #### 'tests/elf_loader/nacl.scons', 'tests/irt/nacl.scons', - 'tests/irt_compatibility/nacl.scons', 'tests/irt_entry_alignment/nacl.scons', 'tests/irt_ext/nacl.scons', 'tests/irt_stack_alignment/nacl.scons', - 'tests/sbrk/nacl.scons', 'tests/translator_size_limits/nacl.scons', ] diff --git a/pynacl/platform.py b/pynacl/platform.py index ca637936d5..b0e1ec60d4 100644 --- a/pynacl/platform.py +++ b/pynacl/platform.py @@ -200,7 +200,7 @@ def PlatformTripleSaigo(platform=None, machine=None): def KillSubprocessAndChildren(proc): """Kill a subprocess and all children. - While this is trivial on Posix platforms, on Windows this requires some + On Windows this requires some method for walking the process tree. Relying on this functionality in the taskkill.exe utility for now. @@ -210,8 +210,10 @@ def KillSubprocessAndChildren(proc): if IsWindows(): # Do subprocess call as the process may terminate before we manage # to invoke taskkill. + # TODO: use job object instead? subprocess.call( [os.path.join(os.environ['SYSTEMROOT'], 'System32', 'taskkill.exe'), '/F', '/T', '/PID', str(proc.pid)]) else: + # TODO: implement for *nix. This kills only the one process proc.kill() diff --git a/run.py b/run.py index 30fc773c69..dcfa67eee5 100755 --- a/run.py +++ b/run.py @@ -470,6 +470,9 @@ def Run(args, cwd=None, verbose=True, exit_on_failure=False, # PNaCl toolchain executables (pnacl-translate, readelf) are scripts # not binaries, so it doesn't want to run on Windows without a shell. use_shell = True if pynacl.platform.IsWindows() else False + if use_shell: + args = args[:] + args[0] = os.path.normpath(args[0]) # Must use \ not / p = subprocess.Popen(args, stdin=stdin_redir, stdout=stdout_redir, stderr=stderr_redir, cwd=cwd, shell=use_shell, encoding='utf-8') @@ -590,7 +593,7 @@ def FindReadElf(): # Look for Saigo or PNaCl readelf or the system one # The architecture the toolchain was built for generally doesn't matter. - readelves = ['x86_64-nacl-readelf', 'pnacl-readelf', 'readelf'] + readelves = ['nacl-readelf', 'x86_64-nacl-readelf', 'pnacl-readelf', 'readelf'] toolchain_paths = [os.path.join(env.saigo_base, 'bin'), os.path.join(env.pnacl_base, 'bin')] diff --git a/site_scons/site_tools/naclsdk.py b/site_scons/site_tools/naclsdk.py index 28ad4aa639..1688906392 100755 --- a/site_scons/site_tools/naclsdk.py +++ b/site_scons/site_tools/naclsdk.py @@ -65,7 +65,8 @@ def _StubOutEnvToolsForBuiltElsewhere(env): env.Replace(CC='true', CXX='true', LINK='true', AR='true', RANLIB='true', AS='true', ASPP='true', LD='true', STRIP='true', OBJDUMP='true', OBJCOPY='true', - PNACLOPT='true', PNACLFINALIZE='true') + PNACLOPT='true', PNACLFINALIZE='true', + GDB='false') def _SetEnvForNativeSdk(env, sdk_path): @@ -112,6 +113,13 @@ def _SetEnvForNativeSdk(env, sdk_path): cc = 'clang' if env.Bit('nacl_clang') else 'gcc' cxx = 'clang++' if env.Bit('nacl_clang') else 'g++' + def FindRenamedTool(tool): + # For ones renamed in https://github.com/DaemonEngine/saigo-nacl-sdk/releases/tag/v20260805 + newname = os.path.join(bin_path, 'nacl-' + tool) + if os.path.exists(newname) or os.path.exists(newname + '.exe'): + return newname + return os.path.join(bin_path, '%s-%s' % (tool_prefix, tool)) + env.Replace(# Replace header and lib paths. # where to put nacl extra sdk headers # TODO(robertm): switch to using the mechanism that @@ -125,18 +133,17 @@ def _SetEnvForNativeSdk(env, sdk_path): AR=os.path.join(bin_path, '%s-ar' % tool_prefix), AS=os.path.join(bin_path, '%s-as' % tool_prefix), ASPP=os.path.join(bin_path, '%s-%s' % (tool_prefix, cc)), - FILECHECK=os.path.join(bin_path, 'FileCheck'), - GDB=os.path.join(bin_path, '%s-gdb' % tool_prefix), + GDB=FindRenamedTool('gdb'), # NOTE: use g++ for linking so we can handle C AND C++. LINK=os.path.join(bin_path, '%s-%s' % (tool_prefix, cxx)), # Grrr... and sometimes we really need ld. LD=os.path.join(bin_path, '%s-ld' % tool_prefix) + ld_mode_flag, - RANLIB=os.path.join(bin_path, '%s-ranlib' % tool_prefix), - NM=os.path.join(bin_path, '%s-nm' % tool_prefix), - OBJDUMP=os.path.join(bin_path, '%s-objdump' % tool_prefix), + RANLIB=FindRenamedTool('ranlib'), + NM=FindRenamedTool('nm'), + OBJDUMP=FindRenamedTool('objdump'), OBJCOPY=os.path.join(bin_path, '%s-objcopy' % tool_prefix), STRIP=os.path.join(bin_path, '%s-strip' % tool_prefix), - ADDR2LINE=os.path.join(bin_path, '%s-addr2line' % tool_prefix), + ADDR2LINE='false', BASE_LINKFLAGS=[cc_mode_flag], BASE_CFLAGS=[cc_mode_flag], BASE_CXXFLAGS=[cc_mode_flag], @@ -755,21 +762,6 @@ def FakeInstall(dest, source, env): else: _SetEnvForNativeSdk(env, root) - # Daemon: don't depend on a second NaCl toolchain! - if (env.Bit('bitcode') or env.Bit('nacl_clang')) and env.Bit('build_x86') and \ - not env.Bit('no_gdb_tests') and 'nacl_gdb' not in SCons.Script.ARGUMENTS: - # Get GDB from the nacl-gcc glibc toolchain even when using PNaCl. - # TODO(mseaborn): We really want the nacl-gdb binary to be in a - # separate tarball from the nacl-gcc toolchain, then this step - # will not be necessary. - # See http://code.google.com/p/nativeclient/issues/detail?id=2773 - temp_env = env.Clone() - temp_env.ClearBits('bitcode', 'nacl_clang', 'saigo') - temp_env.SetBits('nacl_glibc') - temp_root = temp_env.GetToolchainDir() - _SetEnvForNativeSdk(temp_env, temp_root) - env.Replace(GDB=temp_env['GDB']) - env.Prepend(LIBPATH='${NACL_SDK_LIB}') # Install our scanner for (potential) linker scripts. diff --git a/src/shared/platform/nacl_sync_test.c b/src/shared/platform/nacl_sync_test.c index 8aeb5ee935..4a29c568d1 100644 --- a/src/shared/platform/nacl_sync_test.c +++ b/src/shared/platform/nacl_sync_test.c @@ -80,6 +80,8 @@ */ uint32_t g_timeout_milliseconds = 500; +volatile int g_done = 0; + /* * TimeOutThread is responsible for doing deadlock detection. If the * main thread hits a deadlock, then this thread will time out and @@ -114,7 +116,9 @@ void WINAPI TimeOutThread(void *thread_state) { * If we reach here, we assume that the main thread has deadlocked * and so we optimistically report that via the exit status. */ - exit(time_out_exit_status); + if (!g_done) { + exit(time_out_exit_status); + } } /* @@ -178,7 +182,7 @@ int TestLockTrylock(void) { int TestTrylockLock(void) { struct NaClMutex mu; struct NaClThread nt; - printf("TestLockTrylock\n"); + printf("TestTrylockLock\n"); printf("Constructing mutex\n"); if (!NaClMutexCtor(&mu)) return 1; printf("Trylocking mutex\n"); @@ -200,7 +204,7 @@ int TestTrylockLock(void) { int TestTrylockTrylock(void) { struct NaClMutex mu; struct NaClThread nt; - printf("TestLockTrylock\n"); + printf("TestTrylockTrylock\n"); printf("Constructing mutex\n"); if (!NaClMutexCtor(&mu)) return 1; printf("Trylocking mutex\n"); @@ -276,6 +280,7 @@ int main(int ac, char **av) { } NaClPlatformInit(); retcode = (*test_fn)(); + g_done = 1; NaClPlatformFini(); return retcode; } diff --git a/src/trusted/debug_stub/win/platform_impl.cc b/src/trusted/debug_stub/win/platform_impl.cc index 54732b8726..f6ed36da31 100644 --- a/src/trusted/debug_stub/win/platform_impl.cc +++ b/src/trusted/debug_stub/win/platform_impl.cc @@ -21,74 +21,6 @@ * Define the OS specific portions of IPlatform interface. */ - /* - * Find files mappings and replaces them with memory which can be made - * writable. Works only with code regions where debugger need to set - * breakpoints. - */ - -static bool UnmapFiles(struct NaClApp *nap, void *ptr, uint32_t len) { - DWORD old_flags; - uintptr_t max_step; - uintptr_t user_ptr = NaClSysToUser(nap, reinterpret_cast(ptr)); - if (user_ptr + len <= user_ptr || user_ptr + len > nap->dynamic_text_end) { - return false; - } - uintptr_t user_ptr_end = user_ptr + len; - uintptr_t start_page = user_ptr >> NACL_PAGESHIFT; - uintptr_t end_page = ((user_ptr_end - 1) >> NACL_PAGESHIFT) + 1; - uintptr_t page_len = end_page - start_page; - uintptr_t current_page = start_page; - char buf[0x10000]; - while (page_len > 0) { - const NaClVmmapEntry *entry = - NaClVmmapFindPage(&nap->mem_map, current_page); - if (entry == NULL) { - current_page++; - page_len--; - continue; - } - max_step = entry->npages - (current_page - entry->page_num); - if (max_step > page_len) { - max_step = page_len; - } - if (entry->flags != 0) { - for (uintptr_t i = 0; i < max_step; i++) { - void *addr = reinterpret_cast( - NaClUserToSys(nap, (current_page + i) << NACL_PAGESHIFT)); - size_t size = 0x10000; - nacl_off64_t file_size = entry->file_size - - ((current_page + i - entry->page_num) << NACL_PAGESHIFT); - if (static_cast(size) > file_size) { - size = static_cast(file_size); - } - // fill buffer with hlt. - memset(buf, 0xf4, 0x10000); - memcpy(buf, addr, size); - if (!UnmapViewOfFile(addr)) { - return false; - } - if (NULL == VirtualAlloc(addr, 0x10000, - MEM_COMMIT, PAGE_EXECUTE_READWRITE)) { - NaClLog(LOG_FATAL, - "UnmapFiles: VirtualAlloc failed with %d\n", - GetLastError()); - } - memcpy(addr, buf, 0x10000); - if (!VirtualProtect(addr, 0x10000, - PAGE_EXECUTE_READ, &old_flags)) { - NaClLog(LOG_FATAL, - "UnmapFiles: VirtualProtect failed with %d\n", - GetLastError()); - } - } - } - current_page += max_step; - page_len -= max_step; - } - return true; -} - static bool CheckReadRights(void *ptr, uint32_t len) { MEMORY_BASIC_INFORMATION memory_info; SIZE_T offset; @@ -152,14 +84,6 @@ bool IPlatform::SetMemory(struct NaClApp *nap, uint64_t virt, uint32_t len, if (oldFlags == (DWORD) -1) { oldFlags = Reprotect(reinterpret_cast(virt), len, PAGE_WRITECOPY); - if (oldFlags == (DWORD) -1) { - // Windows XP doesn't support PAGE_EXECUTE_WRITECOPY so we fallback to - // unmapping files and mapping normal memory instead. - if (UnmapFiles(nap, reinterpret_cast(virt), len)) { - oldFlags = Reprotect(reinterpret_cast(virt), len, - PAGE_WRITECOPY); - } - } } if (oldFlags == (DWORD) -1) return false; diff --git a/src/trusted/platform_qualify/build.scons b/src/trusted/platform_qualify/build.scons index c3f867d003..4afcf85534 100644 --- a/src/trusted/platform_qualify/build.scons +++ b/src/trusted/platform_qualify/build.scons @@ -63,7 +63,7 @@ if env.Bit('build_x86') and env.Bit('build_x86'): node = env.CommandTest('platform_qual_test.out', [platform_qual_test]) env.AddNodeToTestSuite( node, ['small_tests'], 'run_platform_qual_test', - is_broken=env.IsRunningUnderValgrind()) + is_broken=env.IsRunningUnderValgrind() or env.Bit('mingw')) cpuallowlist_test = env.ComponentProgram( 'cpuallowlist_test', 'arch/x86/nacl_cpuallowlist_test.c', diff --git a/src/trusted/service_runtime/build.scons b/src/trusted/service_runtime/build.scons index d5bdbb7cda..5f5d653188 100644 --- a/src/trusted/service_runtime/build.scons +++ b/src/trusted/service_runtime/build.scons @@ -533,7 +533,7 @@ hello_world_nexe = untrusted_env.File('$STAGING_DIR/hello_world.nexe') # Doesn't work on windows under coverage. # TODO(bradnelson): fix this to work on windows under coverage. if ((not env.Bit('windows') or not env.Bit('coverage_enabled')) and - env.Bit('nacl_static_link')): + env.Bit('nacl_static_link') and UsingNaclMode()): # NOTE: uses validator mmap_test_objs = [env.ComponentObject('mmap_test.c')] mmap_test_exe = env.ComponentProgram( @@ -666,7 +666,7 @@ if env.Bit('windows') and env.Bit('build_x86_64'): node = env.CommandTest( 'ntdll_fallback_test.out', command=[intercept_test_prog, 'test_fallback'], - exit_status='untrusted_segfault', + exit_status=0xC0000409, stdout_golden=env.File('win/exception_patch/fallback_test.stdout')) env.AddNodeToTestSuite(node, ['small_tests'], 'run_ntdll_fallback_test') @@ -759,17 +759,18 @@ node = env.CommandSelLdrTestNacl( exit_status='1') env.AddNodeToTestSuite(node, ['small_tests'], 'run_sel_ldr_exe_not_found_test') -# Check that "-F" makes sel_ldr stop after loading the nexe but before running -# it. -nullptr_nexe = untrusted_env.GetTranslatedNexe( - untrusted_env.File('$STAGING_DIR/nullptr$PROGSUFFIX')) +if UsingNaclMode(): + # Check that "-F" makes sel_ldr stop after loading the nexe but before running + # it. + nullptr_nexe = untrusted_env.GetTranslatedNexe( + untrusted_env.File('$STAGING_DIR/nullptr$PROGSUFFIX')) -node = env.CommandSelLdrTestNacl( - 'fuzz_nullptr_test.out', - nullptr_nexe, - size='large', - sel_ldr_flags=['-F']) -env.AddNodeToTestSuite(node, ['large_tests'], 'run_fuzz_nullptr_test') + node = env.CommandSelLdrTestNacl( + 'fuzz_nullptr_test.out', + nullptr_nexe, + size='large', + sel_ldr_flags=['-F']) + env.AddNodeToTestSuite(node, ['large_tests'], 'run_fuzz_nullptr_test') if env.Bit('build_mips32'): text_region_start = 0x00020000 @@ -836,7 +837,7 @@ if env.Bit('build_x86_64'): ) env.AddNodeToTestSuite(node, ['small_tests'], 'run_hello_x32_test') -if env.Bit('build_x86') and env.Bit('nacl_static_link'): +if env.Bit('build_x86') and env.Bit('nacl_static_link') and UsingNaclMode(): RE_HELLO = '^(Hello, World!)$' RE_IDENT = r'^\[[0-9,:.]*\] (e_ident\+1 = ELF)$' diff --git a/src/trusted/service_runtime/include/sys/nacl_syscalls.h b/src/trusted/service_runtime/include/sys/nacl_syscalls.h index 88bd43afb3..5d338334d1 100644 --- a/src/trusted/service_runtime/include/sys/nacl_syscalls.h +++ b/src/trusted/service_runtime/include/sys/nacl_syscalls.h @@ -32,11 +32,8 @@ extern void null_syscall(void); /** * @nacl - * Sets the system break to the given address and return the address after - * the update. If new_break is NULL, simply returns the current break address. - * @param new_break The address to set the break to. - * @return On success, sysbrk returns the value of the break address. On - * failure, it returns -1 and sets errno appropriately. + * Returns the initial break address if argument is NULL. + * Otherwise it returns an error */ extern void *sysbrk(void *new_break); diff --git a/src/trusted/service_runtime/mmap_test.c b/src/trusted/service_runtime/mmap_test.c index f93e638e4e..1f56e16a6e 100644 --- a/src/trusted/service_runtime/mmap_test.c +++ b/src/trusted/service_runtime/mmap_test.c @@ -393,6 +393,26 @@ int main(int argc, char **argv) { * 4. rw Stack */ + /* + * Check mprotect failures due to partially unmapped regions. + */ + addr = NaClSysMmapIntern(nap, (void *) (500 << 20), + NACL_MAP_PAGESIZE * 10, + NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, + NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_FIXED, + -1, 0); + ASSERT_EQ(addr, 500 << 20); + errcode = NaClSysMprotectInternal(nap, addr - NACL_MAP_PAGESIZE, 3 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ); + ASSERT_EQ(errcode, -NACL_ABI_EACCES); + errcode = NaClSysMprotectInternal(nap, addr + 5 * NACL_MAP_PAGESIZE, 6 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ); + ASSERT_EQ(errcode, -NACL_ABI_EACCES); + /* Now successful ones */ + errcode = NaClSysMprotectInternal(nap, addr + NACL_MAP_PAGESIZE, 3 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ); + ASSERT_EQ(errcode, 0); + errcode = NaClSysMprotectInternal(nap, addr + 5 * NACL_MAP_PAGESIZE, 5 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ); + ASSERT_EQ(errcode, 0); + + /* * Check use of hint. */ @@ -443,13 +463,13 @@ int main(int argc, char **argv) { errcode = NaClSysMunmap(natp, initial_addr, 2 * NACL_MAP_PAGESIZE); ASSERT_EQ(errcode, 0); - /* Check that we cannot make the read-only data segment writable */ + /* Make the read-only data segment writable */ ent = mem_map->vmentry[2]; errcode = NaClSysMprotectInternal(nap, (uint32_t) (ent->page_num << NACL_PAGESHIFT), - ent->npages * NACL_MAP_PAGESIZE, + ent->npages * NACL_PAGESIZE, NACL_ABI_PROT_WRITE); - ASSERT_EQ(errcode, -NACL_ABI_EACCES); + ASSERT_EQ(errcode, 0); #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64 CheckForGuardRegion(nap->mem_start - ((size_t) 40 << 30), (size_t) 40 << 30); diff --git a/src/trusted/service_runtime/sel_ldr_standard.c b/src/trusted/service_runtime/sel_ldr_standard.c index bb2a20c099..7f5c90f546 100644 --- a/src/trusted/service_runtime/sel_ldr_standard.c +++ b/src/trusted/service_runtime/sel_ldr_standard.c @@ -278,10 +278,7 @@ NaClErrorCode NaClAppLoadFileAslr(struct NaClDesc *ndp, * page boundary. * * Memory allocation will use NaClRoundPage(nap->break_addr), but - * the system notion of break is always an exact address. Even - * though we must allocate and make accessible multiples of pages, - * the linux-style brk system call (which returns current break on - * failure) permits a non-aligned address as argument. + * the system notion of break is always an exact address. */ nap->break_addr = max_vaddr; nap->data_end = max_vaddr; diff --git a/src/trusted/service_runtime/sel_util-inl.h b/src/trusted/service_runtime/sel_util-inl.h index db900972b1..4f6d591f48 100644 --- a/src/trusted/service_runtime/sel_util-inl.h +++ b/src/trusted/service_runtime/sel_util-inl.h @@ -21,18 +21,10 @@ static INLINE size_t NaClRoundPage(size_t nbytes) { return (nbytes + NACL_PAGESIZE - 1) & ~((size_t) NACL_PAGESIZE - 1); } -static INLINE uint32_t NaClRoundPage32(uint32_t nbytes) { - return (nbytes + NACL_PAGESIZE - 1) & ~((size_t) NACL_PAGESIZE - 1); -} - static INLINE size_t NaClRoundAllocPage(size_t nbytes) { return (nbytes + NACL_MAP_PAGESIZE - 1) & ~((size_t) NACL_MAP_PAGESIZE - 1); } -static INLINE uint32_t NaClRoundAllocPage32(uint32_t nbytes) { - return (nbytes + NACL_MAP_PAGESIZE - 1) & ~((uint32_t)NACL_MAP_PAGESIZE - 1); -} - static INLINE size_t NaClTruncPage(size_t nbytes) { return nbytes & ~((size_t) NACL_PAGESIZE - 1); } @@ -41,10 +33,6 @@ static INLINE size_t NaClTruncAllocPage(size_t nbytes) { return nbytes & ~((size_t) NACL_MAP_PAGESIZE - 1); } -static INLINE size_t NaClBytesToPages(size_t nbytes) { - return (nbytes + NACL_PAGESIZE - 1) >> NACL_PAGESHIFT; -} - static INLINE int /* bool */ NaClIsPageMultiple(uintptr_t addr_or_size) { return 0 == ((NACL_PAGESIZE - 1) & addr_or_size); } diff --git a/src/trusted/service_runtime/sys_memory.c b/src/trusted/service_runtime/sys_memory.c index 45562ea332..2946a61655 100644 --- a/src/trusted/service_runtime/sys_memory.c +++ b/src/trusted/service_runtime/sys_memory.c @@ -45,160 +45,17 @@ static INLINE size_t size_min(size_t a, size_t b) { return (a < b) ? a : b; } +/* + * No changing the break address, only inspecting the initial one. + * This is kept around for some tests that inspect the ELF layout. + */ int32_t NaClSysBrk(struct NaClAppThread *natp, uintptr_t new_break) { struct NaClApp *nap = natp->nap; - uintptr_t break_addr; - int32_t rv = -NACL_ABI_EINVAL; - struct NaClVmmapIter iter; - struct NaClVmmapEntry *ent; - struct NaClVmmapEntry *next_ent; - uintptr_t sys_break; - uintptr_t sys_new_break; - uintptr_t usr_last_data_page; - uintptr_t usr_new_last_data_page; - uintptr_t last_internal_data_addr; - uintptr_t last_internal_page; - uintptr_t start_new_region; - uintptr_t region_size; - - /* - * The sysbrk() IRT interface is deprecated and is not enabled for - * ABI-stable PNaCl pexes, so for security hardening, disable the - * syscall under PNaCl too. - */ - if (nap->pnacl_mode) + if (new_break != 0) return -NACL_ABI_ENOSYS; - break_addr = nap->break_addr; - - NaClLog(3, "Entered NaClSysBrk(new_break 0x%08"NACL_PRIxPTR")\n", - new_break); - - sys_new_break = NaClUserToSysAddr(nap, new_break); - NaClLog(3, "sys_new_break 0x%08"NACL_PRIxPTR"\n", sys_new_break); - - if (kNaClBadAddress == sys_new_break) { - goto cleanup_no_lock; - } - if (NACL_SYNC_OK != NaClMutexLock(&nap->mu)) { - NaClLog(LOG_ERROR, "Could not get app lock for 0x%08"NACL_PRIxPTR"\n", - (uintptr_t) nap); - goto cleanup_no_lock; - } - if (new_break < nap->data_end) { - NaClLog(4, "new_break before data_end (0x%"NACL_PRIxPTR")\n", - nap->data_end); - goto cleanup; - } - if (new_break <= nap->break_addr) { - /* freeing memory */ - NaClLog(4, "new_break before break (0x%"NACL_PRIxPTR"); freeing\n", - nap->break_addr); - nap->break_addr = new_break; - break_addr = new_break; - } else { - /* - * See if page containing new_break is in mem_map; if so, we are - * essentially done -- just update break_addr. Otherwise, we - * extend the VM map entry from the page containing the current - * break to the page containing new_break. - */ - - sys_break = NaClUserToSys(nap, nap->break_addr); - - usr_last_data_page = (nap->break_addr - 1) >> NACL_PAGESHIFT; - - usr_new_last_data_page = (new_break - 1) >> NACL_PAGESHIFT; - - last_internal_data_addr = NaClRoundAllocPage(new_break) - 1; - last_internal_page = last_internal_data_addr >> NACL_PAGESHIFT; - - NaClLog(4, ("current break sys addr 0x%08"NACL_PRIxPTR", " - "usr last data page 0x%"NACL_PRIxPTR"\n"), - sys_break, usr_last_data_page); - NaClLog(4, "new break usr last data page 0x%"NACL_PRIxPTR"\n", - usr_new_last_data_page); - NaClLog(4, "last internal data addr 0x%08"NACL_PRIxPTR"\n", - last_internal_data_addr); - - if (NULL == NaClVmmapFindPageIter(&nap->mem_map, - usr_last_data_page, - &iter) - || NaClVmmapIterAtEnd(&iter)) { - NaClLog(LOG_FATAL, ("current break (0x%08"NACL_PRIxPTR", " - "sys 0x%08"NACL_PRIxPTR") " - "not in address map\n"), - nap->break_addr, sys_break); - } - ent = NaClVmmapIterStar(&iter); - NaClLog(4, ("segment containing current break" - ": page_num 0x%08"NACL_PRIxPTR", npages 0x%"NACL_PRIxS"\n"), - ent->page_num, ent->npages); - if (usr_new_last_data_page < ent->page_num + ent->npages) { - NaClLog(4, "new break within break segment, just bumping addr\n"); - nap->break_addr = new_break; - break_addr = new_break; - } else { - NaClVmmapIterIncr(&iter); - if (!NaClVmmapIterAtEnd(&iter) - && ((next_ent = NaClVmmapIterStar(&iter))->page_num - <= last_internal_page)) { - /* ran into next segment! */ - NaClLog(4, - ("new break request of usr address " - "0x%08"NACL_PRIxPTR" / usr page 0x%"NACL_PRIxPTR - " runs into next region, page_num 0x%"NACL_PRIxPTR", " - "npages 0x%"NACL_PRIxS"\n"), - new_break, usr_new_last_data_page, - next_ent->page_num, next_ent->npages); - goto cleanup; - } - NaClLog(4, - "extending segment: page_num 0x%08"NACL_PRIxPTR", " - "npages 0x%"NACL_PRIxS"\n", - ent->page_num, ent->npages); - /* go ahead and extend ent to cover, and make pages accessible */ - start_new_region = (ent->page_num + ent->npages) << NACL_PAGESHIFT; - ent->npages = (last_internal_page - ent->page_num + 1); - region_size = (((last_internal_page + 1) << NACL_PAGESHIFT) - - start_new_region); - if (0 != NaClMprotect((void *) NaClUserToSys(nap, start_new_region), - region_size, - PROT_READ | PROT_WRITE)) { - NaClLog(LOG_FATAL, - ("Could not mprotect(0x%08"NACL_PRIxPTR", " - "0x%08"NACL_PRIxPTR", " - "PROT_READ|PROT_WRITE)\n"), - start_new_region, - region_size); - } - NaClLog(4, "segment now: page_num 0x%08"NACL_PRIxPTR", " - "npages 0x%"NACL_PRIxS"\n", - ent->page_num, ent->npages); - nap->break_addr = new_break; - break_addr = new_break; - } - /* - * Zero out memory between old break and new break. - */ - CHECK(sys_new_break > sys_break); - memset((void *) sys_break, 0, sys_new_break - sys_break); - } - -cleanup: - NaClXMutexUnlock(&nap->mu); -cleanup_no_lock: - - /* - * This cast is safe because the incoming value (new_break) cannot - * exceed the user address space--even though its type (uintptr_t) - * theoretically allows larger values. - */ - rv = (int32_t) break_addr; - - NaClLog(3, "NaClSysBrk: returning 0x%08"NACL_PRIx32"\n", rv); - return rv; + return (int32_t) NaClUserToSys(nap, nap->break_addr); } int NaClSysCommonAddrRangeContainsExecutablePages(struct NaClApp *nap, diff --git a/src/trusted/validator_ragel/build.scons b/src/trusted/validator_ragel/build.scons index 0ecf5b70b1..9f763a4596 100644 --- a/src/trusted/validator_ragel/build.scons +++ b/src/trusted/validator_ragel/build.scons @@ -545,9 +545,10 @@ for bits in ['32', '64']: '--bits', bits, tests_mask] + update_option) - env.AddNodeToTestSuite( + if UsingNaclMode(): env.AddNodeToTestSuite( dis_section_test, ['small_tests', 'validator_tests'], + is_broken=env.Bit('built_elsewhere'), # OBJDUMP is stubbed out node_name='run_dis_section_test_%s' % bits) if env.Bit('regenerate_golden'): diff --git a/src/untrusted/irt/irt.h b/src/untrusted/irt/irt.h index f86f807d3a..7f28d8f025 100644 --- a/src/untrusted/irt/irt.h +++ b/src/untrusted/irt/irt.h @@ -150,50 +150,6 @@ struct nacl_irt_filename { int (*stat)(const char *pathname, nacl_irt_stat_t *); }; -/* - * This old version of irt-memory is disabled under PNaCl because it - * contains sysbrk() (see - * https://code.google.com/p/nativeclient/issues/detail?id=3542). - */ -#define NACL_IRT_MEMORY_v0_1 "nacl-irt-memory-0.1" -struct nacl_irt_memory_v0_1 { - /* - * sysbrk() allocates memory from the "brk" heap. This function is - * deprecated; new programs should use mmap() instead. - * - * If |*newbrk| is NULL, sysbrk() sets |*newbrk| to the current - * break pointer and returns 0. - * - * If |*newbrk| is non-NULL and greater than the current break - * pointer, sysbrk() tries to allocate this memory. If the - * allocation fails, it returns ENOMEM. Otherwise, sysbrk(): - * * ensures the memory between the break pointer and |*newbrk| is - * readable and writable, and zeroes it; - * * sets the current break pointer to |*newbrk|; and - * * returns 0 to indicate success. - * - * If |*newbrk| is non-NULL and less than the current break pointer, - * sysbrk() deallocates this memory. sysbrk() sets the break - * pointer to |*newbrk| and returns 0. If |*newbrk| is less than - * the process's initial break pointer, the behaviour is undefined. - */ - int (*sysbrk)(void **newbrk); - /* Note: this version of mmap silently ignores PROT_EXEC bit. */ - int (*mmap)(void **addr, size_t len, int prot, int flags, int fd, - nacl_irt_off_t off); - int (*munmap)(void *addr, size_t len); -}; - -/* This old version of irt-memory is also disabled under PNaCl. */ -#define NACL_IRT_MEMORY_v0_2 "nacl-irt-memory-0.2" -struct nacl_irt_memory_v0_2 { - int (*sysbrk)(void **newbrk); - int (*mmap)(void **addr, size_t len, int prot, int flags, int fd, - nacl_irt_off_t off); - int (*munmap)(void *addr, size_t len); - int (*mprotect)(void *addr, size_t len, int prot); -}; - #define NACL_IRT_MEMORY_v0_3 "nacl-irt-memory-0.3" struct nacl_irt_memory { int (*mmap)(void **addr, size_t len, int prot, int flags, int fd, diff --git a/src/untrusted/irt/irt_interfaces.c b/src/untrusted/irt/irt_interfaces.c index e9c8cf3a16..9795ac3512 100644 --- a/src/untrusted/irt/irt_interfaces.c +++ b/src/untrusted/irt/irt_interfaces.c @@ -68,15 +68,6 @@ static const struct nacl_irt_interface irt_interfaces[] = { sizeof(nacl_irt_dev_filename_v0_2), file_access_filter }, { NACL_IRT_DEV_FILENAME_v0_3, &nacl_irt_dev_filename, sizeof(nacl_irt_dev_filename), file_access_filter }, - /* - * The old versions of "irt-memory", v0.1 and v0.2, which contain - * the deprecated sysbrk() function, are disabled under PNaCl. See: - * https://code.google.com/p/nativeclient/issues/detail?id=3542 - */ - { NACL_IRT_MEMORY_v0_1, &nacl_irt_memory_v0_1, sizeof(nacl_irt_memory_v0_1), - non_pnacl_filter }, - { NACL_IRT_MEMORY_v0_2, &nacl_irt_memory_v0_2, sizeof(nacl_irt_memory_v0_2), - non_pnacl_filter }, { NACL_IRT_MEMORY_v0_3, &nacl_irt_memory, sizeof(nacl_irt_memory), NULL }, /* * "irt-dyncode" is not supported under PNaCl because dynamically diff --git a/src/untrusted/irt/irt_interfaces.h b/src/untrusted/irt/irt_interfaces.h index c1e9f8e40c..ef4271523e 100644 --- a/src/untrusted/irt/irt_interfaces.h +++ b/src/untrusted/irt/irt_interfaces.h @@ -15,8 +15,6 @@ extern const struct nacl_irt_dev_fdio nacl_irt_dev_fdio; extern const struct nacl_irt_filename nacl_irt_filename; extern const struct nacl_irt_dev_filename_v0_2 nacl_irt_dev_filename_v0_2; extern const struct nacl_irt_dev_filename nacl_irt_dev_filename; -extern const struct nacl_irt_memory_v0_1 nacl_irt_memory_v0_1; -extern const struct nacl_irt_memory_v0_2 nacl_irt_memory_v0_2; extern const struct nacl_irt_memory nacl_irt_memory; extern const struct nacl_irt_dyncode nacl_irt_dyncode; extern const struct nacl_irt_thread nacl_irt_thread; diff --git a/src/untrusted/irt/irt_memory.c b/src/untrusted/irt/irt_memory.c index b3c1a3bef7..aba91f7c64 100644 --- a/src/untrusted/irt/irt_memory.c +++ b/src/untrusted/irt/irt_memory.c @@ -13,27 +13,6 @@ #include "native_client/src/untrusted/irt/irt_private.h" #include "native_client/src/untrusted/nacl/syscall_bindings_trampoline.h" -static int nacl_irt_sysbrk(void **newbrk) { - /* - * The syscall does not actually indicate error. It just returns the - * new current value, which is unchanged if something went wrong. - * But if the requested value was below the end of the data segment, - * the new value will be greater, but this is not "going wrong". - * Here we just approximate a saner interface: you get what you requested, - * you did a "probe" request passing NULL in, or it's an error. - * TODO(mcgrathr): this interface should just go away!! - */ - void *requested = *newbrk; - void *got = NACL_SYSCALL(brk)(requested); - - if (got == requested || requested == NULL) { - *newbrk = got; - return 0; - } - - return ENOMEM; -} - static int nacl_irt_mmap(void **addr, size_t len, int prot, int flags, int fd, off_t off) { /* @@ -85,15 +64,6 @@ static int nacl_irt_mmap(void **addr, size_t len, return 0; } -/* - * mmap from nacl-irt-memory-0.1 interface should ignore PROT_EXEC bit for - * backward-compatibility reasons. - */ -static int nacl_irt_mmap_v0_1(void **addr, size_t len, - int prot, int flags, int fd, off_t off) { - return nacl_irt_mmap(addr, len, prot & ~PROT_EXEC, flags, fd, off); -} - static int nacl_irt_munmap(void *addr, size_t len) { return -NACL_SYSCALL(munmap)(addr, len); } @@ -102,19 +72,6 @@ static int nacl_irt_mprotect(void *addr, size_t len, int prot) { return -NACL_SYSCALL(mprotect)(addr, len, prot); } -const struct nacl_irt_memory_v0_1 nacl_irt_memory_v0_1 = { - nacl_irt_sysbrk, - nacl_irt_mmap_v0_1, - nacl_irt_munmap, -}; - -const struct nacl_irt_memory_v0_2 nacl_irt_memory_v0_2 = { - nacl_irt_sysbrk, - nacl_irt_mmap, - nacl_irt_munmap, - nacl_irt_mprotect, -}; - const struct nacl_irt_memory nacl_irt_memory = { nacl_irt_mmap, nacl_irt_munmap, diff --git a/src/untrusted/nacl/nacl_irt_init.c b/src/untrusted/nacl/nacl_irt_init.c index f0f02c52a7..d085b28421 100644 --- a/src/untrusted/nacl/nacl_irt_init.c +++ b/src/untrusted/nacl/nacl_irt_init.c @@ -8,10 +8,6 @@ #include "native_client/src/include/elf32.h" #include "native_client/src/untrusted/nacl/nacl_irt.h" -static int __libnacl_irt_mprotect(void *addr, size_t len, int prot) { - return ENOSYS; -} - /* * Scan the auxv for AT_SYSINFO, which is the pointer to the IRT query function. * Stash that for later use. @@ -51,24 +47,6 @@ void __libnacl_irt_init(Elf32_auxv_t *auxv) { } DO_QUERY(NACL_IRT_BASIC_v0_1, basic); - - if (!__libnacl_irt_query(NACL_IRT_MEMORY_v0_3, - &__libnacl_irt_memory, - sizeof(__libnacl_irt_memory))) { - /* Fall back to trying the old version, before sysbrk() was removed. */ - struct nacl_irt_memory_v0_2 old_irt_memory; - if (!__libnacl_irt_query(NACL_IRT_MEMORY_v0_2, - &old_irt_memory, - sizeof(old_irt_memory))) { - /* Fall back to trying an older version, before mprotect() was added. */ - __libnacl_mandatory_irt_query(NACL_IRT_MEMORY_v0_1, - &old_irt_memory, - sizeof(struct nacl_irt_memory_v0_1)); - __libnacl_irt_memory.mprotect = __libnacl_irt_mprotect; - } - __libnacl_irt_memory.mmap = old_irt_memory.mmap; - __libnacl_irt_memory.munmap = old_irt_memory.munmap; - } - + DO_QUERY(NACL_IRT_MEMORY_v0_3, memory); DO_QUERY(NACL_IRT_TLS_v0_1, tls); } diff --git a/src/untrusted/nacl/tls.h b/src/untrusted/nacl/tls.h index 8787ecf068..e88373e272 100644 --- a/src/untrusted/nacl/tls.h +++ b/src/untrusted/nacl/tls.h @@ -12,7 +12,7 @@ void __pthread_initialize(void); /* - * Allocates (using sbrk) and initializes the combined area for the + * Allocates and initializes the combined area for the * main thread. Always called, whether or not pthreads is in use. */ void __pthread_initialize_minimal(size_t tdb_size); diff --git a/tests/app_lib/.gitattributes b/tests/app_lib/.gitattributes new file mode 100644 index 0000000000..b2e75b19cf --- /dev/null +++ b/tests/app_lib/.gitattributes @@ -0,0 +1,2 @@ +app_lib_test.stdin eol=lf +app_lib_test.stdout eol=lf diff --git a/tests/gdb/gdb_test.py b/tests/gdb/gdb_test.py index e2f98a9da6..0a2425c79a 100644 --- a/tests/gdb/gdb_test.py +++ b/tests/gdb/gdb_test.py @@ -3,6 +3,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import atexit import json import optparse import os @@ -205,6 +206,7 @@ def __init__(self, options, name): self._gdb = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + atexit.register(self.KillProcess) self._expected_success = True def Wait(self): @@ -289,6 +291,7 @@ def Kill(self): def KillProcess(self): self._expected_success = False KillProcess(self._gdb) + atexit.unregister(self.KillProcess) def Eval(self, expression): return self.Command('-data-evaluate-expression ' + expression)[b'value'] diff --git a/tests/gdb/nacl.scons b/tests/gdb/nacl.scons index 2ef028f0f8..7919ea7b93 100644 --- a/tests/gdb/nacl.scons +++ b/tests/gdb/nacl.scons @@ -17,24 +17,6 @@ if env.UnderWindowsCoverage(): if 'nacl_gdb' in SCons.Script.ARGUMENTS: env.Replace(GDB=SCons.Script.ARGUMENTS['nacl_gdb']) -elif env.Bit('build_arm') or env.Bit('build_mips32'): - if env.UsingEmulator(): - # nacl-gdb is built with ARM support but not MIPS support. - if env.Bit('build_mips32'): - Return() - nacl_x86_toolchain_dir = env.GetToolchainDir(target_arch='x86', - is_pnacl=False, - lib_name='glibc') - nacl_gdb_path = os.path.join(nacl_x86_toolchain_dir, 'bin', 'i686-nacl-gdb') - env.Replace(GDB=nacl_gdb_path) - else: - # Use the system's ARM/MIPS GDB because the NaCl toolchain does not - # include a copy of GDB built to run on ARM/MIPS. - env.Replace(GDB='gdb') - # Unlike nacl-gdb, the system version of GDB does not support the - # "nacl-irt" command. - if env.Bit('tests_use_irt'): - Return() # Disable finalization (which would strip debug metadata), but allow # the sandbox translator where it makes sense. @@ -123,6 +105,10 @@ def AddGdbTest(name, is_broken=False, is_thread_test=False): # is created after continuing (https://github.com/DaemonEngine/native_client/issues/57). no_step = env.Bit('build_arm') or env.Bit('build_mips32') +# Currently GDB builds lack XML support which is needed for some ARM register +# info - see https://github.com/DaemonEngine/saigo-nacl-sdk/issues/9 +no_xml = env.Bit('build_arm') and env.Bit('saigo') + AddGdbTest('complete') AddGdbTest('detach') @@ -133,7 +119,7 @@ using_clang = env.Bit('bitcode') or (env.Bit('nacl_clang') and not env.Bit('saig # https://code.google.com/p/nativeclient/issues/detail?id=4059 AddGdbTest('invalid_memory', - is_broken = (using_clang and not env.UsingEmulator())) + is_broken = no_xml or (using_clang and not env.UsingEmulator())) AddGdbTest('kill') AddGdbTest('remote_get') @@ -147,7 +133,7 @@ AddGdbTest('print_symbol', is_broken=no_step) # TODO(mseaborn): Investigate and enable this test. # http://code.google.com/p/nativeclient/issues/detail?id=3252 AddGdbTest('stack_trace', - is_broken=using_clang and env.Bit('build_arm')) + is_broken=no_xml or (using_clang and env.Bit('build_arm'))) AddGdbTest('step_from_func_start', is_broken=no_step) diff --git a/tests/gdb/stack_trace.py b/tests/gdb/stack_trace.py index a56144f414..fdeb9fe3fe 100644 --- a/tests/gdb/stack_trace.py +++ b/tests/gdb/stack_trace.py @@ -19,8 +19,11 @@ def test_stack_trace(self): result = self.gdb.Command('-stack-list-arguments 1 0 1') self.assertEqual(result[b'stack-args'][0][b'frame'][b'args'][0][b'value'], b'2') - self.assertEqual(result[b'stack-args'][1][b'frame'][b'args'][0][b'value'], - b'1') + # This stopped working somewhere between llvm commits + # ecea8371ff03c15fb3dc27ee4108b98335fd2d63 and + # 1d5d18924d185a4267462479307f1ff9911cb112 + #self.assertEqual(result[b'stack-args'][1][b'frame'][b'args'][0][b'value'], + # b'1') self.gdb.Command('return') self.gdb.ResumeAndExpectStop('finish', 'function-finished') self.assertEqual(self.gdb.Eval('global_var'), b'1') diff --git a/tests/irt/irt_interface_prefix_test.c b/tests/irt/irt_interface_prefix_test.c deleted file mode 100644 index 5d9fccc01b..0000000000 --- a/tests/irt/irt_interface_prefix_test.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2013 The Native Client Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "native_client/src/untrusted/irt/irt.h" - -const size_t k64Kbytes = 64 * 1024; -const int kAnonymousFiledesc = -1; - -/* - * Check that the old version of the memory interface is - * a prefix of the new version. - */ -void test_memory_interface_prefix(void) { - struct nacl_irt_memory_v0_1 m1; - struct nacl_irt_memory_v0_2 m2; - struct nacl_irt_memory m3; - void *addr; - int rc; - - rc = nacl_interface_query(NACL_IRT_MEMORY_v0_1, &m1, sizeof m1); - assert(rc == sizeof m1); - - rc = nacl_interface_query(NACL_IRT_MEMORY_v0_2, &m2, sizeof m2); - assert(rc == sizeof m2); - - rc = nacl_interface_query(NACL_IRT_MEMORY_v0_3, &m3, sizeof m3); - assert(rc == sizeof m3); - - /* Verify that v0.1 mmap ignores PROT_EXEC */ - addr = 0; - rc = m1.mmap(&addr, - k64Kbytes, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, - kAnonymousFiledesc, - 0); - /* Return value is actually new address and not a negative return code. */ - assert(0xffff0000u > (uint32_t)rc); - - - /* Verify that v0.2 mmap does not ignore PROT_EXEC */ - addr = 0; - rc = m2.mmap(&addr, - k64Kbytes, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, - kAnonymousFiledesc, - 0); - assert(rc = -EINVAL); - - /* mmap is different, everything else should be the same. */ - m1.mmap = m2.mmap; - assert(memcmp(&m1, &m2, sizeof m1) == 0); - - /* v0.3 is the same as v0.2, but with the deprecated sysbrk() removed. */ - assert(m3.mmap == m2.mmap); - assert(m3.munmap == m2.munmap); - assert(m3.mprotect == m2.mprotect); -} - -int main(void) { - test_memory_interface_prefix(); - - return 0; -} diff --git a/tests/irt/nacl.scons b/tests/irt/nacl.scons index 908ca1763e..a323a0fbd0 100644 --- a/tests/irt/nacl.scons +++ b/tests/irt/nacl.scons @@ -20,20 +20,6 @@ node = env.CommandSelLdrTestNacl( env.AddNodeToTestSuite(node, ['small_tests'], 'run_irt_present_test') -# IRT interface prefix test - -nexe = env.ComponentProgram('irt_interface_prefix_test', - 'irt_interface_prefix_test.c', - EXTRA_LIBS=['${NONIRT_LIBS}'], - ) - -node = env.CommandSelLdrTestNacl( - 'irt_interface_prefix_test.out', - nexe, - ) - -env.AddNodeToTestSuite(node, ['small_tests'], 'run_irt_interface_prefix_test') - # IRT interface dev test interface_dev_test_nexe = env.ComponentProgram('irt_interface_dev_test', diff --git a/tests/irt_compatibility/irt_comp_interfaces.c b/tests/irt_compatibility/irt_comp_interfaces.c deleted file mode 100644 index a80e087e86..0000000000 --- a/tests/irt_compatibility/irt_comp_interfaces.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2013 The Native Client Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include - -#include "native_client/src/include/nacl_macros.h" -#include "native_client/src/untrusted/irt/irt.h" -#include "native_client/src/untrusted/irt/irt_interfaces.h" - -struct nacl_interface_table { - const char *name; - const void *table; - size_t size; -}; - -static const struct nacl_interface_table irt_interfaces[] = { - /* - * We expect current NaCl programs to be able to work with this - * minimal set of IRT interface versions. Some of these are old - * interface versions. - */ - { NACL_IRT_BASIC_v0_1, &nacl_irt_basic, sizeof(nacl_irt_basic) }, - { NACL_IRT_MEMORY_v0_1, &nacl_irt_memory_v0_1, sizeof(nacl_irt_memory_v0_1) }, - { NACL_IRT_TLS_v0_1, &nacl_irt_tls, sizeof(nacl_irt_tls) }, -#if ALLOW_DYNAMIC_LINKING - { NACL_IRT_FILENAME_v0_1, &nacl_irt_filename, sizeof(nacl_irt_filename) }, - { NACL_IRT_DYNCODE_v0_1, &nacl_irt_dyncode, sizeof(nacl_irt_dyncode) }, -#endif - /* - * Nexes should not necessarily require "fdio" at startup, but its - * presence is necessary for hello_world to produce output and so - * for the hello_world test to pass. - */ - { NACL_IRT_FDIO_v0_1, &nacl_irt_fdio, sizeof(nacl_irt_fdio) }, -}; - -size_t nacl_irt_query_core(const char *interface_ident, - void *table, size_t tablesize) { - int i; - for (i = 0; i < NACL_ARRAY_SIZE(irt_interfaces); ++i) { - if (0 == strcmp(interface_ident, irt_interfaces[i].name)) { - const size_t size = irt_interfaces[i].size; - if (size <= tablesize) { - memcpy(table, irt_interfaces[i].table, size); - return size; - } - break; - } - } - return 0; -} diff --git a/tests/irt_compatibility/nacl.scons b/tests/irt_compatibility/nacl.scons deleted file mode 100644 index 32846a13db..0000000000 --- a/tests/irt_compatibility/nacl.scons +++ /dev/null @@ -1,45 +0,0 @@ -# -*- python -*- -# Copyright (c) 2013 The Native Client 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('env') - -# IRT backward compatibility test - -# This test uses a nexe built by another test. Nexes do not get -# staged in pexe mode, so only run this test in nonpexe mode. -if env.Bit('pnacl_generate_pexe'): - Return() - -# The new glibc requires some newer IRT interfaces. -if env.Bit('nacl_glibc') and not env.Bit('build_x86'): - Return() - -blob_env = env['NACL_IRT_ENV'].Clone() -blob_env.Append(LINKFLAGS=['-Wl,-Trodata-segment=${IRT_BLOB_DATA_START}', - '-Wl,-Ttext-segment=${IRT_BLOB_CODE_START}']) - -# Build custom IRT library which provides a minimal subset of old -# interface versions. -blob_env.Append(CPPDEFINES=[['ALLOW_DYNAMIC_LINKING', - str(int(not env.Bit('nacl_static_link')))]]) -irt_comp_test_raw_library = blob_env.ComponentProgram( - 'irt_comp_test_raw', ['irt_comp_interfaces.c'], - EXTRA_LIBS=['irt_support_private']) - -irt_comp_test_library = env.ApplyTLSEdit( - 'irt_comp_test', - irt_comp_test_raw_library) - -# Don't provide IRT, we provide it ourselves via -B. -env.ClearBits('tests_use_irt') - -node = env.CommandSelLdrTestNacl( - 'irt_compatibility_test.out', - env.File('${STAGING_DIR}/hello_world.nexe'), - sel_ldr_flags=['-B', irt_comp_test_library], - stdout_golden=env.File('../hello_world/hello_world.stdout')) - -env.AddNodeToTestSuite(node, ['small_tests', 'nonpexe_tests'], - 'run_irt_compatibility_test') diff --git a/tests/sbrk/nacl.scons b/tests/sbrk/nacl.scons deleted file mode 100644 index 500d168f21..0000000000 --- a/tests/sbrk/nacl.scons +++ /dev/null @@ -1,18 +0,0 @@ -# -*- python -*- -# Copyright (c) 2011 The Native Client 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('env') - -sbrk_nexe = env.ComponentProgram('sbrk_test', - ['sbrk_test.c'], - EXTRA_LIBS=['${NONIRT_LIBS}']) - -node = env.CommandSelLdrTestNacl( - 'sbrk_test.out', - sbrk_nexe, - ) -env.AddNodeToTestSuite(node, - ['small_tests', 'sel_ldr_tests'], - 'run_sbrk_test') diff --git a/tests/sbrk/sbrk_test.c b/tests/sbrk/sbrk_test.c deleted file mode 100644 index cc89331f7d..0000000000 --- a/tests/sbrk/sbrk_test.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2011 The Native Client Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include -#include -#include -#include -#include - -#include "native_client/src/include/nacl_assert.h" -#include "native_client/src/untrusted/irt/irt.h" - -/* - * This test checks that memory allocated via sysbrk() is zeroed, even - * if it was previously allocated and deallocated. - * See http://code.google.com/p/nativeclient/issues/detail?id=2417 - * - * sysbrk() is deprecated, so we test the IRT interface directly - * rather than testing any libc wrappers for it. - */ - -static struct nacl_irt_memory_v0_2 irt_memory; - -static void *get_break(void) { - void *addr = NULL; - int rc = irt_memory.sysbrk(&addr); - ASSERT_EQ(rc, 0); - ASSERT_NE(addr, NULL); - return addr; -} - -static void set_break(void *new_addr) { - void *addr_copy = new_addr; - int rc = irt_memory.sysbrk(&addr_copy); - ASSERT_EQ(rc, 0); - /* Check that sysbrk() does not modify the value in the success case. */ - ASSERT_EQ(addr_copy, new_addr); -} - -#define NUM_WORDS 512 - -int main(void) { - size_t ix; - int status; - - size_t query_result = nacl_interface_query(NACL_IRT_MEMORY_v0_2, - &irt_memory, sizeof(irt_memory)); - ASSERT_EQ(query_result, sizeof(irt_memory)); - - /* Find the current break pointer. */ - int *alloc_start = get_break(); - fprintf(stderr, "initial break is at %p\n", (void *) alloc_start); - - /* We expect that the initial break pointer is word-aligned. */ - ASSERT_EQ((uintptr_t) alloc_start & 3, 0); - - /* Allocate some memory and fill it with data. */ - void *alloc_end = alloc_start + NUM_WORDS; - set_break(alloc_end); - for (ix = 0; ix < NUM_WORDS; ++ix) { - alloc_start[ix] = 0xdeadbeef; - } - /* Deallocate the memory. */ - set_break(alloc_start); - /* Allocate the memory again. The contents should have been zeroed. */ - set_break(alloc_end); - status = 0; - for (ix = 0; ix < NUM_WORDS; ++ix) { - if (0 != alloc_start[ix]) { - fprintf(stderr, "new memory word at %zd contains 0x%04x\n", - ix, alloc_start[ix]); - status = 3; - } - } - return status; -} diff --git a/tests/sysbasic/sysbasic.c b/tests/sysbasic/sysbasic.c index 1c66b77650..216f9f70ff 100644 --- a/tests/sysbasic/sysbasic.c +++ b/tests/sysbasic/sysbasic.c @@ -121,7 +121,7 @@ int main(void) { myprint("\nsysbrk()\n"); i = (int) sysbrk((void *) sysbrkBase); PrintInt(i); - if (sysbrkBase != i) Error("bad sysbrk() value\n"); + if (i != -ENOSYS) Error("sysbrk() didn't return failure value\n"); myprint("\nmmap()\n"); i = (int) mmap(0, kMmapSize, diff --git a/tests/syscalls/nacl.scons b/tests/syscalls/nacl.scons index a897970174..d565debbb9 100644 --- a/tests/syscalls/nacl.scons +++ b/tests/syscalls/nacl.scons @@ -163,24 +163,6 @@ env.AddNodeToTestSuite(node, ['small_tests', 'sel_ldr_tests'], 'run_mem_test') -nonstable_env = env.Clone() -if nonstable_env.SetNonStableBitcodeIfAllowed(): - if nonstable_env.Bit('bitcode'): - # sysbrk_test.cc has an external reference to "end", a symbol - # defined by the native linker, which is disallowed by PNaCl's - # ABI. - nonstable_env.Append(LINKFLAGS=['--pnacl-disable-abi-check']) - sysbrk_test_nexe = nonstable_env.ComponentProgram( - 'sysbrk_test', ['sysbrk_test.cc'], - EXTRA_LIBS=['syscall_test_framework', - '${NONIRT_LIBS}', - 'nacl_sys_private']) - node = nonstable_env.CommandSelLdrTestNacl('sysbrk_test.out', - sysbrk_test_nexe) - nonstable_env.AddNodeToTestSuite(node, - ['small_tests', 'sel_ldr_tests'], - 'run_sysbrk_test') - # additions to add syscall tests 40-42 timefuncs_test_nexe = env.ComponentProgram( 'timefuncs_test', diff --git a/tests/syscalls/sysbrk_test.cc b/tests/syscalls/sysbrk_test.cc deleted file mode 100644 index 272c1a34e6..0000000000 --- a/tests/syscalls/sysbrk_test.cc +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2011 The Native Client Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// These tests exercise NaCl's sysbrk() system call. - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "native_client/src/trusted/service_runtime/include/sys/nacl_syscalls.h" -#include "native_client/tests/syscalls/test.h" - -/* - * This is defined by the linker as the address of the end of our data segment. - * That's where the break starts out by default. - */ -extern "C" { - extern char end; -} - -namespace { -// Note: these parameters to sysbrk are not supposed to be const. - -// The defined error return address. -void* kSysbrkErrorAddress = reinterpret_cast(-1); - -// This is an address outside of the 1Gb address range allowed for NaCl -// modules. -void* kIllegalBreakAddress = reinterpret_cast(~0U); - -// Make sure the current break address is non-0 when using sysbrk(). -int TestCurrentBreakAddr() { - START_TEST("TestCurrentBreakAddr"); - - // Clear errno incase a previous function set it. - errno = 0; - - void* break_addr = sysbrk(NULL); - EXPECT(NULL != break_addr); - EXPECT(kSysbrkErrorAddress != break_addr); - EXPECT(0 == errno); - END_TEST(); -} - - -// Try to reset the program's break address to a legitimate value. -int TestSysbrk() { - // Round up to the end of the page that's our last initial data page. - // Then add 10MB for good measure to be out of the way of any allocations - // that might have been done before we got here. - void* const sysbrkBase = reinterpret_cast - (((reinterpret_cast(&end) + 0xffff) & -0x10000) + (10 << 20)); - - START_TEST("TestSysbrk"); - - // Clear errno incase a previous function set it. - errno = 0; - - void* break_addr = sysbrk(sysbrkBase); - EXPECT(NULL != break_addr); - EXPECT(kSysbrkErrorAddress != break_addr); - EXPECT(sysbrkBase == break_addr); - EXPECT(0 == errno); - END_TEST(); -} - - -// Try to reset the program's break address to something illegal using sysbrk(). -// When sysbrk() fails, it is supposed to return the old break address and set -// |errno| "to an appropriate value" (in this case, EINVAL). -int TestIllegalSysbrk() { - START_TEST("TestIllegalSysbrk"); - - // Clear errno incase a previous function set it. - errno = 0; - - void* current_break = sysbrk(NULL); - void* break_addr = sysbrk(kIllegalBreakAddress); - /* sysbrk does not touch errno, only the sbrk wrapper would */ - EXPECT(0 == errno); - EXPECT(NULL != break_addr); - EXPECT(current_break == break_addr); - END_TEST(); -} -} // namespace - -// Run through the complete sequence of sysbrk tests. Sets the exit code to -// the number of failed tests. Exit code 0 means all passed. -int main() { - int fail_count = 0; - fail_count += TestCurrentBreakAddr(); - fail_count += TestSysbrk(); - fail_count += TestIllegalSysbrk(); - return fail_count; -} diff --git a/tests/thread_suspension/suspend_test_host.c b/tests/thread_suspension/suspend_test_host.c index 73634955db..39c65ebacb 100644 --- a/tests/thread_suspension/suspend_test_host.c +++ b/tests/thread_suspension/suspend_test_host.c @@ -439,6 +439,8 @@ static void TestGettingRegisterSnapshotInSyscallContextSwitch( struct NaClAppThread *natp; struct NaClSignalContext regs; int iteration; + int inside = 0; + int outside = 0; g_simple_syscall_should_exit = 0; g_simple_syscall_called = 0; @@ -460,15 +462,28 @@ static void TestGettingRegisterSnapshotInSyscallContextSwitch( * otherwise there is a small set of instructions that untrusted * code executes. */ - if (!NaClAppThreadIsSuspendedInSyscall(natp)) { + if (NaClAppThreadIsSuspendedInSyscall(natp)) { + ++inside; + } else { regs.prog_ctr = test_shm->expected_regs.prog_ctr; +#if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64 + /* + * The compiler turns the call to the trampoline into push rip + * followed by jump, so there are two possible values for the stack + * pointer in untrusted code. + */ + regs.stack_ptr = test_shm->expected_regs.stack_ptr; +#endif RegsUnsetNonCalleeSavedRegisters(®s); + ++outside; } RegsAssertEqual(®s, &test_shm->expected_regs); NaClUntrustedThreadsResumeAll(nap); } + printf("Suspended outside syscall %dx, inside syscall %dx\n", outside, inside); + g_simple_syscall_should_exit = 1; WaitForThreadToExitFully(nap); } diff --git a/tests/threads/nacl.scons b/tests/threads/nacl.scons index 69ffc2dec1..b002ece53a 100644 --- a/tests/threads/nacl.scons +++ b/tests/threads/nacl.scons @@ -41,6 +41,7 @@ node = env.CommandSelLdrTestNacl( # NOTE: this should be a pretty slow test, but its been sped up # to not tickle bug 853 env.AddNodeToTestSuite(node, ['small_tests'], 'run_thread_test', + is_flaky=env.UsingEmulator(), # TODO(khim): reenable it when cause of failure on 32bit Windows glibc # will be found. # See: http://code.google.com/p/nativeclient/issues/detail?id=1690 diff --git a/tests/toolchain/nacl.scons b/tests/toolchain/nacl.scons index a098fbd170..9dedce5694 100644 --- a/tests/toolchain/nacl.scons +++ b/tests/toolchain/nacl.scons @@ -515,6 +515,7 @@ if not env.Bit('pnacl_generate_pexe'): # Test that both the layout and the nops are not munged by stripping. stripped_nexe = asm_env.Command('strip_test.nexe', nexe, '${STRIP} -o ${TARGET} ${SOURCES}') + asm_env.Alias('all_programs', stripped_nexe) node = asm_env.CommandSelLdrTestNacl('strip_test.out', stripped_nexe) asm_env.AddNodeToTestSuite(node, testsuite, 'run_strip_test') diff --git a/tools/test_lib.py b/tools/test_lib.py index 23739369d9..5e35504b4e 100755 --- a/tools/test_lib.py +++ b/tools/test_lib.py @@ -115,29 +115,27 @@ def CommunicateWithTimeout(proc, input_data=None, timeout=None): if timeout == 0: timeout = None - result = [] - def Target(): - result.append(list(proc.communicate(input_data))) - - thread = threading.Thread(target=Target) - thread.start() - thread.join(timeout) - if thread.is_alive(): + try: + out, err = proc.communicate(input_data, timeout) + except subprocess.TimeoutExpired: sys.stderr.write('\nAttempting to kill test due to timeout!\n') - # This will kill the process which should force communicate to return with - # any partial output. - pynacl.platform.KillSubprocessAndChildren(proc) - # Thus result should ALWAYS contain something after this join. - thread.join() + try: + if pynacl.platform.IsWindows(): + raise # Skip to the kill all part + proc.send_signal(signal.SIGINT) + out, err = result = proc.communicate(timeout=3) + except subprocess.TimeoutExpired: + sys.stderr.write('\nForcibly killing test due to timeout!\n') + pynacl.platform.KillSubprocessAndChildren(proc) + out, err = proc.communicate() msg = '\n\nKilled test due to timeout!\n' sys.stderr.write(msg) # Also append to stderr. - result[0][1] += (msg.encode('ascii') if isinstance(result[0][1], bytes) else msg) + err += (msg.encode('ascii') if isinstance(err, bytes) else msg) returncode = -9 else: returncode = proc.returncode - assert len(result) == 1 - return tuple(result[0]) + (returncode,) + return out, err, returncode def RunTestWithInput(cmd, input_data, timeout=None):