def __init__(self, problem_id, source_code): super(Executor, self).__init__() source_code_file = self._file('%s.asm' % problem_id) with open(source_code_file, 'wb') as fo: fo.write(source_code) obj_file = self._file('%s.o' % problem_id) self._executable = output_file = self._file(str(problem_id)) nasm_process = subprocess.Popen([ env['runtime']['nasm'], '-f', 'elf32', source_code_file, '-o', obj_file ], stderr=subprocess.PIPE, cwd=self._dir) _, compile_error = nasm_process.communicate() if nasm_process.returncode != 0: raise CompileError(compile_error) if 'gcc' in env['runtime'] and source_code.startswith('; libc'): ld_process = subprocess.Popen( [env['runtime']['gcc'], '-m32', obj_file, '-o', output_file], stderr=subprocess.PIPE, cwd=self._dir) else: ld_process = subprocess.Popen([ env['runtime']['ld'], '-melf_i386', '-s', obj_file, '-o', output_file ], stderr=subprocess.PIPE, cwd=self._dir) _, link_error = ld_process.communicate() if ld_process.returncode != 0: raise CompileError(link_error) self.name = problem_id self.warning = ('%s\n%s' % (compile_error, link_error)).strip('\n')
def handle_compile_error(self, output: bytes): if b'is public, should be declared in a file named' in utf8bytes( output): raise CompileError( 'You are a troll. Trolls are not welcome. As a judge, I sentence your code to death.\n' ) raise CompileError(output)
def handle_compile_error(self, output): if b'is public, should be declared in a file named' in utf8bytes( output): raise CompileError( 'Public Class Error - Please use exactly one public class in your submission.\n' ) raise CompileError(output)
def compile(self): object = self._file('%s.o' % self.problem) process = subprocess.Popen([self.as_path, '-o', object, self._code], cwd=self._dir, stderr=subprocess.PIPE) as_output = process.communicate()[1] if process.returncode != 0: raise CompileError(as_output) to_link = [object] if 'libc' in self.features: to_link = ['-dynamic-linker', self.dynamic_linker ] + self.crt_pre + ['-lc'] + to_link + self.crt_post executable = self._file(self.problem) process = subprocess.Popen([self.ld_path, '-s', '-o', executable] + to_link, cwd=self._dir, stderr=subprocess.PIPE) ld_output = process.communicate()[1] if process.returncode != 0: raise CompileError(ld_output) self.warning = ('%s\n%s' % (as_output, ld_output)).strip() return executable
def find_class(source): source = reinline_comment.sub('', restring.sub('', recomment.sub('', source))) class_name = reclass.search(source) if class_name is None: raise CompileError('No public class: your main class must be declared as a "public class"\n') package = repackage.search(source) if package: raise CompileError('Invalid package %s: do not declare package\n' % package.group(1)) return class_name
def handle_compile_error(self, output): if b'symbol: class Scanner' in utf8bytes(output): raise CompileError( 'Te has olvidado de importar el Scanner. Has de copiar también todos los imports \n' ) if b'is public, should be declared in a file named' in utf8bytes( output): raise CompileError('Solo debe haber UNA clase pública. \n') raise CompileError(output)
def find_class(source): source = reinline_comment.sub('', restring.sub('', recomment.sub('', source))) class_name = reclass.search(source) if class_name is None: raise CompileError( 'El main debe estar dentro de una public class. ¡Como si fuera Java normal!"\n' ) package = repackage.search(source) if package: raise CompileError('Por favor, borra la linea del package\n') return class_name
def get_generator(self, filename, flags): from dmoj.executors import executors from dmoj.config import InvalidInitException filename = os.path.abspath(filename) cache_key = filename, tuple(flags) if cache_key in self._cache: return self._cache[cache_key] try: with open(filename) as file: source = file.read() except: traceback.print_exc() raise IOError('could not read generator source') def find_cpp(): for grader in ('CPP14', 'CPP11', 'CPP0X', 'CPP'): if grader in executors: return grader raise InvalidInitException( "can't grade with generator; why did I get this submission?") lookup = { '.py': executors.get('PY2', None), '.py3': executors.get('PY3', None), '.c': executors.get('C', None), '.cpp': executors.get(find_cpp(), None), '.java': executors.get('JAVA', None), '.rb': executors.get('RUBY', None) } ext = os.path.splitext(filename)[1] pass_platform_flags = ['.c', '.cpp'] if pass_platform_flags: flags += ['-DWINDOWS_JUDGE', '-DWIN32' ] if os.name == 'nt' else ['-DLINUX_JUDGE'] clazz = lookup.get(ext, None) if not clazz: raise IOError('could not identify generator extension') clazz = clazz.Executor if hasattr(clazz, 'flags'): # We shouldn't be mutating the base class flags # See https://github.com/DMOJ/judge/issues/174 clazz = type('FlaggedExecutor', (clazz, ), {'flags': flags + list(clazz.flags)}) try: # _ so we can't possibly conflict with submission source file name (e.g. /problem/generator submitted in C++) # _ is not a valid char in problem codes executor = clazz('_generator', source) except CompileError as err: # Strip ansi codes from CompileError message so we don't get wacky displays on the site like # 01m[K_generator.cpp:26:23:[m[K [01;31m[Kerror: [m[K'[01m[Kgets[m[K' was not declared in this scope raise CompileError(ansi.strip_ansi(err.message)) self._cache[cache_key] = executor return executor
def compile(self): as_output, to_link = self.assemble() if 'libc' in self.features: to_link = ['-dynamic-linker', self.dynamic_linker ] + self.crt_pre + ['-lc'] + to_link + self.crt_post executable = self._file(self.problem) process = TimedPopen( [self.get_ld_path(), '-s', '-o', executable, '-m', self.ld_m] + to_link, cwd=self._dir, stderr=subprocess.PIPE, preexec_fn=self.create_executable_limits(), time_limit=self.compiler_time_limit, ) ld_output = process.communicate()[1] if process.returncode != 0: raise CompileError(ld_output) if as_output or ld_output: self.warning = ( '%s\n%s' % (utf8text(as_output), utf8text(ld_output))).strip() self._executable = executable return executable
def __init__(self, problem_id, source_code, **kwargs): if self._has_invalid_brackets(source_code): raise CompileError(b'Unmatched brackets\n') code = template.replace( b'{code}', b''.join(map(trans.get, source_code, itertools.repeat(b'')))) super().__init__(problem_id, code, **kwargs)
def __init__(self, problem_id, main_source, aux_sources=None): super(Executor, self).__init__() if not aux_sources: aux_sources = {} aux_sources[problem_id + '.cpp'] = main_source sources = [] for name, source in aux_sources.iteritems(): if '.' not in name: name += '.cpp' with open(self._file(name), 'wb') as fo: fo.write(source) sources.append(name) output_file = self._file('%s.exe' % problem_id) cl_args = ['cl', '-nologo'] + sources + ['-W4', '-DONLINE_JUDGE', '-DWIN32', '-D_CRT_SECURE_NO_WARNINGS', '-EHsc', '-Ox', '-Fe%s' % output_file, '-link', '-stack:67108864'] cl_process = subprocess.Popen(cl_args, stderr=subprocess.PIPE, executable=env['runtime']['cl.exe'], cwd=self._dir, env=VC_COMPILE) _, compile_error = cl_process.communicate() if cl_process.returncode != 0: raise CompileError(compile_error) self._executable = output_file self.name = problem_id self.warning = compile_error
def __init__(self, problem_id, source_code, **kwargs): if source_code.count(b'[') != source_code.count(b']'): raise CompileError(b'Unmatched brackets\n') code = template.replace( b'{code}', b''.join(map(trans.get, source_code, itertools.repeat(b'')))) super(Executor, self).__init__(problem_id, code, **kwargs)
def create_files(self, problem_id, source_code, *args, **kwargs): source_code = decomment(source_code).strip() if source_code.split(b'\n')[0].strip().split() != [ b'package', b'main' ]: raise CompileError(b'Your code must be defined in package main.\n') super(Executor, self).create_files(problem_id, source_code, *args, **kwargs)
def create_files(self, problem_id, source_code, *args, **kwargs): super().create_files(problem_id, source_code, *args, **kwargs) # This step is necessary because of Unicode classnames try: source_code = utf8text(source_code) except UnicodeDecodeError: raise CompileError('Your UTF-8 is bad, and you should feel bad') class_name = find_class(source_code) self._code = self._file('%s.java' % class_name.group(1)) try: with open(self._code, 'wb') as fo: fo.write(utf8bytes(source_code)) except IOError as e: if e.errno in (errno.ENAMETOOLONG, errno.ENOENT, errno.EINVAL): raise CompileError('Why do you need a class name so long? As a judge, I sentence your code to death.\n') raise self._class_name = class_name.group(1)
def compile(self): compile_process = subprocess.Popen(self.get_compile_args(), stderr=subprocess.STDOUT, stdout=subprocess.PIPE, cwd=self._dir) compile_error = compile_process.communicate()[0] if compile_process.returncode != 0: raise CompileError(compile_error) self.warning = compile_error
def assemble(self): object = self._file('%s.o' % self.problem) process = subprocess.Popen(self.get_as_args(object), cwd=self._dir, stderr=subprocess.PIPE) as_output = process.communicate()[1] if process.returncode != 0: raise CompileError(as_output) return as_output, [object]
def assemble(self): object = self._file('%s.o' % self.problem) process = subprocess.Popen([self.as_path, '-o', object, self._code], cwd=self._dir, stderr=subprocess.PIPE) as_output = process.communicate()[1] if process.returncode != 0: raise CompileError(as_output) return as_output, [object]
def get_generator(self, filename, flags): from dmoj.executors import executors from dmoj.config import InvalidInitException filename = os.path.abspath(filename) cache_key = filename, tuple(flags) if cache_key in self._cache: return self._cache[cache_key] try: with open(filename) as file: source = file.read() except: traceback.print_exc() raise IOError('could not read generator source') def find_cpp(): for grader in ('CPP14', 'CPP11', 'CPP0X', 'CPP'): if grader in executors: return grader raise InvalidInitException( "can't grade with generator; why did I get this submission?") lookup = { '.py': executors.get('PY2', None), '.py3': executors.get('PY3', None), '.c': executors.get('C', None), '.cpp': executors.get(find_cpp(), None), '.java': executors.get('JAVA', None), '.rb': executors.get('RUBY', None) } ext = os.path.splitext(filename)[1] pass_platform_flags = ['.c', '.cpp'] if pass_platform_flags: flags += ['-DWINDOWS_JUDGE', '-DWIN32' ] if os.name == 'nt' else ['-DLINUX_JUDGE'] clazz = lookup.get(ext, None) if not clazz: raise IOError('could not identify generator extension') try: executor = clazz.Executor('_generator', source) except CompileError as err: # Strip ansi codes from CompileError message so we don't get wacky displays on the site like # 01m[K_generator.cpp:26:23:[m[K [01;31m[Kerror: [m[K'[01m[Kgets[m[K' was not declared in this scope raise CompileError(ansi.strip_ansi(err.message)) if hasattr(executor, 'flags'): executor.flags += flags self._cache[cache_key] = executor return executor
def create_files(self, problem_id, source_code, *args, **kwargs): super().create_files(problem_id, source_code, *args, **kwargs) # This step is necessary because of Unicode classnames try: source_code = utf8text(source_code) except UnicodeDecodeError: raise CompileError( 'Unicode Error - Please stick to UTF-8 characters in your submission.' ) class_name = find_class(source_code) self._code = self._file('%s.java' % class_name.group(1)) try: with open(self._code, 'wb') as fo: fo.write(utf8bytes(source_code)) except IOError as e: if e.errno in (errno.ENAMETOOLONG, errno.ENOENT, errno.EINVAL): raise CompileError( 'Class Name Error - Please use a shorter class name.\n') raise self._class_name = class_name.group(1)
def get_generator(self, filenames, flags, lang=None): from dmoj.executors import executors filenames = map(os.path.abspath, filenames) sources = {} try: for filename in filenames: with open(filename, 'r') as f: sources[os.path.basename(filename)] = f.read() except: 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', 'CPP0X', '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 hasattr(clazz, 'flags'): flags += ['-DWINDOWS_JUDGE', '-DWIN32'] if os.name == 'nt' else ['-DLINUX_JUDGE'] # We shouldn't be mutating the base class flags. # See <https://github.com/DMOJ/judge/issues/174>. clazz = type('FlaggedExecutor', (clazz,), {'flags': flags + list(clazz.flags)}) try: # 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]) except CompileError as err: # Strip ANSI codes from CompileError message so we don't get wacky displays on the site like # 01m[K_generator.cpp:26:23:[m[K [01;31m[Kerror: [m[K'[01m[Kgets[m[K' was not declared in this scope raise CompileError(ansi.strip_ansi(err.args[0])) return executor
def create_files(self, problem_id, source_code, *args, **kwargs): super(JavacExecutor, self).create_files(problem_id, source_code, *args, **kwargs) source_code = deunicode(source_code) class_name = find_class(source_code) self._code = self._file('%s.java' % class_name.group(1)) try: with open(self._code, 'wb') as fo: fo.write(source_code) except IOError as e: if e.errno in (errno.ENAMETOOLONG, errno.ENOENT): raise CompileError( 'Why do you need a class name so long? ' 'As a judge, I sentence your code to death.') raise self._class_name = class_name.group(1)
def _generate_binary(self): siggraders = ('C', 'CPP03', 'CPP0X', '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' '#define main main_%s\n') % ( handler_data['header'], str( uuid.uuid4()).replace('-', '')) 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 try: 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']) except CompileError as compilation_error: self.judge.packet_manager.compile_error_packet( ansi.format_ansi(compilation_error.args[0] or 'compiler exited abnormally')) # Compile error is fatal raise self.judge.packet_manager.compile_error_packet( 'no valid handler compiler exists')
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)
def _generate_binary(self): siggraders = ('C', 'CPP', 'CPP0X', 'CPP11', 'CPP14') for i in reversed(siggraders): if i in executors: siggrader = i break else: raise CompileError( "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_template = '''#include "%s" #define main main_%s %s ''' aux_sources[self.problem.id + '_submission'] = \ (submission_template % (handler_data['header'], str(uuid.uuid4()).replace('-', '')), self.source) aux_sources[handler_data['header']] = header entry = entry_point # Compile as CPP11 regardless of what the submission language is try: return executors[siggrader].Executor( self.problem.id, entry, aux_sources=aux_sources, writable=handler_data['writable'] or (1, 2), fds=handler_data['fds']) except CompileError as compilation_error: self.judge.packet_manager.compile_error_packet( compilation_error.message) # Compile error is fatal raise self.judge.packet_manager.compile_error_packet( 'no valid handler compiler exists')
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)
def compile(self): as_output, to_link = self.assemble() if 'libc' in self.features: to_link = ['-dynamic-linker', self.dynamic_linker ] + self.crt_pre + ['-lc'] + to_link + self.crt_post executable = self._file(self.problem) process = self.TimedPopen( [self.get_ld_path(), '-s', '-o', executable, '-m', self.ld_m] + to_link, cwd=self._dir, stderr=subprocess.PIPE, preexec_fn=self.create_executable_fslimit(), time_limit=self.compiler_time_limit) ld_output = process.communicate()[1] if process.returncode != 0 or (hasattr(process, '_killed') and process._killed): raise CompileError(ld_output) self.warning = ('%s\n%s' % (as_output, ld_output)).strip() return executable
def handle_compile_error(self, output): raise CompileError(output)
def handle_compile_error(self, output: bytes) -> None: raise CompileError(output)
def create_files(self, problem_id, source_code, *args, **kwargs): source_lines = decomment(source_code).strip().split(b'\n') if not repackage.match(source_lines[0]): raise CompileError(b'Your code must be defined in package main.\n') super().create_files(problem_id, source_code, *args, **kwargs)
def __init__(self, problem_id, source_code, **kwargs): if resetup.search(recomment.sub('', utf8text(source_code))) is None: raise CompileError('You must implement "void setup()"\n') code = template.replace(b'{code}', source_code) super(Executor, self).__init__(problem_id, code, **kwargs)