예제 #1
0
 def parse_return_code(cls, proc, executor, point_value, time_limit,
                       memory_limit, feedback, name, stderr):
     if proc.returncode == cls.AC:
         return CheckerResult(True, point_value, feedback=feedback)
     elif proc.returncode == cls.PARTIAL:
         match = cls.repartial.search(stderr)
         if not match:
             raise InternalError('Invalid stderr for partial points: %r' %
                                 stderr)
         points = int(match.group(1))
         if not 0 <= points <= point_value:
             raise InternalError('Invalid partial points: %d' % points)
         return CheckerResult(True, points, feedback=feedback)
     elif proc.returncode == cls.WA:
         return CheckerResult(False, 0, feedback=feedback)
     elif proc.returncode == cls.PE:
         return CheckerResult(False,
                              0,
                              feedback=feedback or 'Presentation Error')
     elif proc.returncode == cls.IE:
         raise InternalError('%s failed assertion with message %s' %
                             (name, feedback))
     else:
         parse_helper_file_error(proc, executor, name, stderr, time_limit,
                                 memory_limit)
예제 #2
0
def check(process_output: bytes,
          judge_output: bytes,
          point_value: float = 1,
          point_distribution: List[int] = [1],
          filler_lines_required: bool = True,
          **kwargs) -> Union[CheckerResult, bool]:
    judge_lines = list(
        filter(None, resplit(b'[\r\n]', utf8bytes(judge_output))))

    if len(judge_lines) != len(point_distribution):
        raise InternalError(
            'point distribution length must equal to judge output length')

    if sum(point_distribution) == 0:
        raise InternalError('sum of point distribution must be positive')

    process_lines = list(
        filter(None, resplit(b'[\r\n]', utf8bytes(process_output))))

    if filler_lines_required and len(process_lines) != len(judge_lines):
        return False

    points = 0
    for process_line, judge_line, line_points in zip(process_lines,
                                                     judge_lines,
                                                     point_distribution):
        if process_line == judge_line:
            points += line_points

    return CheckerResult(points > 0,
                         point_value * (points / sum(point_distribution)))
예제 #3
0
    def _run_generator(self, gen, args=None):
        flags = []
        args = args or []

        # resource limits on how to run the generator
        time_limit = env.generator_time_limit
        memory_limit = env.generator_memory_limit
        use_sandbox = env.generator_sandboxing

        base = get_problem_root(self.problem.id)
        if isinstance(gen, six.string_types):
            filename = os.path.join(base, gen)
        else:
            filename = os.path.join(base, gen.source)
            if gen.flags:
                flags += gen.flags
            if not args and gen.args:
                args += gen.args

            time_limit = gen.time_limit or time_limit
            memory_limit = gen.memory_limit or memory_limit

            # Optionally allow disabling the sandbox
            if gen.use_sandbox is not None:
                use_sandbox = gen.use_sandbox

        executor = self.problem.generator_manager.get_generator(filename, flags)

        # convert all args to str before launching; allows for smoother int passing
        args = map(str, args)

        # we allow both "trusted" and "untrusted" generators, for different scenarios:
        # e.g., an untrusted generator may be one generated via site-managed data by an
        # arbitrary user, who shouldn't be allowed to do arbitrary things on the host machine
        if use_sandbox:
            # setting large buffers is really important, because otherwise stderr is unbuffered
            # and the generator begins calling into cptbox Python code really frequently
            proc = executor.launch(*args, time=time_limit, memory=memory_limit, pipe_stderr=True,
                                   stderr_buffer_size=65536, stdout_buffer_size=65536)
        else:
            proc = executor.launch_unsafe(*args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                                          stderr=subprocess.PIPE)

        try:
            input = self.problem.problem_data[self.config['in']] if self.config['in'] else None
        except KeyError:
            input = None
        self._generated = list(map(self._normalize, proc.communicate(input)))

        if hasattr(proc, 'tle') and proc.tle:
            raise InternalError('generator timed out (> %s seconds)' % time_limit)
        if hasattr(proc, 'mle') and proc.mle:
            raise InternalError('generator ran out of memory (> %s Kb)' % memory_limit)
        if hasattr(proc, 'protection_fault') and proc.protection_fault:
            syscall, callname, args = proc.protection_fault
            raise InternalError('generator invoked disallowed syscall %s (%s)' % (syscall, callname))
        if proc.returncode:
            raise InternalError('generator exited with nonzero code: %s' % proc.returncode)
