QByteArray not initializing
-
Oddly enough i dont crash here
it just converts to 32 values each time.
-
@aha_1980 this crash is occurring on the second iteration through the loop, so I don't think it's an array/string overrun.
@mzimmers
Hi
Can you try
// QCoreApplication a(argc, argv);
// a.exec();
and just return 0;You are not sending it a close signal so i think crash is due to killing it with debugger.
At least i cannot crash it without running the coreapp and exec().
-
@mrjj yeah, I'm pretty sure my loops are OK. I honestly don't know what's going on -- maybe some weird bug in the constructor.
I removed the core app stuff...same results.
I think I'll implement aha_1980's suggestion. I took another look, and it's a lot simpler than this. I'll report back on how I do with it.
-
@mrjj yeah, I'm pretty sure my loops are OK. I honestly don't know what's going on -- maybe some weird bug in the constructor.
I removed the core app stuff...same results.
I think I'll implement aha_1980's suggestion. I took another look, and it's a lot simpler than this. I'll report back on how I do with it.
-
I'm on Windows 10, using MinGW, FWIW. Just tried null terminating the string myself, and still bombs in the loop (though aha's suggestion works).
-
@mrjj here's the code in its entirety:
#include <QByteArray> #include <QDebug> #include <QCoreApplication> #include <QMessageAuthenticationCode> #include <QCryptographicHash> int test(char *key, char *txt, char *mac); int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); char Key8[] = "60e431591ee0b67f0d8a26aacbf5b77f" // arbitrary key "8e0bc6213728c5140546040f0ee37f54"; char Txt8[] = // Len = 1054 BYTES "e5098b6a0b1cfc57c6a76537104a39c48baecb15c6bbb46fbb0b745f9c9e5c05" "cfcfabb33786f7b7b5b0ce74eeec9eb84f87d2494fab3ec1f4d3bd9c99821890" "ee352a1d40964264fbf2c93c6ded2583cc75dcb27bf4fdb489cabcf97bfa5cc6" "4b2352cfb0b3a707a0579eb713b697cd0b5e3377d1feb9f181d7b89cc86dee4f" "ed8269f10e44ec48adc6940c6badbb40122c1dc2d9323920e4e1fbad0b4397d4" "dc38b8ade3b3dace2926f464fa3b5b82ebc5e3b81cf647e8bbd2cb55c9e31ffd" "212f8729b66739421c6106e64ac83d3b9e13cd8321b3a9f10d9171bb8cb74e71" "c34d1e8d0fc8d14b8e5e12bbe2bd2a1431fc224b70d228e4e2063509db26ecd9" "ca7cc402763e69928805600a4a80eab4ae6a2c3792b98c6942195e643f98c0dc" "3fa3c2b07431cbbe113e38fc0b7b45c51c4431700ed29d2736b236f63f759323" "29aa60be9009bd7832f1e1b9ac1503ec84727a1e6c8423c7c5b903e763262d55" "9078e654532e0868f206a468b5b5ebd3eddb4f673536e5f0f8160e5f3311561b" "7cf79c9c440974355965c931aec5c7225f69f776f052ac4bd6b19f85389fd61d" "f60ecabbeb00c8886ff7983d20ac5d81e303bc71253f40806772fd81f9387402" "05a5b7dcd07cce083da258b493d275967f91e4815d656936b342727cfe45f973" "b2a5ac257ce64c5eca4f53be8d9fd90c3dfcb8cd1e2cef15c307449ed02c2e17" "04f4f1be76a40b311ee7cf81987b5089252a807ef3fc99c79eabbc0ef657d897" "037bced04620d32a425015283bcea1b53e0484bb613d30f14c1422f5f82cc29a" "b7228b8375c06bf13d746dd9ff00953a90720badf2577d3ed62cbe7a5f15b3c9" "29d26ffe8aee9d2d17391ebc6a79f4bd235d5f7b2db2455343d9d7c6b27972cc" "6071c36a0d112f86d98972fb06a186e900abc64e9ab653db9b05b70079c0c84a" "64e8cfee8690eaa68a4bafbb5be112632e46894ec2cc6e7ce697a4513d517deb" "3e20dbb37ed5963232671e27ef9f62d6b514f0a22c5a5dde2d77e7e184965958" "f5002fe17d47fbd5d9c407644d443ce89eff427360cae9aa788dc8d7d9f62439" "916f139f094ee035884cb29dfa396941f0eec9e8e782da88cdc18e5bc1d9a535" "1b57ce15ac520ffa47e666f87fe5b18ab3c8cb2a48ecf81f36fb8397c6a7a5f5" "9a9fa96cedbb4ecd1c7a6d9d65afdb6bef7791600b6e0a18ba23edb06fc9ec21" "162feccc54f2665611f10db53401b18bade263b3b972da1a612115d144a54260" "97efdf5c6a5d1f3c2d318f687242f993f5f1884bd95f2ece34dd4320cea46f5a" "26c7c945b665402778233bdda9d97c2acd8c4a4ff39dcfdc3a3fbfc5942e3ab8" "ca9ff4aec17293c1fbaf583d603002f93f9befe8909485eb7c30d0e91fac6c22" "8c5fa6c011eddeafbdbe30af20ae53a85206c03d37ac17a30096bfb4f584cd3f" "72ef28a3303cea9cc636095c70bb36de0eb50577704d4faed05bd54da020"; char Mac8[] = // HMAC_SHA256 7.3728=410ms 18.4320= "4a0ce2f8ffca9e77443e661c88ccdc04ba6ac9bb901642fadae7fe8e4c2d50f7"; test(Key8, Txt8, Mac8); return a.exec(); } int test(char *key, char *txt, char *mac) { QByteArray qKey; QByteArray qTxt; QByteArray qMac; uint8_t c; char *p; uint32_t n; n = strlen(txt); for (uint32_t i = 0; i < n; i += 2) { p = txt + i; sscanf(p, "%2x", (int *) &c); qTxt.append((char) c); } n = strlen(key); for (uint32_t i = 0; i < n; i +=2) { p = key + i; sscanf(p, "%2x", (int *) &c); qKey.append((char) c); } n = strlen(mac); for (uint32_t i = 0; i < n; i +=2) { p = mac + i; sscanf(p, "%2x", (int *) &c); qMac.append((char) c); } QMessageAuthenticationCode auth(QCryptographicHash::Sha256, qKey); auth.addData(qTxt, 1054); qMac = auth.result(); return (strcmp(qMac.data(), mac) == 0); }qTxt and qKey work perfectly.
EDIT:
I'm aware that the strlen calls might not work right all the time, but they seem to be OK in this example. There's something wrong with my qMac variable, at least in the eyes of the debugger.
@mzimmers said in QByteArray not initializing:
@mrjj here's the code in its entirety:
uint8_t c; sscanf(p, "%2x", (int *) &c);cholds a 8-bitint, right? Firstly that's not right for(int *) &c, and secondly look atsscanf("%2x", it will expect the address of a wholeint(32-bit? 64-bit?) to store its result. So you're overwriting the local stack space, hence possible crashing? Or,uint8_tis allocated on an odd address boundary, which won't be good.Make
cbe a properint, or fix yoursscanf.Your understanding of
QByteArrayis fine, but not ofscanf:-)Also, if you use
QByteArray::fromHex(), you won't need to usesscanf:) -
@mzimmers said in QByteArray not initializing:
@mrjj here's the code in its entirety:
uint8_t c; sscanf(p, "%2x", (int *) &c);cholds a 8-bitint, right? Firstly that's not right for(int *) &c, and secondly look atsscanf("%2x", it will expect the address of a wholeint(32-bit? 64-bit?) to store its result. So you're overwriting the local stack space, hence possible crashing? Or,uint8_tis allocated on an odd address boundary, which won't be good.Make
cbe a properint, or fix yoursscanf.Your understanding of
QByteArrayis fine, but not ofscanf:-)Also, if you use
QByteArray::fromHex(), you won't need to usesscanf:) -
@mzimmers said in QByteArray not initializing:
@mrjj here's the code in its entirety:
uint8_t c; sscanf(p, "%2x", (int *) &c);cholds a 8-bitint, right? Firstly that's not right for(int *) &c, and secondly look atsscanf("%2x", it will expect the address of a wholeint(32-bit? 64-bit?) to store its result. So you're overwriting the local stack space, hence possible crashing? Or,uint8_tis allocated on an odd address boundary, which won't be good.Make
cbe a properint, or fix yoursscanf.Your understanding of
QByteArrayis fine, but not ofscanf:-)Also, if you use
QByteArray::fromHex(), you won't need to usesscanf:)@JNBarchan
Thats a really good observation and might explain why
no crashing here 64bit. Completely overlooked it :)

