imported lab skeletons

This commit is contained in:
Sven Gestegard Robertz 2021-10-27 15:15:47 +02:00
parent 4fc8b6c771
commit e4df45f4a9
47 changed files with 15122 additions and 87 deletions

17
lab1/Makefile Normal file
View file

@ -0,0 +1,17 @@
# The following rule means: "if test_editor does not exist, or
# is older than test_editor.o or editor.o,
# then link test_editor".
test_editor: test_editor.o editor.o
g++ -o test_editor test_editor.o editor.o
# Rules to create the object files.
test_editor.o: test_editor.cc editor.h
g++ -c test_editor.cc -std=c++11
editor.o: editor.cc editor.h
g++ -c editor.cc -std=c++11
print_argv: print_argv.o
g++ -o print_argv print_argv.o
print_argv.o: print_argv.cc
g++ -c print_argv.cc -std=c++11

50
lab1/MakefileWithDeps Normal file
View file

@ -0,0 +1,50 @@
# Define the compiler and the linker. The linker must be defined since
# the implicit rule for linking uses CC as the linker. g++ can be
# changed to clang++.
CXX = g++
CC = $(CXX)
# Generate dependencies in *.d files
DEPFLAGS = -MT $@ -MMD -MP -MF $*.d
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
# if you use clang++ and wish to use libc++ instead of GNU's libstdc++.
# -g is for debugging.
CPPFLAGS = -std=c++11 -I.
CXXFLAGS = -O2 -Wall -Wextra -pedantic-errors -Wold-style-cast
CXXFLAGS += -std=c++11
CXXFLAGS += -g
CXXFLAGS += $(DEPFLAGS)
LDFLAGS = -g
#CPPFLAGS += -stdlib=libc++
#CXXFLAGS += -stdlib=libc++
#LDFLAGS += -stdlib=libc++
# Targets
PROGS = test_editor test_coding print_argv
all: $(PROGS)
test: test_coding test_editor
./test_coding
./test_editor
# Targets rely on implicit rules for compiling and linking
print_argv: print_argv.o
test_editor: test_editor.o editor.o
test_coding: test_coding.o coding.o
# Phony targets
.PHONY: all test clean distclean
# Standard clean
clean:
rm -f *.o $(PROGS)
distclean: clean
rm *.d
# Include the *.d files
SRC = $(wildcard *.cc)
-include $(SRC:.cc=.d)

View file

@ -0,0 +1,81 @@
# An example CMakeLists.txt for the sanitizers example, showing how to
# enable sanitizers in a debug build.
# It uses generator expressions, to set additional flags when the build type
# is Debug.
#
# To try this out, first create a build directory for a release build,
# and do a release build, e.g.,
# % mkdir build-rel
# % cd build-rel
# % cmake SRC_DIR -DCMAKE_BUILD_TYPE=Release
# % make
#
# Run the examples and see that they crash.
#
# Then create another build directory and do a debug build:
#
# % mkdir build-dbg
# % cd build-dbg
# % cmake SRC_DIR -DCMAKE_BUILD_TYPE=Debug
# % make
#
# where SRC_DIR is the directory containing the source and CMakeLists.txt,
# e.g., .. if your build directories are placed in this directory.
#
# Run the examples and verify that the sanitizers find the errors.
#
# If you want to see the actual commands run during the build, for instance
# to verify that the correct compiler flags are used, you can do
#
# % make VERBOSE=1
cmake_minimum_required (VERSION 3.5)
project (Sanitizers)
set (CMAKE_CXX_STANDARD 11)
# The three standard build types are Release, Debug, and RelWithDebInfo.
# If set here, it forces that build type.
#
# set(CMAKE_BUILD_TYPE Release)
# set build type to DEBUG
# set(CMAKE_BUILD_TYPE Debug)
# or to get an optimized build w/ debug symbols
# set(CMAKE_BUILD_TYPE RelWithDebInfo)
# add the executables
add_executable(leak leak.cc)
add_executable(bounds bounds.cc)
add_executable(bounds-heap bounds-heap.cc)
add_executable(ub ub.cc)
add_executable(dangling dangling.cc)
add_executable(sum sum.cc)
add_executable(sum_alt sum.cc)
# set compiler flag to turn off optimization (for all builds)
# add_compile_options("-O0")
# or use generator expressions to set flags in debug builds
add_compile_options($<$<CONFIG:Debug>:-O0>)
# set compiler and linker flags to enable the relevant sanitizer
target_compile_options(leak PUBLIC $<$<CONFIG:Debug>:-fsanitize=leak>)
target_link_libraries(leak $<$<CONFIG:Debug>:-fsanitize=leak>)
target_compile_options(bounds PUBLIC $<$<CONFIG:Debug>:-fsanitize=address>)
target_link_libraries(bounds $<$<CONFIG:Debug>:-fsanitize=address>)
target_compile_options(bounds-heap PUBLIC $<$<CONFIG:Debug>:-fsanitize=address>)
target_link_libraries(bounds-heap $<$<CONFIG:Debug>:-fsanitize=address>)
target_compile_options(ub PUBLIC $<$<CONFIG:Debug>:-fsanitize=undefined>)
target_link_libraries(ub $<$<CONFIG:Debug>:-fsanitize=undefined>)
target_compile_options(dangling PUBLIC $<$<CONFIG:Debug>:-fsanitize=address>)
target_link_libraries(dangling $<$<CONFIG:Debug>:-fsanitize=address>)
target_compile_options(sum PUBLIC $<$<CONFIG:Debug>:-fsanitize=undefined>)
target_link_libraries(sum $<$<CONFIG:Debug>:-fsanitize=undefined>)
target_compile_options(sum_alt PUBLIC $<$<CONFIG:Debug>:-fsanitize=address>)
target_link_libraries(sum_alt $<$<CONFIG:Debug>:-fsanitize=address>)