예제 #4
0
def get_executor(checker_kwargs, problem_id):
    global executor

    if executor is None:
        if 'files' not in checker_kwargs:
            raise InternalError('no checker file(s) specified!')
        if 'lang' not in checker_kwargs:
            raise InternalError('language not specified for checker!')

        filenames = list(map(lambda x: os.path.join(get_problem_root(problem_id), x), checker_kwargs['files']))
        lang = checker_kwargs['lang']
        executor = compile_with_auxiliary_files(filenames, lang, checker_kwargs['compiler_time_limit'])

    return executor
예제 #5
0
    def parse_feedback_from_stderr(self, stderr: bytes,
                                   process: TracedPopen) -> str:
        if process.returncode:
            assert self._dir is not None
            try:
                with open(os.path.join(self._dir, 'submission_jvm_crash.log'),
                          'r') as err:
                    log = err.read()
                    # "Newer" (post-Java 8) JVMs regressed a bit in terms of handling out-of-memory situations during
                    # initialization, whereby they now dump a crash log rather than exiting with
                    # java.lang.OutOfMemoryError. Handle this case so that we don't erroneously emit internal errors.
                    if 'There is insufficient memory for the Java Runtime' in log:
                        return 'insufficient memory to initialize JVM'
                    else:
                        raise InternalError('\n\n' + log)
            except IOError:
                pass

        if b'Error: Main method not found in class' in stderr:
            exception = 'public static void main(String[] args) not found'
        else:
            match = deque(reexception.finditer(utf8text(stderr, 'replace')),
                          maxlen=1)
            if not match:
                exception = 'abnormal termination'  # Probably exited without calling shutdown hooks
            else:
                exception = match[0].group(1).split(':')[0]

        return exception
예제 #6
0
    def _protection_fault(self, syscall):
        # When signed, 0xFFFFFFFF is equal to -1, meaning that ptrace failed to read the syscall for some reason.
        # We can't continue debugging as this could potentially be unsafe, so we should exit loudly.
        # See <https://github.com/DMOJ/judge/issues/181> for more details.
        if syscall == 0xFFFFFFFF:
            raise InternalError('ptrace failed')
            # TODO: this would be more useful if we had access to a proper errno
            # import errno, os
            # err = ...
            # raise InternalError('ptrace error: %d (%s: %s)' % (err, errno.errorcode[err], os.strerror(err)))
        else:
            callname = 'unknown'
            index = self._syscall_index
            for id, call in enumerate(translator):
                if call[index] == syscall:
                    callname = by_id[id]
                    break

            print >> sys.stderr, 'Protection fault on: %d (%s)' % (syscall,
                                                                   callname)
            print >> sys.stderr, 'Arg0: 0x%016x' % self.debugger.uarg0
            print >> sys.stderr, 'Arg1: 0x%016x' % self.debugger.uarg1
            print >> sys.stderr, 'Arg2: 0x%016x' % self.debugger.uarg2
            print >> sys.stderr, 'Arg3: 0x%016x' % self.debugger.uarg3
            print >> sys.stderr, 'Arg4: 0x%016x' % self.debugger.uarg4
            print >> sys.stderr, 'Arg5: 0x%016x' % self.debugger.uarg5

            self.protection_fault = (syscall, callname)
예제 #7
0
 def parse_return_code(cls, proc, executor, point_value, time_limit,
                       memory_limit, feedback, name, stderr):
     if proc.returncode == cls.PARTIAL:
         match = cls.repartial.search(stderr)
         if not match:
             raise InternalError(
                 'Invalid stderr for fraction of points: %r' % stderr)
         percentage = int(match.group(2)) / int(match.group(3))
         if not 0.0 <= percentage <= 1.0:
             raise InternalError('Invalid fraction: %s' % match.group(1))
         points = percentage * point_value
         return CheckerResult(True, points, feedback=feedback)
     else:
         return super().parse_return_code(proc, executor, point_value,
                                          time_limit, memory_limit,
                                          feedback, name, stderr)