-
@JNBarchan the pointer should be OK, as far as I can see. Your point about the sscanf() overwriting the output buffer may be valid, though it's really odd that the first two loops worked fine.
@mzimmers said in QByteArray not initializing:
@JNBarchan the pointer should be OK
What pointer, and what do you mean by "OK"?
P.S. I can explain why it goes through sometimes and fails others, but it's going to mean quite a bit of typing, do you really want to know?
-
@JNBarchan
Thats a really good observation and might explain why
no crashing here 64bit. Completely overlooked it :)

-
@mzimmers said in QByteArray not initializing:
@JNBarchan the pointer should be OK
What pointer, and what do you mean by "OK"?
P.S. I can explain why it goes through sometimes and fails others, but it's going to mean quite a bit of typing, do you really want to know?
@JNBarchan in this line of code:
sscanf(p, "%2x", (int *) &c);the address formed by the cast should be fine, as far as I can tell.
I agree the problem is in the sscanf. This line of code:
sscanf(p, "%hhx", &c);compiles but doesn't work right (c keeps getting 0xff). I'm going to go with aha_1980's approach and call it a day.
Thanks to everyone who looked at this.
-
@JNBarchan in this line of code:
sscanf(p, "%2x", (int *) &c);the address formed by the cast should be fine, as far as I can tell.
I agree the problem is in the sscanf. This line of code:
sscanf(p, "%hhx", &c);compiles but doesn't work right (c keeps getting 0xff). I'm going to go with aha_1980's approach and call it a day.
Thanks to everyone who looked at this.
@mzimmers said in QByteArray not initializing:
@JNBarchan in this line of code:
sscanf(p, "%2x", (int *) &c);the address formed by the cast should be fine, as far as I can tell.
The address is indeed a valid address, but it points to an area reserved to hold one byte and you're storing 4 or 8 bytes there, which is very naughty! Hope you understand.
-
@mzimmers said in QByteArray not initializing:
@JNBarchan in this line of code:
sscanf(p, "%2x", (int *) &c);the address formed by the cast should be fine, as far as I can tell.
The address is indeed a valid address, but it points to an area reserved to hold one byte and you're storing 4 or 8 bytes there, which is very naughty! Hope you understand.
@JNBarchan said in QByteArray not initializing:
which is very naughty!
Buffer overflows - the pinnacle of C programming ... ;)
-
@JNBarchan said in QByteArray not initializing:
which is very naughty!
Buffer overflows - the pinnacle of C programming ... ;)
@kshegunov I expected the "%2x" in the sscanf to restrict output to one byte (2 hex characters), but I guess it doesn't work that way.
-
@kshegunov I expected the "%2x" in the sscanf to restrict output to one byte (2 hex characters), but I guess it doesn't work that way.
Not really, no. There's no compile-time type checking with variadic functions (which
scanfand related are). It will expect you to give it a proper integer to write to. But really your error is the cast itself. You can't cast pointers like this. You have acharon the stack and you cast its address to aint *. From there on the compiler will consider that this pointer is referencing an integer, meaning you have "hijacked" 3 bytes from the nearby variables in the stack. If you modify your code like this:uint8_t c, c2, c3, c4; // ... sscanf(p, "%2x", (int *) &c); // ...You'd discover that all those variables -
c2,c3andc4are modified alongside your originalcbecausesscanfoverruns the given buffer and writes outside of it. -
The original code has:
QByteArray qMac; uint8_t c;My guess is
qMacis stored abovecin the local stack. When you write to&cyou cobble what's inqMac, so the bug doesn't show up till you reach theqMacloop. ThenqMac.append((char) c);gets evaluated and crashes. Am I right?Behaviour could vary across 32/64 size and specific compiler allocation or register code generated.
-
The original code has:
QByteArray qMac; uint8_t c;My guess is
qMacis stored abovecin the local stack. When you write to&cyou cobble what's inqMac, so the bug doesn't show up till you reach theqMacloop. ThenqMac.append((char) c);gets evaluated and crashes. Am I right?Behaviour could vary across 32/64 size and specific compiler allocation or register code generated.
-
Not really, no. There's no compile-time type checking with variadic functions (which
scanfand related are). It will expect you to give it a proper integer to write to. But really your error is the cast itself. You can't cast pointers like this. You have acharon the stack and you cast its address to aint *. From there on the compiler will consider that this pointer is referencing an integer, meaning you have "hijacked" 3 bytes from the nearby variables in the stack. If you modify your code like this:uint8_t c, c2, c3, c4; // ... sscanf(p, "%2x", (int *) &c); // ...You'd discover that all those variables -
c2,c3andc4are modified alongside your originalcbecausesscanfoverruns the given buffer and writes outside of it.@kshegunov said in QByteArray not initializing:
uint8_t c, c2, c3, c4; // ... sscanf(p, "%2x", (int *) &c); // ...You'd discover that all those variables -
c2,c3andc4are modified alongside your originalcbecausesscanfoverruns the given buffer and writes outside of it.@kshegunov Purely OOI, did you actually test this code? I was actually thinking, assuming local variables allocated down the stack in order they're encountered, you'd have to
sscanfintoc4rather thancto get that behaviour from the way they're laid out...? -
@kshegunov said in QByteArray not initializing:
uint8_t c, c2, c3, c4; // ... sscanf(p, "%2x", (int *) &c); // ...You'd discover that all those variables -
c2,c3andc4are modified alongside your originalcbecausesscanfoverruns the given buffer and writes outside of it.@kshegunov Purely OOI, did you actually test this code? I was actually thinking, assuming local variables allocated down the stack in order they're encountered, you'd have to
sscanfintoc4rather thancto get that behaviour from the way they're laid out...?@JNBarchan said in QByteArray not initializing:
@kshegunov Purely OOI, did you actually test this code?
Not at the time, no.
I was actually thinking, assuming local variables allocated down the stack in order they're encountered, you'd have to sscanf into c4 rather than c to get that behaviour from the way they're laid out...?
Depends on many things in fact, but most important of those would be the compiler (also which way the stack goes address-wise). Don't forget the compiler's allowed to reorder the variables and memory access freely (with exception of memory fences and
volatile, but that's another discussion) if it finds it convenient to do so. Meaning, if you don't reference a variable it may even strip it from the assembly. That is for release, though, I've noticed compilers (at least g++) will not remove things from the binary in debug mode even if redundant/unnecessary.Anyway, I just made a quick test with g++ (7.2):
uint8_t c = 0, c2 = 0, c3 = 0, c4 = 0; *reinterpret_cast<int *>(&c) = -1; // c = c2 = c3 = c4 = 0xFFand
uint8_t c = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0; *reinterpret_cast<int *>(&c) = -1; // c = c3 = c4 = c5 = 0xFF; c2 = 0x00and the assembly for the second one:
8 [1] uint8_t c = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0; 0x5555555547c5 <+0x000b> c6 45 fb 00 movb $0x0,-0x5(%rbp) 0x5555555547c9 <+0x000f> c6 45 ff 00 movb $0x0,-0x1(%rbp) 0x5555555547cd <+0x0013> c6 45 fe 00 movb $0x0,-0x2(%rbp) 0x5555555547d1 <+0x0017> c6 45 fd 00 movb $0x0,-0x3(%rbp) 0x5555555547d5 <+0x001b> c6 45 fc 00 movb $0x0,-0x4(%rbp) 9 [1] *reinterpret_cast<int *>(&c) = -1; 0x5555555547d9 <+0x001f> 48 8d 45 fb lea -0x5(%rbp),%rax 0x5555555547dd <+0x0023> c7 00 ff ff ff ff movl $0xffffffff,(%rax)As you can see the variable
cwas actually reordered by the compiler to occupy an address deeper in the stack.