View file

@ -0,0 +1,40 @@
# Define the compiler and the linker. The linker must be defined since
# the implicit rule for linking uses CC as the linker. g++ can be
# changed to clang++.
CXX = g++
CC = $(CXX)
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
# if you use clang++ and wish to use libc++ instead of GNU's libstdc++.
# -g is for debugging.
CPPFLAGS = -std=c++11 -I.
CXXFLAGS = -O0 -Wall -Wextra -pedantic-errors -Wold-style-cast
CXXFLAGS += -std=c++11
CXXFLAGS += -g
LDFLAGS = -g
# CPPFLAGS += -stdlib=libc++
# CXXFLAGS += -stdlib=libc++
# LDFLAGS += -stdlib=libc++
PROGS=ub leak bounds bounds-heap dangling sum
ALL: $(PROGS)
leak: leak.cc
dangling: dangling.cc
bounds: bounds.cc
ub: ub.cc
sum: sum.cc
# Targets
# Phony targets
.PHONY: all clean test
# Standard clean
clean:
-rm $(PROGS)
-rm -r $(addsuffix .dSYM, $(PROGS))

View file

@ -0,0 +1,58 @@
# Define the compiler and the linker. The linker must be defined since
# the implicit rule for linking uses CC as the linker. g++ can be
# changed to clang++.
CXX = g++
CC = $(CXX)
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
# if you use clang++ and wish to use libc++ instead of GNU's libstdc++.
# -g is for debugging.
CPPFLAGS = -std=c++11 -I.
CXXFLAGS = -O0 -Wall -Wextra -pedantic-errors -Wold-style-cast
CXXFLAGS += -std=c++11
CXXFLAGS += -g
LDFLAGS = -g
# CPPFLAGS += -stdlib=libc++
# CXXFLAGS += -stdlib=libc++
# LDFLAGS += -stdlib=libc++
PROGS=ub leak bounds bounds-heap dangling sum sum-alt bounds-alt bounds-heap-alt
ALL: $(PROGS)
leak: leak.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=leak -o $@ $<
dangling: dangling.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=address -o $@ $<
bounds: bounds.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=address -o $@ $<
bounds-heap: bounds-heap.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=address -o $@ $<
bounds-alt: bounds.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=undefined -o $@ $<
bounds-heap-alt: bounds-heap.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=undefined -o $@ $<
ub: ub.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=undefined -o $@ $<
sum: sum.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=undefined -o $@ $<
sum-alt: sum.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fsanitize=address -o $@ $<
# Targets
# Phony targets
.PHONY: all clean
# Standard clean
clean:
-rm $(PROGS)
-rm -r $(addsuffix .dSYM, $(PROGS))

View file