예제 #8
0
파일: sorted.py 프로젝트: uwapcs/DMOJ-judge
def check(process_output, judge_output, split_on='lines', **kwargs):
    split_pattern = {
        'lines': b'[\r\n]',
        'whitespace': b'[\s]',
    }.get(split_on)

    if not split_pattern:
        raise InternalError('invalid `split_on` mode')

    process_lines = list(
        filter(None, resplit(split_pattern, utf8bytes(process_output))))
    judge_lines = list(
        filter(None, resplit(split_pattern, utf8bytes(judge_output))))

    if len(process_lines) != len(judge_lines):
        return False

    if split_on == 'lines':
        process_lines = list(map(six.binary_type.split, process_lines))
        judge_lines = list(map(six.binary_type.split, judge_lines))

    process_lines.sort()
    judge_lines.sort()

    for process_line, judge_line in zip(process_lines, judge_lines):
        if process_line != judge_line:
            return False

    return True
예제 #9
0
    def parse_feedback_from_stderr(self, stderr, process):
        if process.returncode:
            try:
                with open(os.path.join(self._dir, 'submission_jvm_crash.log'),
                          'r') as err:
                    log = err.read()
                    # "Newer" (post-Java 8) JVMs regressed a bit in terms of handling out-of-memory situations during
                    # initialization, whereby they now dump a crash log rather than exiting with
                    # java.lang.OutOfMemoryError. Handle this case so that we don't erroneously emit internal errors.
                    if 'There is insufficient memory for the Java Runtime' in log:
                        return 'insufficient memory to initialize JVM'
                    else:
                        raise InternalError('\n\n' + log)
            except IOError:
                pass

        if b'Error: Main method not found in class' in stderr:
            exception = "public static void main(String[] args) not found"
        else:
            print("AQUEST ES EL STDERR", str(stderr))
            match = deque(reexception.finditer(utf8text(stderr, 'replace')),
                          maxlen=1)
            linea = str(stderr).split(':')[-1].split(')')[0]
            print(linea)
            if not match:
                exception = "El teu codi ha petat sense donar excepció. Això es tecnicament impossible que passi, així que si passa ensenya-li això al Marc i es rascarà el cap mentre diu -Pero això és impossible que passi!- "  # Probably exited without calling shutdown hooks
            elif "AccessControlException" in match[0].group(1).split(':')[0]:
                exception = (
                    "Has intentat hackejar-me. Et sentencio a mort.\n")
            else:
                exception = match[0].group(1).split(
                    ':')[0] + " en línea " + linea

        return exception
예제 #10
0
 def __init__(self, judge, problem, language, source):
     super().__init__(judge, problem, language, source)
     self.handler_data = self.problem.config.interactive
     self.interactor_binary = self._generate_interactor_binary()
     self.contrib_type = self.handler_data.get('type', 'default')
     if self.contrib_type not in contrib_modules:
         raise InternalError('%s is not a valid contrib module' % self.contrib_type)
예제 #11
0
class BridgedInteractiveGrader(StandardGrader):
    def __init__(self, judge, problem, language, source):
        super().__init__(judge, problem, language, source)
        self.handler_data = self.problem.config.interactive
        self.interactor_binary = self._generate_interactor_binary()

    def check_result(self, case, result):
        if result.result_flag:
            # This is usually because of a TLE verdict raised after the interactor
            # has issued the AC verdict
            # This results in a TLE verdict getting full points, which should not be the case
            return False

        stderr = self._interactor.stderr.read()
        return_code = self.handler_data.get('type', 'default')
        if return_code not in contrib_modules:
            raise InternalError('%s is not a valid return code parser' %
                                return_code)

        return contrib_modules[return_code].ContribModule.parse_return_code(
            self._interactor,
            self.interactor_binary,
            case.points,
            self._interactor_time_limit,
            self._interactor_memory_limit,
            feedback=utf8text(stderr) if self.handler_data.feedback else None,
            name='interactor',
            stderr=stderr)
예제 #12
0
    def _generate_binary(self):
        siggraders = ('C', 'C11', 'CPP03', 'CPP11', 'CPP14', 'CPP17', 'CLANG',
                      'CLANGX')

        if self.language in siggraders:
            aux_sources = {}
            handler_data = self.problem.config['signature_grader']

            entry_point = self.problem.problem_data[handler_data['entry']]
            header = self.problem.problem_data[handler_data['header']]

            submission_prefix = '#include "%s"\n' % handler_data['header']
            if not handler_data.get('allow_main', False):
                submission_prefix += '#define main main_%s\n' % uuid.uuid4(
                ).hex

            aux_sources[
                self.problem.id +
                '_submission'] = utf8bytes(submission_prefix) + self.source

            aux_sources[handler_data['header']] = header
            entry = entry_point
            return executors[self.language].Executor(
                self.problem.id,
                entry,
                aux_sources=aux_sources,
                defines=['-DSIGNATURE_GRADER'],
            )
        else:
            raise InternalError(
                'no valid runtime for signature grading %s found' %
                self.language)
