Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime Error in MQTTPacket_formatPayload Due to char Type Not Defaulting to Unsigned in MSVC 193833134 (Visual Studio 2022) #1565

Open
liuyuanlins opened this issue Jan 17, 2025 · 4 comments
Assignees
Labels
Milestone

Comments

@liuyuanlins
Copy link

liuyuanlins commented Jan 17, 2025

Issue Description:

Compilation Environment: Visual Studio 2022
Compiler Version: MSVC 193833134

In the file paho.mqtt.c\src\MQTTPacket.c, the function:

int MQTTPacket_formatPayload(int buflen, char* buf, int payloadlen, char* payload)

at line 863:

if (isprint(payload[i]))

the isprint causes an error during debugging with the isprint function. This is because the compiler does not default the char type to unsigned, as shown in the attached image.

Image
convert isclype.cpp Line: 36 Expression:c>=-1&&c<= 255

@robinstampa
Copy link

robinstampa commented Feb 7, 2025

The problem here is that the behavior for isprint(ch) is undefined for anything outside ch >= -1 && ch <= 255 per C standard:

The behavior is undefined if the value of ch is not representable as unsigned char and is not equal to EOF. 1

Therefore, the CRT debug library correctly throws an assertion error if the character is outside this range to prevent undefined behavior:

When a debug CRT library is used and c isn't one of these values, the functions raise an assertion. 2

The problem is that although int isprint( int ch ); accepts an int, one must make sure parameter ch is not outside the allowed range.

Following code locations might produce the same issue:

Footnotes

  1. https://en.cppreference.com/w/c/string/byte/isprint

  2. See last paragraph of 'Return value'

  3. Same situation: undefined behavior

@icraggs
Copy link
Contributor

icraggs commented Feb 11, 2025

It does feel a little odd to accept an int but only be valid for an unsigned char!

I presume a cast to unsigned char would work in this case ...

@icraggs icraggs added this to the 1.3.15 milestone Feb 11, 2025
@icraggs icraggs added the bug label Feb 11, 2025
@sergeibobyr
Copy link

sergeibobyr commented Feb 16, 2025

Is this a new issue? (I see the code that calls isprint() was added 2 months ago...) I was happily using vcpkg paho-mqttpp3 dependency for a while now and just now decided to update vcpkg baseline to the latest. That pulled everything latest, and now I get this error when trying to run my client. Is the workaround going back to the older version? If yes, can you recommend which one?

I'm using protobuf for the payload (the publish method accepts a byte array) and the 'c' it fails on for me has a value -102 but the exact number is obviously irrelevant.

This happens on the async send thread:
Not Flagged > 26128 0 Worker Thread paho-mqtt3as.dll!_MQTTAsync_sendThread@4() ucrtbased.dll!_chvalidator

The error:

Debug Assertion Failed!
Program: xxxxx.exe
File: minkernel\crts\ucrt\src\appcrt\convert\isctype.cpp
Line: 36
Expression: c >= -1 && c <= 255

The call stack:

ucrtbased.dll!_chvalidator(int c, int mask) Line 36 C++
ucrtbased.dll!fast_check_initial_locale(const int c, const int mask) Line 22 C++
ucrtbased.dll!fast_check_current_locale(const int c, const int mask) Line 33 C++
ucrtbased.dll!isprint(int c) Line 198 C++
paho-mqtt3as.dll!MQTTPacket_formatPayload(int buflen, char * buf, int payloadlen, char * payload) Line 863 C
paho-mqtt3as.dll!MQTTPacket_send_publish(Publish * pack, int dup, int qos, int retained, networkHandles * net, const char * clientID) Line 956 C
paho-mqtt3as.dll!MQTTProtocol_startPublishCommon(Clients * pubclient, Publish * publish, int qos, int retained) Line 154 C
paho-mqtt3as.dll!MQTTProtocol_startPublish(Clients * pubclient, Publish * publish, int qos, int retained, Messages * * mm) Line 189 C
paho-mqtt3as.dll!MQTTAsync_processCommand() Line 1472 C
paho-mqtt3as.dll!MQTTAsync_sendThread(void * n) Line 1844 C

The 'char' in this function signature 'int MQTTPacket_formatPayload(int buflen, char* buf, int payloadlen, char* payload)' can obviously be any byte character. To be honest, I'm surprised the isprint() has an assert in debug version. Like was mentions already it should be cast to 'unsighned char' to safely call isprint():

Like all other functions from , the behavior of std::isprint is undefined if the argument's value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char:

bool my_isprint(char ch)
{
return std::isprint(static_cast(ch));
}

@icraggs
Copy link
Contributor

icraggs commented Feb 17, 2025

Yes, it was introduced two months ago. The previous version 1.3.13 doesn't have it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants