From bad95c5f5412b7964bdb3211ceb4c8c45de53c13 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 16 Jun 2026 21:34:32 -0400 Subject: [PATCH] Handle void pointers as pointer comparisons unless the array plugin gives more information. (Fixes #400) --- lib/cmock_generator_utils.rb | 12 ++ .../void_pointer_no_array_plugin.yml | 133 ++++++++++++++++++ test/unit/cmock_generator_utils_test.rb | 45 ++++++ 3 files changed, 190 insertions(+) create mode 100644 test/system/test_interactions/void_pointer_no_array_plugin.yml diff --git a/lib/cmock_generator_utils.rb b/lib/cmock_generator_utils.rb index 52c3ca5..22e8aff 100644 --- a/lib/cmock_generator_utils.rb +++ b/lib/cmock_generator_utils.rb @@ -20,6 +20,7 @@ class CMockGeneratorUtils @ignore = @config.plugins.include? :ignore @ignore_stateless = @config.plugins.include? :ignore_stateless @treat_as = @config.treat_as + @treat_as_void = (['void'] + (@config.respond_to?(:treat_as_void) ? @config.treat_as_void : [])).uniq @helpers = helpers end @@ -155,12 +156,23 @@ class CMockGeneratorUtils unity_func = if (arg[:ptr?]) && ((c_type =~ /\*\*/) || (@ptr_handling == :compare_ptr)) ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] + elsif arg[:ptr?] && !@arrays && void_pointer_type?(c_type) + # void* cannot be safely dereferenced; without the array plugin there's no way + # to specify depth, so fall back to comparing the pointer value itself + ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] else @helpers.nil? || @helpers[:unity_helper].nil? ? ['UNITY_TEST_ASSERT_EQUAL', ''] : @helpers[:unity_helper].get_helper(c_type) end [c_type, arg_name, expected, ignore, unity_func[0], unity_func[1]] end + def void_pointer_type?(c_type) + base = c_type.gsub(/\bconst\b/, '').gsub(/\s+/, '') + return false unless base.end_with?('*') + + @treat_as_void.include?(base.chomp('*')) + end + def ptr_to_array_elem_size(arg, c_type) # For pointer-to-array args (e.g., char (*buf)[10]), the element size is sizeof(base_type[dims]) if arg[:ptr_to_array?] && arg[:array_dims] diff --git a/test/system/test_interactions/void_pointer_no_array_plugin.yml b/test/system/test_interactions/void_pointer_no_array_plugin.yml new file mode 100644 index 0000000..79a8154 --- /dev/null +++ b/test/system/test_interactions/void_pointer_no_array_plugin.yml @@ -0,0 +1,133 @@ +# ========================================================================= +# CMock - Automatic Mock Generation for C +# ThrowTheSwitch.org +# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams +# SPDX-License-Identifier: MIT +# ========================================================================= + +--- +#The purpose of this test is to verify that void* arguments use pointer +#comparison (not byte dereferencing) when the array plugin is not active. +#Dereferencing void* is illegal in C, so the mock must fall back to +#comparing pointer values via UNITY_TEST_ASSERT_EQUAL_PTR. +:cmock: + :plugins: [] + :treat_as_void: + - MY_VOID + +:systest: + :types: | + typedef void MY_VOID; + + :mockable: | + void get_v_ptr(void* ptr); + void get_const_v_ptr(const void* ptr); + void get_my_void_ptr(MY_VOID* ptr); + + :source: + :header: | + void function_a(void* arg); + void function_b(const void* arg); + void function_c(MY_VOID* arg); + + :code: | + void function_a(void* arg) { + get_v_ptr(arg); + } + + void function_b(const void* arg) { + get_const_v_ptr(arg); + } + + void function_c(MY_VOID* arg) { + get_my_void_ptr(arg); + } + + :tests: + :common: | + void setUp(void) {} + void tearDown(void) {} + + :units: + - :pass: TRUE + :should: 'handle void pointer expect passing when same pointer used' + :code: | + test() + { + char* a = "Hello"; + get_v_ptr_Expect(a); + function_a(a); + } + + - :pass: FALSE + :should: 'detect void pointer mismatch when different pointers used even with same content' + :code: | + test() + { + static char a[] = "Hello"; + static char b[] = "Hello"; + get_v_ptr_Expect(a); + function_a(b); + } + + - :pass: TRUE + :should: 'handle null void pointer expect passing' + :code: | + test() + { + get_v_ptr_Expect(NULL); + function_a(NULL); + } + + - :pass: FALSE + :should: 'detect null vs non-null void pointer mismatch' + :code: | + test() + { + char* a = "Hello"; + get_v_ptr_Expect(NULL); + function_a(a); + } + + - :pass: TRUE + :should: 'handle const void pointer expect passing when same pointer used' + :code: | + test() + { + char* a = "Hello"; + get_const_v_ptr_Expect(a); + function_b(a); + } + + - :pass: FALSE + :should: 'detect const void pointer mismatch when different pointers used' + :code: | + test() + { + static char a[] = "Hello"; + static char b[] = "Hello"; + get_const_v_ptr_Expect(a); + function_b(b); + } + + - :pass: TRUE + :should: 'handle treat_as_void alias pointer expect passing when same pointer used' + :code: | + test() + { + char* a = "Hello"; + get_my_void_ptr_Expect(a); + function_c(a); + } + + - :pass: FALSE + :should: 'detect treat_as_void alias pointer mismatch when different pointers used' + :code: | + test() + { + static char a[] = "Hello"; + static char b[] = "Hello"; + get_my_void_ptr_Expect(a); + function_c(b); + } +... diff --git a/test/unit/cmock_generator_utils_test.rb b/test/unit/cmock_generator_utils_test.rb index 286c703..a6a3f57 100644 --- a/test/unit/cmock_generator_utils_test.rb +++ b/test/unit/cmock_generator_utils_test.rb @@ -401,4 +401,49 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do @unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_MY_TYPE_ARRAY', '&'], ['MY_TYPE'] assert_equal(expected, @cmock_generator_utils_complex.code_verify_an_arg_expectation(function, arg)) end + + # void* tests without array plugin (when_ptr: :compare_data) - these must use pointer + # comparison because dereferencing void* is illegal in C + it 'handle void pointer comparison without array plugin by using pointer comparison' do + config_stub = create_stub({ + when_ptr: :compare_data, + enforce_strict_ordering: false, + plugins: [], + treat_as: {'void*' => 'HEX8_ARRAY', 'void const*' => 'HEX8_ARRAY', 'const void*' => 'HEX8_ARRAY'}, + treat_as_void: [] + }) + utils = CMockGeneratorUtils.new(config_stub, {:unity_helper => @unity_helper}) + function = { :name => 'Pear' } + + [ + {:type => "void*", :name => 'MyVoidPtr', :ptr? => true, :const? => false, :const_ptr? => false}, + {:type => "const void*", :name => 'MyConstVoidPtr', :ptr? => true, :const? => true, :const_ptr? => false}, + {:type => "void const*", :name => 'MyVoidConstPtr', :ptr? => true, :const? => false, :const_ptr? => true}, + ].each do |arg| + expected = " {\n" + + " UNITY_SET_DETAILS(CMockString_Pear,CMockString_#{arg[:name]});\n" + + " UNITY_TEST_ASSERT_EQUAL_PTR(cmock_call_instance->Expected_#{arg[:name]}, #{arg[:name]}, cmock_line, CMockStringMismatch);\n" + + " }\n" + assert_equal(expected, utils.code_verify_an_arg_expectation(function, arg)) + end + end + + it 'handle treat_as_void alias pointer comparison without array plugin by using pointer comparison' do + config_stub = create_stub({ + when_ptr: :compare_data, + enforce_strict_ordering: false, + plugins: [], + treat_as: {'MY_VOID*' => 'HEX8_ARRAY'}, + treat_as_void: ['MY_VOID'] + }) + utils = CMockGeneratorUtils.new(config_stub, {:unity_helper => @unity_helper}) + function = { :name => 'Pear' } + + arg = {:type => "MY_VOID*", :name => 'MyVoidAliasPtr', :ptr? => true, :const? => false, :const_ptr? => false} + expected = " {\n" + + " UNITY_SET_DETAILS(CMockString_Pear,CMockString_MyVoidAliasPtr);\n" + + " UNITY_TEST_ASSERT_EQUAL_PTR(cmock_call_instance->Expected_MyVoidAliasPtr, MyVoidAliasPtr, cmock_line, CMockStringMismatch);\n" + + " }\n" + assert_equal(expected, utils.code_verify_an_arg_expectation(function, arg)) + end end