예제 #13
0
def compile_with_auxiliary_files(filenames,
                                 flags=[],
                                 lang=None,
                                 compiler_time_limit=None,
                                 should_cache=True):
    from dmoj.executors import executors
    from dmoj.executors.compiled_executor import CompiledExecutor

    sources = {}

    for filename in filenames:
        with open(filename, 'rb') as f:
            sources[os.path.basename(filename)] = f.read()

    def find_runtime(languages):
        for grader in languages:
            if grader in executors:
                return grader
        return None

    use_cpp = any(
        map(lambda name: os.path.splitext(name)[1] in ['.cpp', '.cc'],
            filenames))
    use_c = any(
        map(lambda name: os.path.splitext(name)[1] in ['.c'], filenames))
    if lang is None:
        best_choices = ('CPP20', 'CPP17', 'CPP14', 'CPP11',
                        'CPP03') if use_cpp else ('C11', 'C')
        lang = find_runtime(best_choices)

    executor = executors.get(lang)
    if not executor:
        raise IOError('could not find an appropriate C++ executor')

    executor = executor.Executor

    kwargs = {'fs': executor.fs + [tempfile.gettempdir()]}

    if issubclass(executor, CompiledExecutor):
        kwargs['compiler_time_limit'] = compiler_time_limit

    if hasattr(executor, 'flags'):
        kwargs['flags'] = flags + list(executor.flags)

    # Optimize the common case.
    if use_cpp or use_c:
        # Some auxiliary files (like those using testlib.h) take an extremely long time to compile, so we cache them.
        executor = executor('_aux_file',
                            None,
                            aux_sources=sources,
                            cached=should_cache,
                            **kwargs)
    else:
        if len(sources) > 1:
            raise InternalError(
                'non-C/C++ auxilary programs cannot be multi-file')
        executor = executor('_aux_file', list(sources.values())[0], **kwargs)

    return executor
예제 #14
0
def check(
    process_output,
    judge_output,
    judge_input,
    problem_id,
    files,
    lang,
    time_limit=env['generator_time_limit'],
    memory_limit=env['generator_memory_limit'],
    compiler_time_limit=env['generator_compiler_limit'],
    feedback=True,
    flags=[],
    type='default',
    args_format_string=None,
    point_value=None,
    **kwargs,
) -> CheckerResult:
    executor = get_executor(problem_id, files, flags, lang,
                            compiler_time_limit)

    if type not in contrib_modules:
        raise InternalError('%s is not a valid contrib module' % type)

    args_format_string = args_format_string or contrib_modules[
        type].ContribModule.get_checker_args_format_string()

    with mktemp(judge_input) as input_file, mktemp(
            process_output) as output_file, mktemp(
                judge_output) as answer_file:
        checker_args = shlex.split(
            args_format_string.format(
                input_file=shlex.quote(input_file.name),
                output_file=shlex.quote(output_file.name),
                answer_file=shlex.quote(answer_file.name),
            ))
        process = executor.launch(
            *checker_args,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            memory=memory_limit,
            time=time_limit,
        )

        proc_output, error = process.communicate()
        proc_output = utf8text(proc_output)

        return contrib_modules[type].ContribModule.parse_return_code(
            process,
            executor,
            point_value,
            time_limit,
            memory_limit,
            feedback=utf8text(proc_output) if feedback else '',
            name='checker',
            stderr=error,
        )