@ -0,0 +1,64 @@
This directory contains a few small examples of how the google sanitizers
can be used to find problems related to memory management and undefined behaviour.
The sanitizers are libraries that are used to instrument your programs, which is
done by compiling and linking with the option -fsanitize=<SANITIZER>.
For building this example includes two makefiles, one for building without
sanitizers (Makefile) and one for building with them (Makefile.sanitizers).
Also included is a CMakeListst.txt which uses sanitizers when doing a debug build.
Examples:
The file leak.cc contains an example of a memory leak.
The files bounds.cc, bounds-heap.cc and sum.cc contain examples of accessing
outside the bounds of an array (on the stack and on the heap).
The file dangling.cc contains an example of using a dangling pointer.
The file ub.cc contains an example of undefined behaviour.
Demonstration:
First build the programs using Makefile, and run them.
Then, first do make clean and then build them using Makefile.sanitizers
(make -f Makefile.sanitizers)
Run the programs again, and see if the errors are detected. Try to understand
the diagnostics pringed when the sanitizer detects an error.
Note that the different sanitizers may produce different error messages
for the same problem. Compare the output from sum and sum_alt (which are
built from the same source file, but with different sanitizers.)
This example also includes a CMakeLists.txt that illustrates how to enable
the sanitizers for debug builds.
Building with cmake:
With cmake, make debug and release builds and compare, typically in
separate build directories:
For the release build:
% mkdir build-rel
% cd build-rel
% cmake -DCMAKE_BUILD_TYPE=Release SRC_DIR
% make
For the debug build:
% mkdir build-rel
% cd build-rel
% cmake -DCMAKE_BUILD_TYPE=Debug SRC_DIR
% make
Both gcc and clang use the google sanitizers, but different compiler versions
may use different versions of the sanitizers. If you have installed a more recent
compiler version, you may need to tell cmake to use that.
By default, cmake will use the system's default compiler. To specify which
compiler to use, you can add (for gcc)
-DCMAKE_CXX_COMPILER=g++
-DCMAKE_C_COMPILER=gcc
or, for clang:
-DCMAKE_CXX_COMPILER=clang++
-DCMAKE_C_COMPILER=clang

View file

@ -0,0 +1,25 @@
#include <iostream>
#include <numeric>
#include <memory>
using std::cout;
void print(int* a, int size)
{
for(int i=0; i < size; ++i){
cout << a[i] << " ";
}
cout << "\n";
}
void example()
{
std::unique_ptr<int[]> xs(new int[10]);
std::iota(xs.get(), xs.get()+10, 0);
print(xs.get(), 15);
}
int main()
{
example();
}

View file

@ -0,0 +1,24 @@
#include <iostream>
#include <numeric>
using std::cout;
void print(int* a, int size)
{
for(int i=0; i < size; ++i){
cout << a[i] << " ";
}
cout << "\n";
}
void example()
{
int xs[10];
std::iota(xs, xs+10, 0);
print(xs, 15);
}
int main()
{
example();
}

View file

@ -0,0 +1,37 @@
#include <iostream>
#include <numeric>
using std::cout;
struct Foo{
Foo(int s) :p(new int[s]), sz(s) {}
~Foo() {delete[] p;}
int* begin() {return p;}
int* end() {return begin()+sz;}
const int* begin() const {return p;}
const int* end() const {return begin()+sz;}
int* p;
int sz;
};
void print(Foo f)
{
for(const auto& x : f) cout << x << " ";
endl(cout);
}
void example1()
{
Foo f(10);
std::iota(std::begin(f), std::end(f), 0);
print(f);
cout << "after first print\n";
*f.begin()=123;
cout << "printing again\n";
print(f);
cout << "done\n";
}
int main()
{
example1();
}

View file

@ -0,0 +1,29 @@
#include <iostream>
using std::cout;
struct Foo{
Foo(int s) :p{new int[s]} {}
int* p;
};
struct Bar{
Bar(int x) :f(x) {}
Foo f;
};
void example1()
{
Foo f(10);
{
cout << "entering inner block\n";
Bar b(20);
cout << "leaving inner block\n";
}
cout << "leaving example1\n";
}
int main()
{
example1();
cout << "leaving main\n";
}

View file

@ -0,0 +1,20 @@
#include <iostream>
#define N (4)
int x = 1000;
int a[]{ 1, 2, 3, 4 };
int y = 2000;
int main()
{
int sum{0};
std::cout << "welcome to the buggy sum program. the sum should be 10\n";
for (int i = 0; i <= N; i++)
sum += a[i];
std::cout << "sum = " << sum << "\n";
return 0;
}

31
lab1/buggy_programs/ub.cc Normal file
View file

@ -0,0 +1,31 @@
#include <iostream>
#include <vector>
#include <cassert>
#include <numeric>
using std::cout;
using std::endl;
std::vector<int> create_vector(int s)
{
assert(s >= 0);
std::vector<int> res(s);
}
template <typename C>
void print_seq(const C& c)
{
for(const auto& x : c) cout << x << " ";
cout << "\n";
}
void example()
{
auto v = create_vector(10);
std::iota(begin(v), end(v), 0);
print_seq(v);
}
int main()
{
example();
}

