From be137101abf51bd228d235683b9834fb5762bcfe Mon Sep 17 00:00:00 2001 From: Attila Prokai Date: Wed, 19 Aug 2026 09:15:09 +0200 Subject: [PATCH 1/5] cldai: name the static dependencies instead of composing them "cmake: declare target link interfaces explicitly" (0b950dd1) made SC_ADDLIB publish its LINK_LIBRARIES as PUBLIC. That is the right change, but it is not compatible with the way src/cldai/CMakeLists.txt names its static dependency: SC_ADDLIB(stepdai-static STATIC SOURCES ${DAI_SRCS} LINK_LIBRARIES $-static) _libdeps holds one entry, steputils, so the generator expression is an elaborate way of writing steputils-static. While the dependency was linked privately it expanded once, on the link line of stepdai-static, and was correct. Published as PUBLIC it lands in INTERFACE_LINK_LIBRARIES and is evaluated again in every consumer, where it comes back out mangled and reaches the linker verbatim: LINK : fatal error LNK1104: cannot open file $ is the first consumer to hit it, so with BUILD_STATIC_LIBS=ON no schema executable links. Reproduced on develop tip - nothing after 0b950dd1 touches either file, so the static build is broken there too. Building the list with a foreach costs nothing, reads the same, and keeps working if _libdeps ever grows. The shared branch is untouched; this is inside if(BUILD_STATIC_LIBS). --- src/cldai/CMakeLists.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/cldai/CMakeLists.txt b/src/cldai/CMakeLists.txt index e37ac06d2..cc9979586 100644 --- a/src/cldai/CMakeLists.txt +++ b/src/cldai/CMakeLists.txt @@ -27,7 +27,16 @@ if(BUILD_SHARED_LIBS) endif() if(BUILD_STATIC_LIBS) - SC_ADDLIB(stepdai-static STATIC SOURCES ${DAI_SRCS} LINK_LIBRARIES $-static) + # Spell the static dependency names out rather than composing them with a + # generator expression. Since 0b950dd1 SC_ADDLIB publishes LINK_LIBRARIES as + # PUBLIC, so anything given here lands in INTERFACE_LINK_LIBRARIES and is + # re-evaluated in each consumer - where a nested $ comes back out + # mangled and reaches the linker verbatim. + set(_static_libdeps) + foreach(_libdep ${_libdeps}) + list(APPEND _static_libdeps ${_libdep}-static) + endforeach() + SC_ADDLIB(stepdai-static STATIC SOURCES ${DAI_SRCS} LINK_LIBRARIES ${_static_libdeps}) endif() # Local Variables: From fb506568aa35bdd559704c57230b6149c68fa890 Mon Sep 17 00:00:00 2001 From: Rob McDonald Date: Tue, 22 Sep 2026 17:30:40 -0700 Subject: [PATCH 2/5] ap203min: build STEPCode as static-only ExternalProject Update the ExternalProjectBuild example (the MWE for how OpenVSP consumes STEPCode) for the current CMake system: - Install to /sc-install via CMAKE_INSTALL_PREFIX; SC_INSTALL_PREFIX is no longer honored, so the install step tried to write to /usr/local. - Build static libraries only (BUILD_SHARED_LIBS=OFF, BUILD_STATIC_LIBS=ON) and link the -static archives in dependency order. - Define SC_STATIC for the consumer so Windows headers do not dllimport. - Declare BUILD_BYPRODUCTS so the Ninja generator works. - Pass through CMAKE_BUILD_TYPE (default Release), PIC, and macOS architecture/deployment target; disable Python generator and tests. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../ExternalProjectBuild/CMakeLists.txt | 52 +++---------- .../cmake/External_STEPCode.cmake | 78 +++++++++++++++---- 2 files changed, 73 insertions(+), 57 deletions(-) diff --git a/example/ap203min/ExternalProjectBuild/CMakeLists.txt b/example/ap203min/ExternalProjectBuild/CMakeLists.txt index 45cce97e9..5dd115cde 100644 --- a/example/ap203min/ExternalProjectBuild/CMakeLists.txt +++ b/example/ap203min/ExternalProjectBuild/CMakeLists.txt @@ -5,58 +5,19 @@ # freely copied in part or in full for any purpose. No acknowledgment is required # for the use of this file. # -project(AP203Minimum) cmake_minimum_required(VERSION 3.12) +project(AP203Minimum) INCLUDE( ExternalProject ) set(CMAKE_MODULE_PATH ${AP203Minimum_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) +# Sets STEPCODE_INSTALL_DIR, STEPCODE_INCLUDE_DIR, STEPCODE_LIBRARIES, +# STEPCODE_SYSTEM_LIBRARIES and STEPCODE_DEFINITIONS. INCLUDE( External_STEPCode ) -##### -# Variables ideally set by FindSTEPCode.cmake - -IF(NOT WIN32) - set( STEPCODE_LIBRARIES - ${STEPCODE_INSTALL_DIR}/lib/libstepcore.a - ${STEPCODE_INSTALL_DIR}/lib/libstepeditor.a - ${STEPCODE_INSTALL_DIR}/lib/libstepdai.a - ${STEPCODE_INSTALL_DIR}/lib/libsteputils.a - ${STEPCODE_INSTALL_DIR}/lib/libsdai_ap203.a - ) -ELSE() - set( STEPCODE_LIBRARIES - ${STEPCODE_INSTALL_DIR}/lib/libstepcore.lib - ${STEPCODE_INSTALL_DIR}/lib/libstepeditor.lib - ${STEPCODE_INSTALL_DIR}/lib/libstepdai.lib - ${STEPCODE_INSTALL_DIR}/lib/libsteputils.lib - ${STEPCODE_INSTALL_DIR}/lib/libsdai_ap203.lib - ${STEPCODE_INSTALL_DIR}/lib/libexpress.lib - ${STEPCODE_INSTALL_DIR}/lib/libexppp.lib - shlwapi.lib - ) -ENDIF() - MESSAGE( STATUS "STEPCODE_INSTALL_DIR: " ${STEPCODE_INSTALL_DIR} ) -set( STEPCODE_INCLUDE_DIR -${STEPCODE_INSTALL_DIR}/include/stepcode -${STEPCODE_INSTALL_DIR}/include/stepcode/clstepcore -${STEPCODE_INSTALL_DIR}/include/stepcode/cldai -${STEPCODE_INSTALL_DIR}/include/stepcode/clutils -${STEPCODE_INSTALL_DIR}/include/stepcode/cleditor -${STEPCODE_INSTALL_DIR}/include/schemas/sdai_ap203 -) - -# End of variables ideally set by FindSTEPCode.cmake -###### - - -include_directories( - ${STEPCODE_INCLUDE_DIR} -) - set(SRCS ../ap203min.cpp) set(HDRS ) @@ -65,8 +26,13 @@ add_executable( ${PROJECT_NAME} ${SRCS} ${HDRS}) add_dependencies( ${PROJECT_NAME} STEPCODE ) -target_link_libraries( ${PROJECT_NAME} +target_include_directories( ${PROJECT_NAME} PRIVATE ${STEPCODE_INCLUDE_DIR} ) + +target_compile_definitions( ${PROJECT_NAME} PRIVATE ${STEPCODE_DEFINITIONS} ) + +target_link_libraries( ${PROJECT_NAME} ${STEPCODE_LIBRARIES} + ${STEPCODE_SYSTEM_LIBRARIES} ) # Local Variables: diff --git a/example/ap203min/ExternalProjectBuild/cmake/External_STEPCode.cmake b/example/ap203min/ExternalProjectBuild/cmake/External_STEPCode.cmake index 08a5e306f..7ad31f5f0 100644 --- a/example/ap203min/ExternalProjectBuild/cmake/External_STEPCode.cmake +++ b/example/ap203min/ExternalProjectBuild/cmake/External_STEPCode.cmake @@ -1,24 +1,74 @@ +# +# Build STEPCode as an ExternalProject, static libraries only. +# +# This mirrors how OpenVSP builds STEPCode. After inclusion, the following +# variables are set for use by the consuming project: +# +# STEPCODE_INSTALL_DIR - install prefix of the STEPCode build +# STEPCODE_INCLUDE_DIR - include directories +# STEPCODE_LIBRARIES - full paths to static libraries, in link order +# STEPCODE_SYSTEM_LIBRARIES - platform libraries STEPCode depends on +# STEPCODE_DEFINITIONS - compile definitions required by consumers +# + +set( STEPCODE_INSTALL_DIR ${CMAKE_BINARY_DIR}/sc-install ) + +# Static libraries are named -static. Order matters for single-pass +# linkers: dependents before their dependencies. +set( STEPCODE_LIB_NAMES + sdai_ap203-static + stepeditor-static + stepcore-static + stepdai-static + steputils-static +) + +set( STEPCODE_LIBRARIES ) +foreach( _sclib ${STEPCODE_LIB_NAMES} ) + list( APPEND STEPCODE_LIBRARIES + ${STEPCODE_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${_sclib}${CMAKE_STATIC_LIBRARY_SUFFIX} ) +endforeach() + +set( STEPCODE_SYSTEM_LIBRARIES ) +if( WIN32 ) + set( STEPCODE_SYSTEM_LIBRARIES shlwapi ) +endif() + +set( STEPCODE_INCLUDE_DIR + ${STEPCODE_INSTALL_DIR}/include/stepcode + ${STEPCODE_INSTALL_DIR}/include/stepcode/clstepcore + ${STEPCODE_INSTALL_DIR}/include/stepcode/cldai + ${STEPCODE_INSTALL_DIR}/include/stepcode/clutils + ${STEPCODE_INSTALL_DIR}/include/stepcode/cleditor + ${STEPCODE_INSTALL_DIR}/include/schemas/sdai_ap203 +) + +# Consumers of the static libraries must define SC_STATIC, otherwise the +# headers declare everything __declspec(dllimport) on Windows. +set( STEPCODE_DEFINITIONS SC_STATIC ) + +if( CMAKE_BUILD_TYPE ) + set( STEPCODE_BUILD_TYPE ${CMAKE_BUILD_TYPE} ) +else() + set( STEPCODE_BUILD_TYPE Release ) +endif() + ExternalProject_Add( STEPCODE URL ${CMAKE_CURRENT_SOURCE_DIR}/../../.. CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} - -DCMAKE_BUILD_TYPE=Debug + -DCMAKE_BUILD_TYPE=${STEPCODE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX:PATH=${STEPCODE_INSTALL_DIR} + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} + -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} -DSC_BUILD_SCHEMAS=ap203/ap203.exp + -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON -DSC_PYTHON_GENERATOR=OFF - -DSC_INSTALL_PREFIX:PATH= + -DSC_ENABLE_TESTING=OFF + # Ninja must be told about every file a rule produces. + BUILD_BYPRODUCTS ${STEPCODE_LIBRARIES} ) -ExternalProject_Get_Property( STEPCODE SOURCE_DIR ) -ExternalProject_Get_Property( STEPCODE BINARY_DIR ) -ExternalProject_Get_Property( STEPCODE INSTALL_DIR ) - -IF( NOT WIN32 ) - SET( STEPCODE_INSTALL_DIR ${SOURCE_DIR}/../sc-install ) -ELSE() - SET( STEPCODE_INSTALL_DIR ${INSTALL_DIR} ) -ENDIF() - -SET( STEPCODE_BINARY_DIR ${BINARY_DIR} ) - From 3d855332bfd27bd037ac1fb79fe8dfcf824593e7 Mon Sep 17 00:00:00 2001 From: Rob McDonald Date: Tue, 22 Sep 2026 18:50:49 -0700 Subject: [PATCH 3/5] ap203min: test that the executable has no non-system dynamic deps Add CTest tests to the ExternalProject example: run AP203Minimum, and inspect it with otool -L (macOS), ldd (Linux) or dumpbin /dependents (Windows). The tool output is printed as a diagnostic; the test fails if any dependency is outside the system library locations, cannot be resolved, or looks like a STEPCode library. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../ExternalProjectBuild/CMakeLists.txt | 24 ++++ .../cmake/CheckStaticDeps.cmake | 128 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 example/ap203min/ExternalProjectBuild/cmake/CheckStaticDeps.cmake diff --git a/example/ap203min/ExternalProjectBuild/CMakeLists.txt b/example/ap203min/ExternalProjectBuild/CMakeLists.txt index 5dd115cde..9621f2461 100644 --- a/example/ap203min/ExternalProjectBuild/CMakeLists.txt +++ b/example/ap203min/ExternalProjectBuild/CMakeLists.txt @@ -35,6 +35,30 @@ target_link_libraries( ${PROJECT_NAME} ${STEPCODE_SYSTEM_LIBRARIES} ) +##### +# Tests: run the example, and verify it has no non-system dynamic dependencies. + +enable_testing() + +add_test( NAME run_ap203min COMMAND ${PROJECT_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) + +if( APPLE ) + find_program( STATIC_DEPS_TOOL otool ) +elseif( WIN32 ) + get_filename_component( _cxx_dir "${CMAKE_CXX_COMPILER}" DIRECTORY ) + get_filename_component( _linker_dir "${CMAKE_LINKER}" DIRECTORY ) + find_program( STATIC_DEPS_TOOL dumpbin HINTS ${_cxx_dir} ${_linker_dir} ) +else() + find_program( STATIC_DEPS_TOOL ldd ) +endif() + +add_test( NAME static_deps_ap203min + COMMAND ${CMAKE_COMMAND} + -DEXE=$ + -DTOOL=${STATIC_DEPS_TOOL} + -P ${AP203Minimum_SOURCE_DIR}/cmake/CheckStaticDeps.cmake ) + # Local Variables: # tab-width: 8 # mode: cmake diff --git a/example/ap203min/ExternalProjectBuild/cmake/CheckStaticDeps.cmake b/example/ap203min/ExternalProjectBuild/cmake/CheckStaticDeps.cmake new file mode 100644 index 000000000..a11704ed2 --- /dev/null +++ b/example/ap203min/ExternalProjectBuild/cmake/CheckStaticDeps.cmake @@ -0,0 +1,128 @@ +# +# Verify that an executable does not dynamically link anything except +# operating system and compiler runtime libraries. +# +# Usage: +# cmake -DEXE= -DTOOL= -P CheckStaticDeps.cmake +# +# The dependency tool's full output is printed as a diagnostic. The check +# fails if any dependency is not a system library, cannot be resolved, or +# looks like a STEPCode library. +# +cmake_minimum_required( VERSION 3.12 ) + +if( NOT EXE OR NOT EXISTS "${EXE}" ) + message( FATAL_ERROR "Executable not found: '${EXE}'" ) +endif() +if( NOT TOOL ) + message( FATAL_ERROR "No dependency tool (otool, ldd or dumpbin) was found." ) +endif() + +get_filename_component( _tool_name "${TOOL}" NAME_WE ) +string( TOLOWER "${_tool_name}" _tool_name ) + +if( _tool_name STREQUAL "otool" ) + set( _args -L "${EXE}" ) +elseif( _tool_name STREQUAL "ldd" ) + set( _args "${EXE}" ) +elseif( _tool_name STREQUAL "dumpbin" ) + set( _args /dependents "${EXE}" ) +else() + message( FATAL_ERROR "Unsupported dependency tool: ${TOOL}" ) +endif() + +execute_process( COMMAND "${TOOL}" ${_args} + OUTPUT_VARIABLE _out + ERROR_VARIABLE _err + RESULT_VARIABLE _res ) + +list( JOIN _args " " _args_str ) +message( "${TOOL} ${_args_str}\n${_out}${_err}" ) + +if( NOT _res EQUAL 0 ) + message( FATAL_ERROR "${TOOL} failed with exit code ${_res}" ) +endif() + +# Collect (name, resolved path) for each dependency. +set( _deps ) +set( _bad ) +string( REPLACE "\r" "" _out "${_out}" ) +string( REPLACE "\n" ";" _lines "${_out}" ) + +if( _tool_name STREQUAL "otool" ) + # First line is the executable itself; dependencies are indented. + foreach( _line ${_lines} ) + if( _line MATCHES "^[ \t]+([^ \t].*) \\(compatibility version" ) + set( _path "${CMAKE_MATCH_1}" ) + list( APPEND _deps "${_path}" ) + if( NOT _path MATCHES "^/usr/lib/" AND NOT _path MATCHES "^/System/Library/" ) + list( APPEND _bad "${_path}" ) + endif() + endif() + endforeach() + +elseif( _tool_name STREQUAL "ldd" ) + foreach( _line ${_lines} ) + string( STRIP "${_line}" _line ) + if( _line STREQUAL "" OR _line MATCHES "statically linked" ) + continue() + endif() + list( APPEND _deps "${_line}" ) + if( _line MATCHES "not found" ) + list( APPEND _bad "${_line}" ) + elseif( _line MATCHES "=> (/[^ ]+)" ) + set( _path "${CMAKE_MATCH_1}" ) + elseif( _line MATCHES "^(/[^ ]+)" ) + set( _path "${CMAKE_MATCH_1}" ) + else() + # Virtual DSO such as linux-vdso.so.1 has no file. + continue() + endif() + if( NOT _path MATCHES "^/(usr/)?lib(32|64|x32)?/" ) + list( APPEND _bad "${_line}" ) + endif() + endforeach() + +elseif( _tool_name STREQUAL "dumpbin" ) + set( _in_deps FALSE ) + foreach( _line ${_lines} ) + string( STRIP "${_line}" _line ) + if( _line MATCHES "has the following dependencies" ) + set( _in_deps TRUE ) + continue() + endif() + if( NOT _in_deps OR _line STREQUAL "" ) + continue() + endif() + if( _line MATCHES "^Summary" OR _line MATCHES "delay load" ) + break() + endif() + list( APPEND _deps "${_line}" ) + # System DLLs (including the MSVC and UCRT runtimes) live in System32. + file( TO_CMAKE_PATH "$ENV{SystemRoot}/System32/${_line}" _sys ) + if( NOT EXISTS "${_sys}" AND NOT _line MATCHES "^(api|ext)-ms-" ) + list( APPEND _bad "${_line}" ) + endif() + endforeach() +endif() + +if( NOT _deps ) + message( FATAL_ERROR "Could not parse any dependencies from ${TOOL} output." ) +endif() + +# Catch STEPCode libraries even if they were somehow installed system-wide. +foreach( _dep ${_deps} ) + get_filename_component( _name "${_dep}" NAME ) + if( _name MATCHES "(step(core|dai|utils|editor|lazyfile)|sdai_|express|exppp)" ) + list( APPEND _bad "${_dep}" ) + endif() +endforeach() + +list( LENGTH _deps _ndeps ) +if( _bad ) + list( REMOVE_DUPLICATES _bad ) + string( REPLACE ";" "\n " _bad "${_bad}" ) + message( FATAL_ERROR "Non-system dynamic dependencies found:\n ${_bad}" ) +endif() + +message( STATUS "OK: all ${_ndeps} dynamic dependencies are system libraries." ) From dc0689c11f12786c1ed84e513205060713abd2fc Mon Sep 17 00:00:00 2001 From: Rob McDonald Date: Tue, 22 Sep 2026 18:50:49 -0700 Subject: [PATCH 4/5] CI: build and test static AP203Min ExternalProject on all platforms Existing CI never exercises a static-only build, which is how OpenVSP consumes STEPCode. Build example/ap203min/ExternalProjectBuild on Linux (GCC, Clang), macOS, and Windows (MSVC with Ninja, and the default Visual Studio generator), check no shared libraries were produced, then run its tests: run AP203Minimum and check it has no non-system dynamic dependencies. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/ap203min.yml | 90 ++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .github/workflows/ap203min.yml diff --git a/.github/workflows/ap203min.yml b/.github/workflows/ap203min.yml new file mode 100644 index 000000000..44aadf620 --- /dev/null +++ b/.github/workflows/ap203min.yml @@ -0,0 +1,90 @@ +name: AP203Min static ExternalProject + +# Builds example/ap203min/ExternalProjectBuild, which builds STEPCode as a +# static-only ExternalProject the same way OpenVSP does, then runs the result. + +on: + workflow_dispatch: + push: + pull_request: + +jobs: + ap203min: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - name: Ubuntu GCC + os: ubuntu-latest + cc: gcc + cxx: g++ + generator: Ninja + - name: Ubuntu Clang + os: ubuntu-latest + cc: clang + cxx: clang++ + generator: Ninja + - name: macOS Clang + os: macos-latest + cc: clang + cxx: clang++ + generator: Ninja + - name: Windows MSVC Ninja + os: windows-latest + cc: cl + cxx: cl + generator: Ninja + - name: Windows Visual Studio + os: windows-latest + # Empty generator: CMake picks the newest installed Visual Studio. + generator: "" + defaults: + run: + shell: bash + steps: + - name: Setup - CMake and Ninja + uses: lukka/get-cmake@latest + + - name: Setup - MSVC + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + + - name: Checkout + uses: actions/checkout@v5 + + - name: Configure + run: | + # Build outside the checkout: the ExternalProject copies the whole source tree. + BUILD_DIR="$(cd .. && pwd)/ap203min-build" + echo "BUILD_DIR=$BUILD_DIR" >> "$GITHUB_ENV" + args=(-S example/ap203min/ExternalProjectBuild -B "$BUILD_DIR") + if [ -n "${{ matrix.generator }}" ]; then + args+=(-G "${{ matrix.generator }}") + fi + if [ -n "${{ matrix.cc }}" ]; then + args+=(-DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx }}) + fi + if [ "${{ matrix.generator }}" = "Ninja" ]; then + args+=(-DCMAKE_BUILD_TYPE=Release) + fi + cmake --version + cmake "${args[@]}" + grep CMAKE_GENERATOR: "$BUILD_DIR/CMakeCache.txt" + + - name: Build + run: cmake --build "$BUILD_DIR" --config Release + + - name: No shared libraries built + run: | + ls -l "$BUILD_DIR"/sc-install/lib + if ls "$BUILD_DIR"/sc-install/lib | grep -Ei '\.(so|dylib|dll)'; then exit 1; fi + if ls "$BUILD_DIR"/sc-install/bin | grep -Ei '\.dll$'; then exit 1; fi + + - name: Test (run, and check for non-system dynamic dependencies) + run: | + cd "$BUILD_DIR" + ctest -C Release -V --output-on-failure + test -s outfile.stp + head -20 outfile.stp From 4897d6118a9bd56cb52ca34c57459fc839cb2010 Mon Sep 17 00:00:00 2001 From: Rob McDonald Date: Tue, 22 Sep 2026 22:22:35 -0700 Subject: [PATCH 5/5] exp2cxx: don't free a SELECT type's tag while it is still in use TYPEselect_print() stores a tag in the type's clientData to mark it as being processed, then freed the tag on return while leaving clientData pointing at it. Later visits to the same type test clientData and read the freed tag, a heap-use-after-free reported by AddressSanitizer while generating ap203 and most other schemas. Keep the tag: it is the "processed" marker the recursion relies on, one small struct per SELECT type in a short-lived program. With AddressSanitizer, exp2cxx now runs cleanly over all 18 schemas in data/, and the generated code is otherwise unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/exp2cxx/selects.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/exp2cxx/selects.c b/src/exp2cxx/selects.c index f03b6e48f..c600dac6a 100644 --- a/src/exp2cxx/selects.c +++ b/src/exp2cxx/selects.c @@ -2012,7 +2012,8 @@ void TYPEselect_print( Type t, FILES * files, Schema schema ) { DAR - moved to TYPEprint_init() - to keep init info together. */ tag -> complete = 1; - free( tag ); + /* Don't free tag: it stays in the type's clientData as the marker that + this type has been processed, which the checks above rely on. */ } #undef BASE_SELECT