예제 #15
0
    def get_generator(self,
                      filenames,
                      flags,
                      lang=None,
                      compiler_time_limit=None):
        from dmoj.executors import executors
        from dmoj.executors.compiled_executor import CompiledExecutor

        filenames = list(map(os.path.abspath, filenames))
        sources = {}

        try:
            for filename in filenames:
                with open(filename, 'rb') as f:
                    sources[os.path.basename(filename)] = f.read()
        except Exception:
            traceback.print_exc()
            raise IOError('could not read generator source')

        def find_runtime(languages):
            for grader in languages:
                if grader in executors:
                    return grader
            return None

        use_cpp = any(
            map(lambda name: os.path.splitext(name)[1] == '.cpp', filenames))
        if lang is None:
            best_choices = ('CPP17', 'CPP14', 'CPP11',
                            'CPP03') if use_cpp else ('C11', 'C')
            lang = find_runtime(best_choices)

        clazz = executors.get(lang)
        if not clazz:
            raise IOError('could not find a C++ executor for generator')

        clazz = clazz.Executor

        if issubclass(clazz, CompiledExecutor):
            compiler_time_limit = compiler_time_limit or clazz.compiler_time_limit
            clazz = type('Executor', (clazz, ),
                         {'compiler_time_limit': compiler_time_limit})

        # Optimize the common case.
        if use_cpp:
            # Some generators (like those using testlib.h) take an extremely long time to compile, so we cache them.
            executor = clazz('_generator',
                             None,
                             aux_sources=sources,
                             cached=True)
        else:
            if len(sources) > 1:
                raise InternalError('non-C/C++ generator cannot be multi-file')
            executor = clazz('_generator', list(sources.values())[0])

        return executor
예제 #16
0
    def parse_return_code(cls, proc, executor, point_value, time_limit,
                          memory_limit, feedback, name, stderr):
        if proc.returncode == cls.AC:
            return CheckerResult(True, point_value, feedback=feedback)
        elif proc.returncode == cls.PARTIAL:
            match = cls.repartial.search(stderr)
            if not match:
                raise InternalError('Invalid stderr for partial points: %r' %
                                    stderr)
            points = float(match.group(0))
            if not 0 <= points <= 1:
                raise InternalError('Invalid partial points: %d' % points)

            ac = (points == 1)
            return CheckerResult(ac, points * point_value, feedback=feedback)
        elif proc.returncode == cls.WA:
            return CheckerResult(False, 0, feedback=feedback)
        else:
            parse_helper_file_error(proc, executor, name, stderr, time_limit,
                                    memory_limit)
예제 #17
0
    def launch(self, *args, **kwargs) -> TracedPopen:
        assert self._dir is not None
        for src, dst in kwargs.get('symlinks', {}).items():
            src = os.path.abspath(os.path.join(self._dir, src))
            # Disallow the creation of symlinks outside the submission directory.
            if os.path.commonprefix([src, self._dir]) == self._dir:
                # If a link already exists under this name, it's probably from a
                # previous case, but might point to something different.
                if os.path.islink(src):
                    os.unlink(src)
                os.symlink(dst, src)
            else:
                raise InternalError(
                    'cannot symlink outside of submission directory')

        agent = self._file('setbufsize.so')
        # Hardcode the ABIs for different executors for now
        if self.name == 'CPP17X':
            shutil.copyfile(setbufsize32_path, agent)
        elif self.name == 'TUR':
            shutil.copyfile(setbufsize86_path, agent)
        else:
            shutil.copyfile(setbufsize_path, agent)
        env = {
            # Forward LD_LIBRARY_PATH for systems (e.g. Android Termux) that require
            # it to find shared libraries
            'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''),
            'LD_PRELOAD': agent,
            'CPTBOX_STDOUT_BUFFER_SIZE': kwargs.get('stdout_buffer_size'),
            'CPTBOX_STDERR_BUFFER_SIZE': kwargs.get('stderr_buffer_size'),
        }
        env.update(self.get_env())

        executable = self.get_executable()
        assert executable is not None
        return TracedPopen(
            [utf8bytes(a) for a in self.get_cmdline(**kwargs) + list(args)],
            executable=utf8bytes(executable),
            security=self.get_security(launch_kwargs=kwargs),
            address_grace=self.get_address_grace(),
            data_grace=self.data_grace,
            personality=self.personality,
            time=kwargs.get('time', 0),
            memory=kwargs.get('memory', 0),
            wall_time=kwargs.get('wall_time'),
            stdin=kwargs.get('stdin'),
            stdout=kwargs.get('stdout'),
            stderr=kwargs.get('stderr'),
            env=env,
            cwd=utf8bytes(self._dir),
            nproc=self.get_nproc(),
            fsize=self.fsize,
        )