View file

@ -0,0 +1,44 @@
cmake_minimum_required (VERSION 3.5)
project (Simple)
set (CMAKE_CXX_STANDARD 11)
# set build type to DEBUG
set(CMAKE_BUILD_TYPE Debug)
# or to get an optimized build w/ debug symbols
# set(CMAKE_BUILD_TYPE RelWithDebInfo)
# add the library to the include file search path
include_directories ("${PROJECT_SOURCE_DIR}/testlib")
add_subdirectory (testlib)
# set compiler and linker flags
add_compile_options("-Og")
#add_compile_options("-fsanitize=address")
#link_libraries("-fsanitize=address")
# add the executable SimpleMain and its dependency on TestLib
add_executable(SimpleMain main.cc)
target_link_libraries (SimpleMain TestLib)
##################### Optional features below this line ############
# The version number. This is not needed but included
# to show how information can be passed from CMakeLists.txt
# to the program.
set (Simple_VERSION_MAJOR 1)
set (Simple_VERSION_MINOR 0)
# configure a header file to pass some of the CMake settings
# to the source code. Only needed if we want to pass some
# information or configuration from Cmake to the program
# being built.
configure_file (
"${PROJECT_SOURCE_DIR}/SimpleConfig.h.in"
"${PROJECT_BINARY_DIR}/SimpleConfig.h"
)
# add the binary tree to the search path for include files
# so that we will find SimpleConfig.h
include_directories("${PROJECT_BINARY_DIR}")

35
lab1/cmake-example/README Normal file
View file

@ -0,0 +1,35 @@
This is an example project that is built with cmake.
The project consists of
- an example library, TestLib, which is built from testlib/foo.h and .cc
- a configuration file, SimpleConfig.h which is built from SimpleConfig.h.in
- a main program, in main.cc
With cmake, you usually build the project in a directory separate from the source,
typically named build. This has the advantages that you can easily make several
separate builds simply by doing them in separate build directories. It also
means that the generated files are kept separate from the source code, so that
removing them is done by simply removing the entire build directory.
The steps to create the build files (Makefile, unless otherwise specified, but
cmake can generate project files for other build systems as well) and then
build the project are
> mkdir build
> cd build
> cmake ..
> make
To see the actual commands executed when building with the generated Makefile,
use the command
> make VERBOSE=1
Configuration of the compilation can be done by setting environment variables
which are read by cmake.
To set which compiler to use:
CC=clang CXX=clang++ cmake ..
To set compiler flags, one can use
cmake -DCMAKE_CXX_FLAGS="-Wall -Werror" ..

View file

@ -0,0 +1,3 @@
// the configured options and settings for simple
#define Simple_VERSION_MAJOR @Simple_VERSION_MAJOR@
#define Simple_VERSION_MINOR @Simple_VERSION_MINOR@

View file

@ -0,0 +1,25 @@
#include <iostream>
#include "SimpleConfig.h"
#include "foo.h"
#include "bar.h"
using std::cout;
using std::endl;
/* A small example of a project built using CMake.
* The Simple_VERSION_* variables are included
* to show how a header file with configuration macros
* can be generated from the CMakeLists.txt.
*/
int main()
{
cout << "This is version " << Simple_VERSION_MAJOR << "." <<
Simple_VERSION_MINOR << "\n";
cout << "Hello, world!\n";
foo_fun();
bar_fun(42);
}

View file

@ -0,0 +1 @@
add_library(TestLib foo.cc bar.cc)

View file

@ -0,0 +1,6 @@
#include <iostream>
void bar_fun(int x)
{
std::cout << "[bar: " << x << "]" << "\n";
}

View file

@ -0,0 +1 @@
void bar_fun(int);

View file

@ -0,0 +1,7 @@
#include <iostream>
void foo_fun()
{
auto x = 17; // use a C++11 feature to see if flags are set correctly
std::cout << "[foo: " << x << "]" << "\n";
}

View file

@ -0,0 +1 @@
void foo_fun();

10
lab1/coding.cc Normal file
View file

@ -0,0 +1,10 @@
#include<coding.h>
unsigned char encode(unsigned char c)
{
return c;
}
unsigned char decode(unsigned char c)
{
return c;
}

6
lab1/coding.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef __CODING_H
#define __CODING_H
unsigned char encode(unsigned char c);
unsigned char decode(unsigned char c);
#endif

16
lab1/editor.cc Normal file
View file

