Skip to content
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

System error code handling and utiltity function cleanup #238

Merged
merged 5 commits into from
Oct 11, 2017

Conversation

saschazelzer
Copy link
Member

This PR addresses issues #191 and #220 and also contains further cleanup.

The first commit contains the actual fixes:

  • Correctly dinstinguish between C runtime library errors and Win32 API errors
  • Set errno to 0 before calling C runtime library functions
  • Use thread-safe strerrror variants if available

It also improves code sharing between the legacy and the new GTest test executable:

  • Pull out TestUtils.cpp for re-use in legacy and GTest tests
  • TestUtils.cpp changes:
    • Use temporary directory instead of "ProgramData" path on Windows
    • Added cross-platform mkdtemp and mkstemp functions for creating unique files and directories (originated from public domain and contributed by me with slight changes to another project a couple of years ago; now just copied here)
    • Added helper functions for creating temporary files and directories

The commit also adds unit tests for our internal filesystem related functions:

  • Create tests for cppmicroservices::fs functions. The tests are compiled for static builds only to avoid exporting internal functions.
  • Make the gtest-based test executable a proper bundle, in order to compile TestUtils.cpp.

For the above changes, I had to duplicate a little more code from the internal file-system code. Seeing that we then had almost the same content duplicated in the framework and the unit test code I wanted to get rid of that and make it reusable.

This is what the second commit contains:

  • Create an object library called "util" that contains framework independent utility code chared between bundles and tests. This includes file-system related functions, error handling routines, string manipulation routines.
  • Add the object library to all bundles and the two test drivers by default

Please note that virtually no new code was written, except for disentangling our C / Win32 error handling, using strerror_r etc. where appropriate, and writing new unit tests (GTest based).

@codecov-io
Copy link

codecov-io commented Sep 3, 2017

Codecov Report

Merging #238 into development will increase coverage by 5.15%.
The diff coverage is 78.92%.

Impacted file tree graph

@@               Coverage Diff               @@
##           development     #238      +/-   ##
===============================================
+ Coverage        77.58%   82.73%   +5.15%     
===============================================
  Files              117      188      +71     
  Lines             8011    13298    +5287     
===============================================
+ Hits              6215    11002    +4787     
- Misses            1796     2296     +500
Impacted Files Coverage Δ
framework/test/driver/ZipFile.h 94.11% <ø> (ø)
framework/src/service/ServiceObjects.cpp 67.7% <0%> (ø) ⬆️
framework/src/bundle/BundleThread.cpp 75.16% <0%> (+1.32%) ⬆️
framework/src/service/ServiceListeners.cpp 98.63% <100%> (ø) ⬆️
framework/test/bundles/libC1/TestBundleC1.cpp 88.29% <100%> (ø)
framework/src/bundle/BundleResourceContainer.cpp 95.41% <100%> (ø) ⬆️
...work/test/driver/BundleRegistryPerformanceTest.cpp 93.15% <100%> (ø)
framework/test/driver/ResourceCompilerTest.cpp 97.68% <100%> (ø)
framework/src/bundle/BundleUtils.cpp 100% <100%> (+13.04%) ⬆️
framework/test/driver/FrameworkTest.cpp 95.62% <100%> (ø)
... and 101 more

@saschazelzer saschazelzer requested a review from a team September 3, 2017 13:47
@saschazelzer saschazelzer self-assigned this Sep 3, 2017
set(CTEST_BUILD_FLAGS "-j")
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
# gcc in combination with gcov seems to consume a lot of memory
# and my lead to OOM error on Travis containers. Hence we compile
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: "my" -> "may"

bundleRegistry.Install(execPath, systemBundle.get());
}
}
catch (const std::exception& e)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the behavior to users will change since exceptions are now suppressed from failing to install embedded bundles. is this the right thing to do?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. That was not intended.

extern const char DIR_SEP;

// Get the path of the calling executable.
// Throws std::runtime_error is the path cannot be
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: "is" -> "if"


#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this #ifndef/#define WIN32_LEAN_AND_MEAN is in multiple places. it would be good to put it in a central location. perhaps in GlobalConfig.h?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need #126 resolved and have an internal global .h file (which is not included in public .h files) where we can place such defines.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that sounds good to me.


std::string GetLastWin32ErrorStr()
{
#ifdef US_PLATFORM_WINDOWS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this function is only intended to be called on Windows, I think it should only be visible to the compiler when building on Windows. perhaps move the #ifdef outside of the function body?
This has an added benefit of failing at compile time if this function is called from non-Windows code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look at that.

// This is the XSI strerror_r version
if (strerror_r(errno, errorString, sizeof errorString))
{
return "Unknown error";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strerror_r will return a error number indicating why it failed. It would be useful to return the error instead of "unknown".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could return errno as a number in the returned string (by saving it before calling strerror_r). I think returning the error code from a failing strerror_r call would be misleading, because it will mask the original error for which we wanted to retrieve the textual description.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I meant returning a string indicating why strerror_r failed.
According to the documentation for strerror_r it only returns a failure if errno is invalid or the string buffer isn't big enough.

}

US_MSVC_PUSH_DISABLE_WARNING(4715) // 'function' : not all control paths return a value
std::string GetExceptionStr(const std::exception_ptr& exc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The warning push pop can be removed with the following block.

std::string GetExceptionStr(const std::exception_ptr& exc)
{
  std::string exceptionStr;
  try
  {
    if(exc)
    {
      std::rethrow_exception(exc);
    }
  }
  catch (const std::exception& e)
  {
    exceptionStr = e.what();
  }
  catch (...)
  {
    exceptionStr=  "unknown";
  }
  return exceptionStr;
}

return std::string();
}

static const std::string s_CurrWorkingDir = InitCurrentWorkingDirectory();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not make this magic static inside the function?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code was just moved from a different file and not changed. We had a discussion about the actual code in the original PR. Basically, we need to call InitCurrentWorkingDirectory at a time when there is only the main thread running (during static init).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karthikreddy09 take a look at PR #216 for more information.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ... now I understand. Thanks for pointing to the previous discussion.

}
catch (const std::exception& e)
{
DIAG_LOG(*sink) << e.what();
// Let the exeception propagate all the way up to the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: "exeception"

}

// A cross-platform version of the POSIX mkdtemp function
char* mkdtemps_compat(char *tmpl, int suffixlen)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there's a lot of common code between mkdtemps_compat and mkstemps_compat that can be factored out to remove the duplication?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly for the same reason as above. Laziness, working on bugs or features, afraid of introducing regressions, ...


static const char validLetters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

// A cross-platform version of the mkstemps function
Copy link
Contributor

@ksubramz ksubramz Oct 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sascha, curious about why we need to be compatible with mkstemp (or mkdtemp), AFAIU, these are only called by our tests and if we drop the compatibility criterion, we could avoid passing "char *" and avoid using strlen() etc.

i.e. I think it's better to operate on std::string's instead of (less safe) C-style strings, use std::string methods and throw an exception from this function itself in-case of any error.

Copy link
Member Author

@saschazelzer saschazelzer Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The answer is a historical one. The code originates from the public domain on the Internet. As such it was C code, written to be compatible with mkstemp and friends by the original author. I only did very small changes initially (many years ago) and used the code as is in another project. It did its job well enough and I thought I would spend my time elsewhere instead of making it prettier for CppMicroServices.

Feel free to send a PR for C++ification or other improvements, but I think there is not much gain unless there is a bug of course.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Sounds good.


static const char validLetters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

// A cross-platform version of the mkstemps function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Sounds good.

@saschazelzer saschazelzer force-pushed the system-error-code-handling-cleanup branch from e6caf9b to 4fb25d9 Compare October 11, 2017 05:55
@saschazelzer saschazelzer merged commit 4fb25d9 into development Oct 11, 2017
@saschazelzer saschazelzer deleted the system-error-code-handling-cleanup branch October 29, 2017 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants