Skip to content

Segfault avoidance #62

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Sep 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ AllCops:

# inherit_from: .rubocop_todo.yml

# TODO: stuff I actually want to fix
Style/RescueStandardError:
Enabled: false

Security/Open:
Enabled: false


# Extra lines for readability
Layout/EmptyLinesAroundClassBody:
Enabled: false
Expand Down Expand Up @@ -79,8 +87,16 @@ Style/RedundantSelf:
Style/StringLiterals:
Enabled: false

Style/TrailingCommaInLiteral:
Style/TrailingCommaInArrayLiteral:
Enabled: false

Style/TrailingCommaInHashLiteral:
Enabled: false

Style/SymbolArray:
Enabled: false

# because if the robot can comment better than me then
# it might as well learn to write the code for me
Style/CommentAnnotation:
Enabled: false
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- CPP library class now reaches into included Arduino libraries for source files
- SPI mocks
- `ensure_arduino_installation.rb` to allow custom libraries to be installed
- Copy constructor for `ArduinoCITable`
- Some error information on failures to download the Arduino binary

### Changed
- Refactored documentation
- External libraries aren't forcibly installed via the Arduino binary (in `arduino_cmd_remote.rb`) if they appear to exist on disk already
- `attachInterrupt` and `detachInterrupt` are now mocked instead of `_NOP`
- Unit test binaries now run with debugging symbols and address sanitization (if available), to help isolate the causes of segfaults
- `ArduinoCommand::libdir` logic is now centralized, using `sketchbook.path` from prefs instead of hard-coding

### Deprecated

Expand All @@ -24,6 +28,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Fixed
- OSX splash screen re-disabled
- ArduinoCITable didn't initialize its size on `clear()`
- CPP file aggregation now ignores dotfiles
- Unit test `compilers` section of YAML configuration is now properly inherited from parent configuration files
- Retrieving preferences is now properly cached
- Paths on Windows should now work due to the use of `Pathname`
- symlinking directories in Windows environments now properly uses `/D` switch to `mklink`

### Security

Expand Down
2 changes: 0 additions & 2 deletions SampleProjects/DoSomething/.arduino-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,3 @@ unittest:
- uno
- due
- leonardo
compilers:
- g++
7 changes: 5 additions & 2 deletions SampleProjects/TestSomething/.arduino-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ unittest:
platforms:
- uno
- due
compilers:
- g++

compile:
platforms:
- uno
- due
16 changes: 16 additions & 0 deletions SampleProjects/TestSomething/test/queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,20 @@ unittest(copy_constructor)
}
}

unittest(boundaries)
{
ArduinoCIQueue<int> q;
int data[2] = {11, 22};
for (int i = 0; i < 2; ++i) q.push(data[i]);

assertEqual(2, q.size());
q.pop();
assertEqual(1, q.size());
q.pop();
assertEqual(0, q.size());
q.pop();
assertEqual(0, q.size());

}

unittest_main()
37 changes: 35 additions & 2 deletions SampleProjects/TestSomething/test/table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ void setResult3(long l, int k, int v) {
}