@ -0,0 +1,16 @@
#include "editor.h"
#include <string>
using std::string;
using size_type = Editor::size_type;
size_type Editor::get_size() const
{
return text.size();
}
size_type Editor::find_left_par(size_type pos) const {
return string::npos;
}

27
lab1/editor.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef EDITOR_H
#define EDITOR_H
#include <string>
class Editor {
public:
using size_type = std::string::size_type;
/* Creates a text editor containing the text t */
Editor(const std::string& t) : text(t) {}
/* Get the size of the current contents */
size_type get_size() const;
/*
* Text[pos] contains a right parentheses. Returns the position of
* the corresponding left parentheses, or string::npos if there
* is no match.
*/
size_type find_left_par(size_type pos) const;
// ... functions to edit the text (insert and delete characters)
private:
std::string text;
};
#endif

25
lab1/file_io_example.cc Normal file
View file

@ -0,0 +1,25 @@
#include"coding.h"
#include<iostream>
#include <iomanip>
#include<fstream>
void print_bytes(std::string infile)
{
std::ifstream in{infile};
int c;
while((c = in.get()) != EOF ) {
std::cout << "read: " << std::setw(3) << c << " [" << char(c) << "]" << std::endl;
}
}
int main(int argc, char* argv[])
{
if(argc != 2) {
std::cout << "Usage: " << argv[0] << " filename" << std::endl;
return 1;
}
print_bytes(argv[1]);
return 0;
}

29
lab1/print_argv.cc Normal file
View file

@ -0,0 +1,29 @@
#include <string>
#include <iostream>
using std::cout;
using std::endl;
/* Example program, printing command line arguments
* It is good practice to convert the C string
* i.e., "pointer to first element of a null-terminated
* array of char" to a std::string and then use the
* safer std::string instead of directly using the C-string.
*/
void print_string(std::string str)
{
cout << "[" << str << "] ";
}
int main(int argc, char** argv)
{
cout << "argc=" << argc << endl;
for(int i=0; i != argc; ++i){
std::string arg{argv[i]}; // create a std::string for the argument
print_string(arg); // pass the std::string to a functio
}
cout << endl;
return 0;
}

6
lab1/separate_fn.cc Normal file
View file

@ -0,0 +1,6 @@
#include <iostream>
void the_function(const std::string& s)
{
std::cout << "the_function: " << s << "\n";
}

3
lab1/separate_fn.h Normal file
View file

@ -0,0 +1,3 @@
#include <string>
void the_function(const std::string& s);

7
lab1/separate_main.cc Normal file
View file

@ -0,0 +1,7 @@
#include "separate_fn.h"
int main()
{
the_function("Called from main()");
exit(0);
}

56
lab1/test_coding.cc Normal file
View file

@ -0,0 +1,56 @@
#include <iostream>
#include "coding.h"
#include <string>
#include <cassert>
std::string do_encode(std::string s)
{
for(auto& c : s) {
c = encode(c);
}
return s;
}
std::string do_decode(std::string s)
{
for(auto& c: s) {
c = decode(c);
}
return s;
}
bool test_coding()
{
std::string str = "Testing, testing... I should be the same after encoding and decoding";
std::string enc = do_encode(str);
assert(enc.size() == str.size()); // sanity check for test program
bool result = true;
for(std::string::size_type i=0; i != enc.size(); ++i){
if(enc[i] == str[i]) {
std::cout << "enc == str in position " << i << std::endl;
result = false;
}
};
std::string dec = do_decode(enc);
assert(enc.size() == dec.size()); // sanity check for test program
if(str != dec) {
std::cout << "Expected: " << str << "(" << str.size() <<
")\nActual: " << dec << "(" << dec.size() << ")" << std::endl;
result = false;
}
return result;
}
int main()
{
if(test_coding()) {
std::cout << "Test passed." << std::endl;
} else {
std::cout << "Test failed." << std::endl;
}
return 0;
}

22
lab1/test_editor.cc Normal file
View file

@ -0,0 +1,22 @@
#include "editor.h"
#include <iostream>
void test_equals(Editor::size_type x, Editor::size_type y)
{
if(x != y) {
std::cout << "Wrong result: " << x << " != " << y << std::endl;
};
}
int main() {
Editor ed("...(...(...[...]...)...)...{...}...");
std::cout << "editor.size(): " << ed.get_size() << std::endl;
test_equals( ed.find_left_par(15), 11);
test_equals( ed.find_left_par(19), 7);
test_equals( ed.find_left_par(23), 3);
test_equals( ed.find_left_par(31), 27);
test_equals( ed.find_left_par(32), std::string::npos);
std::cout << "test done." << std::endl;
}