Handle void pointers as pointer comparisons unless the array plugin gives more information. (Fixes #400)

This commit is contained in:
Mark VanderVoord
2026-06-16 21:34:32 -04:00
parent f756eeaf55
commit bad95c5f54
3 changed files with 190 additions and 0 deletions
+12
View File
@@ -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]
@@ -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);
}
...
+45
View File
@@ -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