Bladeren bron

Merge pull request #1393 from open62541/feature/drmemory

Add DrMemory on appveyor and fix memleak on windows
Stefan Profanter 7 jaren geleden
bovenliggende
commit
3de3208811

+ 2 - 2
CMakeLists.txt

@@ -98,8 +98,8 @@ if (MSVC AND UA_ENABLE_FULL_NS0)
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8000000")
 endif()
 
-option(UA_ENABLE_VALGRIND_UNIT_TESTS "Use Valgrind to detect memory leaks when running the unit tests" OFF)
-mark_as_advanced(UA_ENABLE_VALGRIND_UNIT_TESTS)
+option(UA_ENABLE_UNIT_TESTS_MEMCHECK "Use Valgrind (Linux) or DrMemory (Windows) to detect memory leaks when running the unit tests" OFF)
+mark_as_advanced(UA_ENABLE_UNIT_TESTS_MEMCHECK)
 
 option(UA_ENABLE_NONSTANDARD_UDP "Enable udp extension (non-standard)" OFF)
 mark_as_advanced(UA_ENABLE_NONSTANDARD_UDP)

+ 4 - 2
appveyor.yml

@@ -75,10 +75,12 @@ install:
   # Download and build libcheck
   - appveyor DownloadFile https://github.com/Pro/check/releases/download/0.12.0_win/check.zip
   - 7z x check.zip -oc:\ >NUL
+  # Install DrMemory
+  - cinst drmemory
 
 before_build:
   # use MinGW64
-  - set PATH=C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin;%PATH%
+  - set PATH=C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin;C:\Program Files (x86)\Dr. Memory\bin;%PATH%
   # Workaround for CMake not wanting sh.exe on PATH for MinGW
   - set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
   # Miktex
@@ -159,7 +161,7 @@ build_script:
   - if "%CC_SHORTNAME%" == "vs2015" md build
   - if "%CC_SHORTNAME%" == "vs2015" cd build
   - if "%CC_SHORTNAME%" == "vs2015" echo. && echo "##### Testing %CC_NAME% with unit tests #####" && echo.
-  - if "%CC_SHORTNAME%" == "vs2015" cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=OFF -DUA_ENABLE_DISCOVERY=ON -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DCMAKE_LIBRARY_PATH=c:\check\lib -DCMAKE_INCLUDE_PATH=c:\check\include -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -G"%CC_NAME%" ..
+  - if "%CC_SHORTNAME%" == "vs2015" cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=OFF -DUA_ENABLE_DISCOVERY=ON -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_UNIT_TESTS_MEMCHECK=ON  -DCMAKE_LIBRARY_PATH=c:\check\lib -DCMAKE_INCLUDE_PATH=c:\check\include -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -G"%CC_NAME%" ..
   - if "%CC_SHORTNAME%" == "vs2015" %MAKE%
   - if "%CC_SHORTNAME%" == "vs2015" cmake --build . --target test-verbose --config debug
   # do not cache log

+ 12 - 4
tests/CMakeLists.txt

@@ -12,12 +12,16 @@ include_directories(${PROJECT_SOURCE_DIR}/tests/testing-plugins)
 #############################
 
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/tests)
-set(TESTS_BINARY_DIR ${CMAKE_BINARY_DIR}/bin/tests)
+if (MSVC)
+	set(TESTS_BINARY_DIR ${CMAKE_BINARY_DIR}/bin/tests/${CMAKE_BUILD_TYPE})
+else()
+	set(TESTS_BINARY_DIR ${CMAKE_BINARY_DIR}/bin/tests)
+endif()
 
 # Load CMake Packages
 find_package(Check REQUIRED)
 find_package(Threads REQUIRED)
-if(UA_ENABLE_VALGRIND_UNIT_TESTS)
+if(NOT MSVC AND UA_ENABLE_UNIT_TESTS_MEMCHECK)
     find_package(Valgrind REQUIRED)
 endif()
 
@@ -52,8 +56,12 @@ endif()
 # This also requires to disable the phtread cache with no-nptl-pthread-stackcache
 set(VALGRIND_FLAGS --quiet --trace-children=yes --leak-check=full --run-libc-freeres=no --sim-hints=no-nptl-pthread-stackcache)
 macro(add_test_valgrind TEST_NAME)
-    if(UA_ENABLE_VALGRIND_UNIT_TESTS)
-        add_test(${TEST_NAME} valgrind --error-exitcode=1 --suppressions=${PROJECT_SOURCE_DIR}/tools/valgrind_suppressions.supp ${VALGRIND_FLAGS} ${ARGN})
+    if(UA_ENABLE_UNIT_TESTS_MEMCHECK)
+        if(MSVC)
+            add_test(${TEST_NAME} drmemory -batch -exit_code_if_errors 1 -results_to_stderr -summary -- ${ARGN})
+        else()
+            add_test(${TEST_NAME} valgrind --error-exitcode=1 --suppressions=${PROJECT_SOURCE_DIR}/tools/valgrind_suppressions.supp ${VALGRIND_FLAGS} ${ARGN})
+        endif()
     else()
         add_test(${TEST_NAME} ${ARGN})
     endif()

+ 5 - 5
tools/nodeset_compiler/backend_open62541_datatypes.py

@@ -75,14 +75,14 @@ def generateNodeValueCode(node, instanceName, asIndirect=False, max_string_lengt
     if type(node) in [Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float, Double]:
         return "(UA_" + node.__class__.__name__ + ") " + str(node.value)
     elif type(node) == String:
-        return generateStringCode(node.value, asIndirect, max_string_length)
+        return generateStringCode(node.value, alloc=asIndirect, max_string_length=max_string_length)
     elif type(node) == XmlElement:
-        return generateXmlElementCode(node.value, asIndirect, max_string_length)
+        return generateXmlElementCode(node.value, alloc=asIndirect, max_string_length=max_string_length)
     elif type(node) == ByteString:
         # replace whitespaces between tags and remove newlines
-        return generateByteStringCode(re.sub(r">\s*<", "><", re.sub(r"[\r\n]+", "", node.value)), asIndirect, max_string_length)
+        return generateByteStringCode(re.sub(r">\s*<", "><", re.sub(r"[\r\n]+", "", node.value)), alloc=asIndirect, max_string_length=max_string_length)
     elif type(node) == LocalizedText:
-        return generateLocalizedTextCode(node, asIndirect, max_string_length)
+        return generateLocalizedTextCode(node, alloc=asIndirect, max_string_length=max_string_length)
     elif type(node) == NodeId:
         return generateNodeIdCode(node)
     elif type(node) == ExpandedNodeId:
@@ -90,7 +90,7 @@ def generateNodeValueCode(node, instanceName, asIndirect=False, max_string_lengt
     elif type(node) == DateTime:
         return generateDateTimeCode(node.value)
     elif type(node) == QualifiedName:
-        return generateQualifiedNameCode(node.value, asIndirect, max_string_length)
+        return generateQualifiedNameCode(node.value, alloc=asIndirect, max_string_length=max_string_length)
     elif type(node) == StatusCode:
         raise Exception("generateNodeValueCode for type " + node.__class__.name + " not implemented")
     elif type(node) == DiagnosticInfo:

+ 3 - 3
tools/nodeset_compiler/backend_open62541_nodes.py

@@ -480,8 +480,8 @@ def generateNodeCode(node, supressGenerationOfAttribute, generate_ns0, parentref
     elif isinstance(node, ViewNode):
         code.extend(generateViewNodeCode(node))
 
-    code.append("attr.displayName = " + generateLocalizedTextCode(node.displayName, max_string_length) + ";")
-    code.append("attr.description = " + generateLocalizedTextCode(node.description, max_string_length) + ";")
+    code.append("attr.displayName = " + generateLocalizedTextCode(node.displayName, alloc=False, max_string_length=max_string_length) + ";")
+    code.append("attr.description = " + generateLocalizedTextCode(node.description, alloc=False, max_string_length=max_string_length) + ";")
     code.append("attr.writeMask = %d;" % node.writeMask)
     code.append("attr.userWriteMask = %d;" % node.userWriteMask)
 
@@ -501,7 +501,7 @@ def generateNodeCode(node, supressGenerationOfAttribute, generate_ns0, parentref
     code.append(generateNodeIdCode(node.id) + ",")
     code.append(generateNodeIdCode(parentNode) + ",")
     code.append(generateNodeIdCode(parentRef) + ",")
-    code.append(generateQualifiedNameCode(node.browseName) + ",")
+    code.append(generateQualifiedNameCode(node.browseName, max_string_length=max_string_length) + ",")
     if isinstance(node, VariableTypeNode):
         # we need the HasSubtype reference
         code.append(generateSubtypeOfDefinitionCode(node) + ",")

+ 2 - 2
tools/travis/travis_linux_script.sh

@@ -198,7 +198,7 @@ else
     # Valgrind cannot handle the full NS0 because the generated file is too big. Thus run NS0 full without valgrind
     cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/$PYTHON -DUA_ENABLE_FULL_NS0=ON \
     -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_DISCOVERY=ON -DUA_ENABLE_DISCOVERY_MULTICAST=ON \
-    -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=OFF -DUA_ENABLE_VALGRIND_UNIT_TESTS=OFF ..
+    -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=OFF -DUA_ENABLE_UNIT_TESTS_MEMCHECK=OFF ..
     make -j && make test ARGS="-V"
     if [ $? -ne 0 ] ; then exit 1 ; fi
     cd .. && rm build -rf
@@ -208,7 +208,7 @@ else
     mkdir -p build && cd build
     cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/$PYTHON \
     -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_DISCOVERY=ON -DUA_ENABLE_DISCOVERY_MULTICAST=ON \
-    -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=ON -DUA_ENABLE_VALGRIND_UNIT_TESTS=ON ..
+    -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=ON -DUA_ENABLE_UNIT_TESTS_MEMCHECK=ON ..
     make -j && make test ARGS="-V"
     if [ $? -ne 0 ] ; then exit 1 ; fi
     echo -en 'travis_fold:end:script.build.unit_test_ns0_minimal\\r'

+ 1 - 1
tools/travis/travis_osx_script.sh

@@ -42,7 +42,7 @@ echo -en 'travis_fold:end:script.build.multithread\\r'
 
 echo "Debug build and unit tests with valgrind" && echo -en 'travis_fold:start:script.build.unit_test\\r'
 mkdir -p build && cd build
-cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_DISCOVERY=ON -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=ON -DUA_ENABLE_VALGRIND_UNIT_TESTS=ON ..
+cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_DISCOVERY=ON -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=ON -DUA_ENABLE_UNIT_TESTS_MEMCHECK=ON ..
 make -j && make test ARGS="-V"
 cd .. && rm -rf build
 echo -en 'travis_fold:end:script.build.unit_test\\r'