Skip to content

Commit d66596d

Browse files
committed
Merge branch 'cpp'
2 parents 4278363 + cc7941d commit d66596d

28 files changed

+464
-95
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
EMBEDDED_SOURCE = $(wildcard run_time_python/*.py wrapper_c/*.c)
1+
EMBEDDED_SOURCE = $(wildcard run_time_python/*.py wrapper_c/*.c wrapper_c/*.cpp)
22
SOURCE = $(wildcard compile_time_python/*.py)
33
BUILD_DIR=_build
44

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,6 @@ Install by creating a symbolic link, e.g.:
260260
sudo ln -sf dcc /usr/local/bin/dcc++
261261
```
262262

263-
A significant limitation is that running dual-sanitizers is not currently supported for the
264-
`iostream` library which is commonly used in novice programs.
265-
266263

267264
# Run-time Error Handling Implementation
268265

compile_time_python/compile.py

Lines changed: 102 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def main():
3737

3838

3939
def compile_user_program(options):
40-
wrapper_source, tar_source = get_wrapper_tar_source(options)
40+
wrapper_source, tar_source, wrapper_cpp_source = get_wrapper_code(options)
4141
compiler_stdout = ""
4242
executable_source = ""
4343

@@ -67,8 +67,9 @@ def compile_user_program(options):
6767
+ sanitizer2_sanitizer_args
6868
+ ["-o", executable],
6969
options,
70-
wrapper_source=sanitizer2_wrapper_source,
71-
debug_wrapper_file="tmp_dcc_sanitizer2.c",
70+
wrapper_C_source=sanitizer2_wrapper_source,
71+
wrapper_cpp_source=wrapper_cpp_source,
72+
debug_C_wrapper_file="tmp_dcc_sanitizer2.c",
7273
)
7374
with open(executable, "rb") as f:
7475
(
@@ -115,7 +116,8 @@ def compile_user_program(options):
115116
+ sanitizer_args
116117
+ ["-o", options.object_pathname],
117118
options,
118-
wrapper_source=wrapper_source,
119+
wrapper_C_source=wrapper_source,
120+
wrapper_cpp_source=wrapper_cpp_source,
119121
print_stdout=not compiler_stdout,
120122
)
121123

@@ -142,8 +144,8 @@ def compile_user_program(options):
142144

143145

144146
# customize wrapper source for a particular sanitizer
145-
def update_wrapper_source(sanitizer, sanitizer_n, wrapper_source, tar_source, options):
146-
wrapper_source = wrapper_source.replace("__SANITIZER__", sanitizer.upper())
147+
def update_wrapper_source(sanitizer, sanitizer_n, src, tar_source, options):
148+
src = src.replace("__SANITIZER__", sanitizer.upper())
147149
if sanitizer == "valgrind":
148150
sanitizer_args = []
149151
elif sanitizer == "memory":
@@ -153,11 +155,9 @@ def update_wrapper_source(sanitizer, sanitizer_n, wrapper_source, tar_source, op
153155

154156
# if sanitizer != "memory" and not (sanitizer_n == 2 and sanitizer == "valgrind"):
155157
if sanitizer != "memory" and not (sanitizer_n == 2 and sanitizer == "valgrind"):
156-
# FIXME if we enable '-fsanitize=undefined', '-fno-sanitize-recover=undefined,integer' for memory
158+
# FIXME if we enable '-fsanitize=undefined', '-fno-sanitize-recover=undefined,integer' for memory
157159
# which would be preferable here we get uninitialized variable error message for undefined errors
158-
wrapper_source = wrapper_source.replace(
159-
"__UNDEFINED_BEHAVIOUR_SANITIZER_IN_USE__", "1"
160-
)
160+
src = src.replace("__UNDEFINED_BEHAVIOUR_SANITIZER_IN_USE__", "1")
161161
sanitizer_args += ["-fsanitize=undefined"]
162162

163163
# These options stop error explanations if __ubsan_on_report can not be intercepted (on Ubuntu)
@@ -172,59 +172,64 @@ def update_wrapper_source(sanitizer, sanitizer_n, wrapper_source, tar_source, op
172172
if os.path.exists(lib_dir):
173173
sanitizer_args += ["-shared-libasan", "-Wl,-rpath," + lib_dir]
174174

175-
wrapper_source = wrapper_source.replace(
176-
"__LEAK_CHECK_YES_NO__", "yes" if options.leak_check else "no"
177-
)
175+
src = src.replace("__LEAK_CHECK_YES_NO__", "yes" if options.leak_check else "no")
178176
leak_check = options.leak_check
179177
if leak_check and options.sanitizers[1:] == ["valgrind"]:
180178
# do leak checking in valgrind (only) for (currently) better messages
181179
leak_check = False
182-
wrapper_source = wrapper_source.replace(
183-
"__LEAK_CHECK_1_0__", "1" if leak_check else "0"
184-
)
185-
wrapper_source = wrapper_source.replace(
186-
"__USE_FUNOPEN__", "1" if options.use_funopen else "0"
187-
)
180+
src = src.replace("__LEAK_CHECK_1_0__", "1" if leak_check else "0")
181+
src = src.replace("__USE_FUNOPEN__", "1" if options.use_funopen else "0")
188182

189-
wrapper_source = wrapper_source.replace(
190-
"__I_AM_SANITIZER1__", "1" if sanitizer_n == 1 else "0"
191-
)
192-
wrapper_source = wrapper_source.replace(
193-
"__I_AM_SANITIZER2__", "1" if sanitizer_n == 2 else "0"
194-
)
195-
wrapper_source = wrapper_source.replace(
183+
src = src.replace("__I_AM_SANITIZER1__", "1" if sanitizer_n == 1 else "0")
184+
src = src.replace("__I_AM_SANITIZER2__", "1" if sanitizer_n == 2 else "0")
185+
src = src.replace(
196186
"__WHICH_SANITIZER__", "sanitizer2" if sanitizer_n == 2 else "sanitizer1"
197187
)
198188

199-
wrapper_source = tar_source + wrapper_source
200-
return wrapper_source, sanitizer_args
189+
src = tar_source + src
190+
return src, sanitizer_args
201191

202192

203193
def execute_compiler(
204194
compiler,
205195
dcc_supplied_arguments,
206196
options,
207-
wrapper_source="",
208-
debug_wrapper_file="tmp_dcc_sanitizer1.c",
197+
wrapper_C_source="",
198+
debug_C_wrapper_file="tmp_dcc_sanitizer1.c",
209199
rename_functions=True,
210200
print_stdout=True,
211201
checking_only=False,
202+
wrapper_cpp_source="",
203+
debug_cpp_wrapper_file="tmp_dcc_sanitizer1.cpp",
212204
):
213-
extra_arguments, extra_arguments_debug = compile_wrapper_source(
214-
wrapper_source, options, rename_functions, debug_wrapper_file
205+
extra_c_arguments, extra_c_arguments_debug = compile_wrapper_source(
206+
wrapper_C_source,
207+
options,
208+
debug_C_wrapper_file,
209+
cpp=False,
210+
rename_functions=rename_functions,
211+
)
212+
extra_cpp_arguments, extra_cpp_arguments_debug = compile_wrapper_source(
213+
wrapper_cpp_source,
214+
options,
215+
debug_cpp_wrapper_file,
216+
cpp=True,
217+
rename_functions=rename_functions,
215218
)
216219

217220
command = (
218221
[compiler]
219222
+ dcc_supplied_arguments
220-
+ extra_arguments
223+
+ extra_c_arguments
224+
+ extra_cpp_arguments
221225
+ options.user_supplied_compiler_args
222226
)
223227
if options.debug > 1:
224228
debug_command = (
225229
[compiler]
226230
+ dcc_supplied_arguments
227-
+ extra_arguments_debug
231+
+ extra_c_arguments_debug
232+
+ extra_cpp_arguments_debug
228233
+ options.user_supplied_compiler_args
229234
)
230235
append_debug_compile(debug_command)
@@ -282,9 +287,11 @@ def execute_compiler(
282287
dcc_supplied_arguments,
283288
options,
284289
rename_functions=False,
285-
wrapper_source=wrapper_source,
290+
wrapper_C_source=wrapper_C_source,
286291
print_stdout=print_stdout,
287-
debug_wrapper_file=debug_wrapper_file,
292+
debug_C_wrapper_file=debug_C_wrapper_file,
293+
wrapper_cpp_source=wrapper_cpp_source,
294+
debug_cpp_wrapper_file=debug_cpp_wrapper_file,
288295
)
289296

290297
if stdout and print_stdout:
@@ -300,15 +307,20 @@ def execute_compiler(
300307

301308

302309
def compile_wrapper_source(
303-
source, options, rename_functions=True, debug_wrapper_file="tmp_dcc_sanitizer1.c"
310+
source, options, debug_wrapper_file, cpp=False, rename_functions=True
304311
):
305312
if not source:
306313
return [], []
307314
rename_arguments, source = get_rename_arguments(source, options, rename_functions)
308-
relocatable_filename = os.path.join(
309-
options.temporary_directory, "dcc_wrapper_source.o"
315+
relocatable_basename = (
316+
"dcc_cpp_wrapper_source.o" if cpp else "dcc_c_wrapper_source.o"
317+
)
318+
relocatable_pathname = os.path.join(
319+
options.temporary_directory, relocatable_basename
310320
)
311-
compiler = options.c_compiler.replace("clang++", "clang").replace("++", "cc")
321+
compiler = options.c_compiler
322+
if not cpp:
323+
compiler = options.c_compiler.replace("clang++", "clang").replace("++", "cc")
312324
if options.debug > 1:
313325
try:
314326
options.debug_print("Leaving dcc code in", debug_wrapper_file)
@@ -321,23 +333,23 @@ def compile_wrapper_source(
321333
"-c",
322334
debug_wrapper_file,
323335
"-o",
324-
"dcc_wrapper_source.o",
336+
relocatable_basename,
325337
] + WRAPPER_SOURCE_COMPILER_ARGS
326338
append_debug_compile(debug_command)
327339
command = [
328340
compiler,
329341
"-c",
330342
"-x",
331-
"c",
343+
"c++" if cpp else "c",
332344
"-",
333345
"-o",
334-
relocatable_filename,
346+
relocatable_pathname,
335347
] + WRAPPER_SOURCE_COMPILER_ARGS
336348
process = run(command, options, input=source)
337349
if process.stdout or process.returncode != 0:
338350
options.die("Internal error\n" + process.stdout)
339-
return rename_arguments + [relocatable_filename], rename_arguments + [
340-
"dcc_wrapper_source.o",
351+
return rename_arguments + [relocatable_pathname], rename_arguments + [
352+
relocatable_basename
341353
]
342354

343355

@@ -401,7 +413,17 @@ def append_debug_compile(command):
401413
print(e, file=sys.stderr)
402414

403415

404-
def get_wrapper_tar_source(options):
416+
def get_wrapper_cpp_code(options):
417+
wrapper_source = "".join(
418+
pkgutil.get_data("embedded_src", f).decode("utf8")
419+
for f in [
420+
"dcc_io.c",
421+
]
422+
)
423+
return add_constants_to_source_code(wrapper_source, options)
424+
425+
426+
def get_wrapper_code(options):
405427
wrapper_source = "".join(
406428
pkgutil.get_data("embedded_src", f).decode("utf8")
407429
for f in [
@@ -411,41 +433,45 @@ def get_wrapper_tar_source(options):
411433
"dcc_check_output.c",
412434
]
413435
)
414-
415-
wrapper_source = wrapper_source.replace("__PATH__", options.dcc_path)
416-
wrapper_source = wrapper_source.replace("__DCC_VERSION__", '"' + VERSION + '"')
417-
wrapper_source = wrapper_source.replace("__HOSTNAME__", '"' + platform.node() + '"')
418-
wrapper_source = wrapper_source.replace(
419-
"__CLANG_VERSION__", f'"{options.clang_version}"'
420-
)
421-
wrapper_source = wrapper_source.replace(
422-
"__SUPRESSIONS_FILE__", options.suppressions_file
436+
wrapper_source = add_constants_to_source_code(wrapper_source, options)
437+
wrapper_source, tar_source = add_embedded_tarfile_handling_to_source_code(
438+
wrapper_source, options
423439
)
424-
wrapper_source = wrapper_source.replace(
440+
wrapper_cpp_source = ""
441+
if options.cpp_mode:
442+
wrapper_cpp_source = "".join(
443+
pkgutil.get_data("embedded_src", f).decode("utf8")
444+
for f in [
445+
"dcc_io.cpp",
446+
]
447+
)
448+
return wrapper_source, tar_source, wrapper_cpp_source
449+
450+
451+
def add_constants_to_source_code(src, options):
452+
src = src.replace("__PATH__", options.dcc_path)
453+
src = src.replace("__DCC_VERSION__", '"' + VERSION + '"')
454+
src = src.replace("__HOSTNAME__", '"' + platform.node() + '"')
455+
src = src.replace("__CLANG_VERSION__", f'"{options.clang_version}"')
456+
src = src.replace("__SUPRESSIONS_FILE__", options.suppressions_file)
457+
src = src.replace(
425458
"__STACK_USE_AFTER_RETURN__", "1" if options.stack_use_after_return else "0"
426459
)
427-
wrapper_source = wrapper_source.replace(
428-
"__CHECK_OUTPUT__", "1" if options.check_output else "0"
429-
)
430-
wrapper_source = wrapper_source.replace(
460+
src = src.replace("__CHECK_OUTPUT__", "1" if options.check_output else "0")
461+
src = src.replace("__CPP_MODE__", "1" if options.cpp_mode else "0")
462+
src = src.replace(
431463
"__WRAP_POSIX_SPAWN__", "1" if options.valgrind_fix_posix_spawn else "0"
432464
)
433-
wrapper_source = wrapper_source.replace(
434-
"__CLANG_VERSION_MAJOR__", str(options.clang_version_major)
435-
)
436-
wrapper_source = wrapper_source.replace(
437-
"__CLANG_VERSION_MINOR__", str(options.clang_version_minor)
438-
)
439-
wrapper_source = wrapper_source.replace(
440-
"__N_SANITIZERS__", str(len(options.sanitizers))
441-
)
442-
wrapper_source = wrapper_source.replace("__DEBUG__", "1" if options.debug else "0")
443-
465+
src = src.replace("__CLANG_VERSION_MAJOR__", str(options.clang_version_major))
466+
src = src.replace("__CLANG_VERSION_MINOR__", str(options.clang_version_minor))
467+
src = src.replace("__N_SANITIZERS__", str(len(options.sanitizers)))
468+
src = src.replace("__DEBUG__", "1" if options.debug else "0")
444469
if len(options.sanitizers) > 1:
445-
wrapper_source = wrapper_source.replace(
446-
"__SANITIZER_2__", options.sanitizers[1].upper()
447-
)
470+
src = src.replace("__SANITIZER_2__", options.sanitizers[1].upper())
471+
return src
472+
448473

474+
def add_embedded_tarfile_handling_to_source_code(src, options):
449475
tar_n_bytes, tar_source = source_for_embedded_tarfile(options)
450476
watcher = rf"python3 -E -c \"import io,os,sys,tarfile,tempfile\n\
451477
with tempfile.TemporaryDirectory() as temp_dir:\n\
@@ -455,10 +481,8 @@ def get_wrapper_tar_source(options):
455481
os.chdir(temp_dir)\n\
456482
exec(open('watch_valgrind.py').read())\n\
457483
\""
458-
459-
wrapper_source = wrapper_source.replace("__MONITOR_VALGRIND__", watcher)
460-
461-
return wrapper_source, tar_source
484+
src = src.replace("__MONITOR_VALGRIND__", watcher)
485+
return src, tar_source
462486

463487

464488
def run(

compile_time_python/options.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import io, os, platform, re, subprocess, sys, tarfile
22
from version import VERSION
33

4-
# on some platforms -Wno-unused-result is needed to avoid warnings about scanf's return value being ignored -
4+
5+
# on some platforms -Wno-unused-result is needed
6+
# to avoid warnings about scanf's return value being ignored and
57
# novice programmers will often be told to ignore scanf's return value
68
# when writing their first programs
79

@@ -27,17 +29,20 @@
2729
""".split()
2830

2931

30-
# gcc flags some novice programmer mistakes than clang doesn't so
31-
# we run it has an extra checking pass with several extra warnings enabled
32-
# -Wduplicated-branches was only added with gcc-8 so it will break older versions of gcc
33-
# this will be silent but we lose gcc checking - we could fix by checking gcc version
32+
# gcc detects some typical novice programmer mistakes that clang doesn't
33+
# We run gcc has an extra checking pass with several warnings options enabled
34+
#
35+
# The option -Wduplicated-branches was only added with gcc-8
36+
# it will break older versions of gcc
37+
# this will be silent but we lose gcc checking
3438
#
35-
# -Wnull-dererefence would be useful here but when it flags potential paths
36-
# the errors look confusing for novice programmers ,and there appears no way to get only definite null-derefs
39+
# The option -Wnull-dererefence looks be useful but when it flags potential paths
40+
# the errors look confusing for novice programmers,
41+
# and there appears no way to get only definite null-derefs
3742
#
3843
# -O is needed with gcc to get warnings for some things
3944

40-
GCC_ONLY_ARGS = "-Wunused-but-set-variable -Wduplicated-cond -Wduplicated-branches -Wlogical-op -O -o /dev/null".split()
45+
GCC_ONLY_ARGS = "-Wunused-but-set-variable -Wduplicated-cond -Wduplicated-branches -Wlogical-op -O -o /dev/null".split()
4146

4247

4348
class Options:
@@ -109,6 +114,7 @@ def __init__(self):
109114
]
110115
safe_c_includes = [i + ".h" for i in safe_c_includes_basenames]
111116
safe_cpp_includes = ["c" + i for i in safe_c_includes_basenames if "/" not in i]
117+
safe_cpp_includes += ["iostream"]
112118
self.dual_sanitizer_safe_system_includes = set(
113119
safe_c_includes + safe_cpp_includes
114120
)

0 commit comments

Comments
 (0)