unittest(basic_table)
{
unittest(basic_table) {
ArduinoCITable<String, int> t;
assertTrue(t.empty());

Expand All @@ -46,6 +45,40 @@ unittest(basic_table)

}

unittest(clear) {
ArduinoCITable<String, int> t1;
int data[5] = {11, 22, 33, 44, 55};

for (int i = 0; i < 5; ++i) {
t1.add(String(data[i]), data[i]);
}

assertEqual(5, t1.size());
t1.clear();
assertEqual(0, t1.size());
}

unittest(copy_construction) {
ArduinoCITable<String, int> t1;
int data[5] = {11, 22, 33, 44, 55};

for (int i = 0; i < 5; ++i) {
t1.add(String(data[i]), data[i]);
}

ArduinoCITable<String, int> t2 = t1;
t1.clear();
assertEqual(0, t1.size());
assertEqual(5, t2.size());

for (int i = 0; i < 5; ++i) {
assertTrue(t2.has(String(data[i])));
assertTrue(t2.remove(String(data[i])));
assertFalse(t2.has(String(data[i])));
}
assertEqual(0, t2.size());
}

unittest(iteration_no_arg) {
ArduinoCITable<int, int> t;
for (int i = 0; i < 5; ++i) {
Expand Down
2 changes: 1 addition & 1 deletion arduino_ci.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ Gem::Specification.new do |spec|

spec.add_development_dependency "bundler", "~> 1.15"
spec.add_development_dependency "rspec", "~> 3.0"
spec.add_development_dependency 'rubocop', '~>0.49.0'
spec.add_development_dependency 'rubocop', '~>0.59.0'
spec.add_development_dependency 'yard', '~>0.9.11'
end
2 changes: 1 addition & 1 deletion cpp/arduino/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class SPIClass: public ObservableDataStream {
advertiseByte((char)data);

// pop bus->memory data from its queue and return it
if (!dataIn->length()) return 0;
if (dataIn->empty()) return 0;
char ret = (*dataIn)[0];
*dataIn = dataIn->substr(1, dataIn->length());
return ret;
Expand Down
8 changes: 8 additions & 0 deletions cpp/arduino/ci/Table.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ class ArduinoCITable {
public:
ArduinoCITable() : mNilK(), mNilV() { init(); }

ArduinoCITable(const ArduinoCITable& obj) : mNilK(), mNilV() {
init();
for (Node* p = obj.mStart; p; p = p->next) {
add(p->key, p->val);
}
}

// number of things in the table
inline unsigned long size() const { return mSize; }

Expand Down Expand Up @@ -119,6 +126,7 @@ class ArduinoCITable {
mStart = mStart->next;
delete p;
}
mSize = 0;
}

~ArduinoCITable() { clear(); }
Expand Down
99 changes: 70 additions & 29 deletions exe/arduino_ci_remote.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#!/usr/bin/env ruby
require 'arduino_ci'
require 'set'
require 'pathname'

WIDTH = 80

@failure_count = 0
@passfail = proc { |result| result ? "✓" : "✗" }

# terminate after printing any debug info. TODO: capture debug info
def terminate(final = nil)
Expand All @@ -21,16 +23,17 @@ def terminate(final = nil)
end

# make a nice status line for an action and react to the action
def perform_action(message, multiline, on_fail_msg, abort_on_fail)
def perform_action(message, multiline, mark_fn, on_fail_msg, abort_on_fail)
line = "#{message}... "
endline = "...#{message} "
if multiline
puts line
else
print line
end
STDOUT.flush
result = yield
mark = result ? "" : "✗"
mark = mark_fn.nil? ? "" : mark_fn.call(result)
# if multline, put checkmark at full width
print endline if multiline
puts mark.rjust(WIDTH - line.length, " ")
Expand All @@ -45,17 +48,29 @@ def perform_action(message, multiline, on_fail_msg, abort_on_fail)

# Make a nice status for something that defers any failure code until script exit
def attempt(message, &block)
perform_action(message, false, nil, false, &block)
perform_action(message, false, @passfail, nil, false, &block)
end

# Make a nice status for something that defers any failure code until script exit
def attempt_multiline(message, &block)
perform_action(message, true, nil, false, &block)
perform_action(message, true, @passfail, nil, false, &block)
end

# Make a nice status for something that kills the script immediately on failure
def assure(message, &block)
perform_action(message, false, "This may indicate a problem with ArduinoCI, or your configuration", true, &block)
perform_action(message, false, @passfail, "This may indicate a problem with ArduinoCI, or your configuration", true, &block)
end

def assure_multiline(message, &block)
perform_action(message, true, @passfail, "This may indicate a problem with ArduinoCI, or your configuration", true, &block)
end

def inform(message, &block)
perform_action(message, false, proc { |x| x }, nil, false, &block)
end

def inform_multiline(message, &block)
perform_action(message, true, nil, nil, false, &block)
end

# Assure that a platform exists and return its definition
Expand All @@ -72,10 +87,23 @@ def assured_platform(purpose, name, config)
@arduino_cmd = ArduinoCI::ArduinoInstallation.autolocate!

# initialize library under test
installed_library_path = assure("Installing library under test") { @arduino_cmd.install_local_library(".") }
installed_library_path = attempt("Installing library under test") do
@arduino_cmd.install_local_library(Pathname.new("."))
end
if installed_library_path.exist?
inform("Library installed at") { installed_library_path.to_s }
else
assure_multiline("Library installed successfully") do
@arduino_cmd.lib_dir.ascend do |path_part|
next unless path_part.exist?

break puts path_part.find.to_a.to_s
end
false
end
end
library_examples = @arduino_cmd.library_examples(installed_library_path)
cpp_library = ArduinoCI::CppLibrary.new(installed_library_path, @arduino_cmd.lib_dir)
attempt("Library installed at #{installed_library_path}") { true }

# check GCC
compilers = config.compilers_to_use
Expand All @@ -84,6 +112,7 @@ def assured_platform(purpose, name, config)
attempt_multiline("Checking #{gcc_binary} version") do
version = cpp_library.gcc_version(gcc_binary)
next nil unless version

puts version.split("\n").map { |l| " #{l}" }.join("\n")
version
end
Expand Down Expand Up @@ -120,25 +149,33 @@ def assured_platform(purpose, name, config)

aux_libraries.each do |l|
if @arduino_cmd.library_present?(l)
assure("Using pre-existing library '#{l}'") { true }
inform("Using pre-existing library") { l.to_s }
else
assure("Installing aux library '#{l}'") { @arduino_cmd.install_library(l) }
end
end

# iterate boards / tests
last_board = nil
if cpp_library.test_files.empty?
attempt("Skipping unit tests; no test files were found") { true }
if !cpp_library.tests_dir.exist?
inform_multiline("Skipping unit tests; no tests dir at #{cpp_library.tests_dir}") do
puts cpp_library.tests_dir.find.to_a.to_s
true
end
elsif cpp_library.test_files.empty?
inform_multiline("Skipping unit tests; no test files were found in #{cpp_library.tests_dir}") do
puts cpp_library.tests_dir.find.to_a.to_s
true
end
elsif config.platforms_to_unittest.empty?
attempt("Skipping unit tests; no platforms were requested") { true }
inform("Skipping unit tests") { "no platforms were requested" }
else
config.platforms_to_unittest.each do |p|
board = all_platforms[p][:board]
assure("Switching to board for #{p} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
last_board = board
cpp_library.test_files.each do |unittest_path|
unittest_name = File.basename(unittest_path)
unittest_name = unittest_path.basename.to_s
compilers.each do |gcc_binary|
attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary}") do
exe = cpp_library.build_for_test_with_configuration(
Expand All @@ -161,26 +198,30 @@ def assured_platform(purpose, name, config)
end
end

unless library_examples.empty?
if library_examples.empty?
inform_multiline("Skipping libraries; no examples found in #{installed_library_path}") do
puts installed_library_path.find.to_a.to_s
end
else
attempt("Setting compiler warning level") { @arduino_cmd.set_pref("compiler.warning_level", "all") }
end

# unlike previous, iterate examples / boards
library_examples.each do |example_path|
ovr_config = config.from_example(example_path)
ovr_config.platforms_to_build.each do |p|
board = all_platforms[p][:board]
assure("Switching to board for #{p} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
last_board = board
example_name = File.basename(example_path)
attempt("Verifying #{example_name}") do
ret = @arduino_cmd.verify_sketch(example_path)
unless ret
puts
puts "Last command: #{@arduino_cmd.last_msg}"
puts @arduino_cmd.last_err
# unlike previous, iterate examples / boards
library_examples.each do |example_path|
ovr_config = config.from_example(example_path)
ovr_config.platforms_to_build.each do |p|
board = all_platforms[p][:board]
assure("Switching to board for #{p} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
last_board = board
example_name = File.basename(example_path)
attempt("Verifying #{example_name}") do
ret = @arduino_cmd.verify_sketch(example_path)
unless ret
puts
puts "Last command: #{@arduino_cmd.last_msg}"
puts @arduino_cmd.last_err
end
ret
end
ret
end
end
end
Expand Down
Empty file modified exe/ensure_arduino_installation.rb
100644 → 100755
Empty file.
Loading