Azure / azure-iot-sdk-c

A C99 SDK for connecting devices to Microsoft Azure IoT services
https://azure.github.io/azure-iot-sdk-c
Other
580 stars 738 forks source link

unit tests rely on unspecified order-of-evaluation bahavior #2591

Closed jianyan-li-qnx closed 4 months ago

jianyan-li-qnx commented 4 months ago

Development Machine, OS, Compiler (and Other Relevant Toolchain Info) OS: QNX8 Raspberry Pi 4, gcc 12.1.0 QEMU x64, gcc 12.1.0

SDK Version (Please Give Commit SHA if Manually Compiling)

LTS_08_2023

Describe the Bug This issue occurs at several places in the unit tests, but let's look at prov_sc_delete_device_registration_state_GOLDEN_NO_ETAG in provisioning_service_client/tests/provisioning_service_client_ut/provisioning_service_client_ut.c as an example.

This test expects deviceRegistrationState_getEtag, deviceRegistrationState_getRegistrationId to be called in this order:

    STRICT_EXPECTED_CALL(deviceRegistrationState_getEtag(IGNORED_PTR_ARG)).SetReturn(NULL); //no etag
    STRICT_EXPECTED_CALL(deviceRegistrationState_getRegistrationId(IGNORED_PTR_ARG));

And this is the actual call site in prov_sc_delete_device_registration_state:

 prov_sc_delete_record_by_param(prov_client, deviceRegistrationState_getRegistrationId(reg_state), deviceRegistrationState_getEtag(reg_state), REG_STATE_PROVISION_PATH_FMT);

Notice that both mocks, deviceRegistrationState_getEtag and deviceRegistrationState_getRegistrationId, are arguments to a function.

This is what cppreference says about the order of evaluation of arguments (https://en.cppreference.com/w/c/language/eval_order):

Order of evaluation of the operands of any C operator, including the order of evaluation of function arguments in a function-call expression, and the order of evaluation of the subexpressions within any expression is unspecified (except where noted below). The compiler will evaluate them in any order, and may choose another order when the same expression is evaluated again.

Here you are making the assumption that deviceRegistrationState_getEtag will be called before deviceRegistrationState_getRegistrationId. In practice, this works for gcc-x86_64. _However, gcc-arm64 calls deviceRegistrationState_getRegistrationId before deviceRegistrationStategetEtag.

As a result, this test (along with several other tests) would fail on my raspberry pi.

ericwol-msft commented 4 months ago

2597

jianyan-li-qnx commented 4 months ago

That'll do, thanks.