예제 #18
0
def check(proc_output, judge_output, judge_input, point_value,
          submission_source, **kwargs):
    try:
        proc_output = utf8text(proc_output)
        judge_input = utf8text(judge_input)
        judge_output = utf8text(judge_output)
        submission_source = utf8text(submission_source).replace('\r', '')

    except (AssertionError, ValueError, IndexError, TypeError, OverflowError):
        return False
    except Exception as e:
        raise InternalError('Error in checker - ' + str(e))
예제 #19
0
def check(process_output,
          judge_output,
          judge_input,
          checker_kwargs,
          problem_id,
          point_value=None,
          **kwargs) -> CheckerResult:

    # Update checker_kwargs with defaults
    for key, value in checker_defaults.items():
        checker_kwargs.setdefault(key, value)

    executor = get_executor(checker_kwargs, problem_id)

    with mktemp(judge_input) as input_file, mktemp(
            process_output) as output_file, mktemp(judge_output) as judge_file:
        process = executor.launch(input_file.name,
                                  output_file.name,
                                  judge_file.name,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE,
                                  memory=checker_kwargs['memory_limit'],
                                  time=checker_kwargs['time_limit'])

        proc_output, error = map(utf8text, process.communicate())

        # We use the testlib.h return codes
        AC = 0
        WA = 1
        PE = 2
        IE = 3

        if process.returncode == AC:
            if checker_kwargs['feedback']:
                return CheckerResult(True, point_value, feedback=proc_output)
            else:
                return CheckerResult(True, point_value)
        elif process.returncode in (WA, PE):
            if checker_kwargs['feedback']:
                return CheckerResult(False, 0, feedback=proc_output)
            else:
                return CheckerResult(False,
                                     0,
                                     feedback='Presentation Error'
                                     if process.returncode == PE else '')
        else:
            if process.returncode == IE:
                error = 'checker failed assertion with message %s' % proc_output
            else:
                error = 'checker returned unexpected return code %d with stderr %s' % (
                    process.returncode, error)
            raise InternalError(error)
예제 #20
0
def check(process_output,
          judge_output,
          judge_input,
          problem_id,
          files,
          lang,
          time_limit=env['generator_time_limit'],
          memory_limit=env['generator_memory_limit'],
          compiler_time_limit=env['generator_compiler_limit'],
          feedback=True,
          point_value=None,
          **kwargs) -> CheckerResult:
    executor = get_executor(files, lang, compiler_time_limit, problem_id)

    with mktemp(judge_input) as input_file, mktemp(
            process_output) as output_file, mktemp(judge_output) as judge_file:
        process = executor.launch(input_file.name,
                                  output_file.name,
                                  judge_file.name,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE,
                                  memory=memory_limit,
                                  time=time_limit)

        proc_output, error = map(utf8text, process.communicate())

        # We use the testlib.h return codes
        AC = 0
        WA = 1
        PE = 2
        IE = 3

        if process.returncode == AC:
            if feedback:
                return CheckerResult(True, point_value, feedback=proc_output)
            else:
                return CheckerResult(True, point_value)
        elif process.returncode in (WA, PE):
            if feedback:
                return CheckerResult(False, 0, feedback=proc_output)
            else:
                return CheckerResult(False,
                                     0,
                                     feedback='Presentation Error'
                                     if process.returncode == PE else '')
        else:
            if process.returncode == IE:
                error = 'checker failed assertion with message %s' % proc_output
            else:
                error = 'checker returned unexpected return code %d with stderr %s' % (
                    process.returncode, error)
            raise InternalError(error)
예제 #21
0
def check(process_output: bytes,
          judge_output: bytes,
          precision: int = 6,
          error_mode: str = 'default',
          **kwargs) -> bool:
    # Discount empty lines
    process_lines = list(
        filter(None, resplit(b'[\r\n]', utf8bytes(process_output))))
    judge_lines = list(
        filter(None, resplit(b'[\r\n]', utf8bytes(judge_output))))

    if len(process_lines) != len(judge_lines):
        return False

    verify_float = {
        'absolute': verify_absolute,
        'relative': verify_relative,
        'default': verify_default,
    }.get(error_mode)

    if not verify_float:
        raise InternalError('invalid `error_mode` value')

    epsilon = 10**-int(precision)

    try:
        for process_line, judge_line in zip(process_lines, judge_lines):
            process_tokens = process_line.split()
            judge_tokens = judge_line.split()

            if len(process_tokens) != len(judge_tokens):
                return False

            for process_token, judge_token in zip(process_tokens,
                                                  judge_tokens):
                # Allow mixed tokens, for lines like "abc 0.68 def 0.70"
                try:
                    judge_float = float(judge_token)
                except ValueError:
                    # If it's not a float the token must match exactly
                    if process_token != judge_token:
                        return False
                else:
                    process_float = float(process_token)

                    if not verify_float(process_float, judge_float, epsilon):
                        return False
    except Exception:
        return False
    return True
예제 #22
0
 def _protection_fault(self, syscall):
     # When signed, 0xFFFFFFFF is equal to -1, meaning that ptrace failed to read the syscall for some reason.
     # We can't continue debugging as this could potentially be unsafe, so we should exit loudly.
     # See <https://github.com/DMOJ/judge/issues/181> for more details.
     if syscall == 0xFFFFFFFF:
         raise InternalError('ptrace failed')
         # TODO: this would be more useful if we had access to a proper errno
         # import errno, os
         # err = ...
         # raise InternalError('ptrace error: %d (%s: %s)' % (err, errno.errorcode[err], os.strerror(err)))
     else:
         callname = self.debugger.get_syscall_name(syscall)
         self.protection_fault = (syscall, callname, [self.debugger.uarg0, self.debugger.uarg1,
                                                      self.debugger.uarg2, self.debugger.uarg3,
                                                      self.debugger.uarg4, self.debugger.uarg5])
예제 #23
0
 def parse_return_code(cls, proc, executor, point_value, time_limit,
                       memory_limit, feedback, name, stderr):
     if proc.returncode == cls.AC:
         return CheckerResult(True, point_value, feedback=feedback)
     elif proc.returncode == cls.WA:
         return CheckerResult(False, 0, feedback=feedback)
     elif proc.returncode == cls.PE:
         return CheckerResult(False,
                              0,
                              feedback=feedback or 'Presentation Error')
     elif proc.returncode == cls.IE:
         raise InternalError('%s failed assertion with message %s' %
                             (name, feedback))
     else:
         parse_helper_file_error(proc, executor, name, stderr, time_limit,
                                 memory_limit)
예제 #24
0
    def get_feedback(self, stderr, result, process):
        if process.returncode:
            try:
                with open(os.path.join(self._dir, 'submission_jvm_crash.log'),
                          'r') as err:
                    raise InternalError('\n\n' + err.read())
            except IOError:
                pass
        if not result.result_flag & Result.IR or not stderr or len(
                stderr) > 2048:
            return ''

        match = deque(reexception.finditer(stderr), maxlen=1)
        if not match:
            return ''
        exception = match[0].group(1).strip()
        return exception
예제 #25
0
def check(process_output,
          judge_output,
          judge_input,
          problem_id,
          files,
          lang,
          time_limit=env['generator_time_limit'],
          memory_limit=env['generator_memory_limit'],
          compiler_time_limit=env['generator_compiler_limit'],
          feedback=True,
          flags=[],
          cached=True,
          type='default',
          point_value=None,
          **kwargs) -> CheckerResult:
    executor = get_executor(problem_id, files, flags, lang,
                            compiler_time_limit, cached)

    if type not in contrib_modules:
        raise InternalError('%s is not a valid return code parser' % type)

    with mktemp(judge_input) as input_file, mktemp(
            process_output) as output_file, mktemp(judge_output) as judge_file:
        process = executor.launch(
            input_file.name,
            output_file.name,
            judge_file.name,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            memory=memory_limit,
            time=time_limit,
        )

        proc_output, error = process.communicate()
        proc_output = utf8text(proc_output)

        return contrib_modules[type].ContribModule.parse_return_code(
            process,
            executor,
            point_value,
            time_limit,
            memory_limit,
            feedback=utf8text(proc_output) if feedback else None,
            name='checker',
            stderr=error,
        )
예제 #26
0
    def get_feedback(self, stderr, result, process):
        if process.returncode:
            try:
                with open(os.path.join(self._dir, 'submission_jvm_crash.log'), 'r') as err:
                    raise InternalError('\n\n' + err.read())
            except IOError:
                pass
        if not result.result_flag & Result.IR:
            return ''

        try:
            with open(os.path.join(self._dir, 'state'), 'r') as state:
                exception = state.read().strip()
        except IOError:
            exception = "abnormal termination"  # Probably exited without calling shutdown hooks

        return exception
예제 #27
0
    def _generate_binary(self):
        siggraders = ('C', 'C11', 'CPP03', 'CPP11', 'CPP14', 'CPP17')

        for i in reversed(siggraders):
            if i in executors:
                siggrader = i
                break
        else:
            raise CompileError(
                b"can't signature grade, why did I get this submission?")

        if self.language in siggraders:
            aux_sources = {}
            handler_data = self.problem.config['signature_grader']

            entry_point = self.problem.problem_data[handler_data['entry']]
            header = self.problem.problem_data[handler_data['header']]

            # fmt: off
            submission_prefix = ('#include "%s"\n'
                                 '#define main main_%s\n') % (
                                     handler_data['header'], str(
                                         uuid.uuid4()).replace('-', ''))
            # fmt: on

            aux_sources[
                self.problem.id +
                '_submission'] = utf8bytes(submission_prefix) + self.source

            aux_sources[handler_data['header']] = header
            entry = entry_point
            # Compile as CPP regardless of what the submission language is
            return executors[siggrader].Executor(
                self.problem.id,
                entry,
                aux_sources=aux_sources,
                writable=handler_data['writable'] or (1, 2),
                fds=handler_data['fds'],
                defines=['-DSIGNATURE_GRADER'],
            )
        else:
            raise InternalError(
                'no valid runtime for signature grading %s found' %
                self.language)
예제 #28
0
def parse_helper_file_error(proc, executor, name, stderr, time_limit, memory_limit):
    if proc.is_tle:
        error = '%s timed out (> %d seconds)' % (name, time_limit)
    elif proc.is_mle:
        error = '%s ran out of memory (> %s Kb)' % (name, memory_limit)
    elif proc.protection_fault:
        syscall, callname, args = proc.protection_fault
        error = '%s invoked disallowed syscall %s (%s)' % (name, syscall, callname)
    elif proc.returncode:
        if proc.returncode > 0:
            error = '%s exited with nonzero code %d' % (name, proc.returncode)
        else:
            error = '%s exited with %s' % (name, strsignal(proc.signal))
        feedback = Result.get_feedback_str(stderr, proc, executor)
        if feedback:
            error += ' with feedback %s' % feedback
    else:
        return

    raise InternalError(error)
예제 #29
0
    def get_feedback(self, stderr, result, process):
        if process.returncode:
            try:
                with open(os.path.join(self._dir, 'submission_jvm_crash.log'), 'r') as err:
                    raise InternalError('\n\n' + err.read())
            except IOError:
                pass

        if not result.result_flag & Result.IR:
            return ''

        if b'Error: Main method not found in class' in stderr:
            exception = "public static void main(String[] args) not found"
        else:
            match = deque(reexception.finditer(utf8text(stderr, 'replace')), maxlen=1)
            if not match:
                exception = "abnormal termination"  # Probably exited without calling shutdown hooks
            else:
                exception = match[0].group(1).split(':')[0]

        return exception
예제 #30
0
    def _generate_binary(self):
        siggraders = ('C', 'C11', 'CPP03', 'CPP11', 'CPP14', 'CPP17')

        for i in reversed(siggraders):
            if i in executors:
                siggrader = i
                break
        else:
            raise CompileError(
                b"can't signature grade, why did I get this submission?")

        if self.language in siggraders:
            aux_sources = {}
            handler_data = self.problem.config['signature_grader']

            entry_point = self.problem.problem_data[handler_data['entry']]
            header = self.problem.problem_data[handler_data['header']]

            submission_prefix = '#include "%s"\n' % handler_data['header']
            if not handler_data.get('allow_main', False):
                submission_prefix += '#define main main_%s\n' % uuid.uuid4(
                ).hex

            aux_sources[
                self.problem.id +
                '_submission'] = utf8bytes(submission_prefix) + self.source

            aux_sources[handler_data['header']] = header
            entry = entry_point
            # Compile as CPP regardless of what the submission language is
            return executors[siggrader].Executor(
                self.problem.id,
                entry,
                aux_sources=aux_sources,
                defines=['-DSIGNATURE_GRADER'],
            )
        else:
            raise InternalError(
                'no valid runtime for signature grading %s found' %
                self.language)