PDA

View Full Version : semi-random crashes in QByteArray::data()



tuli
22nd May 2013, 18:15
Alright, i am reading into a QByteArray like this:



if(myArray.size() < size)
myArray.resize(size);

__memcpy_dgsint(dataArray.data(), start, size);

then, some seconds after doing that, i access the read data:




char* r = myArray.data();



this works just fine most of the time ("start" is sanitized in the second sample).
Howver, i get crashes with a certain, very specific input file.
In such a case, the crash happens inside myArray.data(), inside internal QByteArray methods, inside a memcpy() function.
See the callstack here:



And the exception:


First-chance exception at 0x1026ed6a (msvcr90d.dll) in x.exe: 0xC0000005: Access violation reading location 0x00a99f00.
Unhandled exception at 0x1026ed6a (msvcr90d.dll) in x.exe: 0xC0000005: Access violation reading location 0x00a99f00.


The size-values we are talking about here arent huge - ~500 bytes maybe.

This seems all very wired to me. I collected some data and there are no extraordinary values involved when it crashes. Rather, the same call with the same size value succeeded several dozen times before, and then
QByteArray decides to wiredly call some realloc functon and crash. :(

any ideas why?


winxpsp3, vs2008 + Qt484

ChrisW67
23rd May 2013, 01:39
Which line of your code triggers the crash?

If you keep and use "r" later then you are inviting problems. QByteArray can and will move its data block as it needs to grow or shrink.

tuli
23rd May 2013, 07:11
the .data() call triggers the crash:

char* r = myArray.data();

(does r change, even if i do not call resize()?)

Anyways, the crash happens before r is set.

lanz
23rd May 2013, 07:43
Well, I googled __memcpy_dgsint, and can't find anything. What does this function do? Is this custom function, maybe it copies wrong number of bytes?
Sometimes functions from custom API take size not in bytes, but in some other units (say in 16-bit words).
It's also unclear how you initializing start.
The fact that program works most of the time, doesn't really prove anything. You may corrupt memory each time and just get "lucky" that nothing important is ruined.

ChrisW67
23rd May 2013, 08:23
the .data() call triggers the crash:

Uh huh, which one? There are two in your original post.

Calling data() causes a deep copy of the data block if the QByteArray is currently shared. If the data block is very large this might fail. Since it fails:

i get crashes with a certain, very specific input file.
it might help to consider what is different about that file. Is it huge?


does r change, even if i do not call resize()?
The value of r won't change unless you change it. The memory address of the QByteArray may move if you do anything non-const to the byte array. If that happens the value of r, which has not changed, becomes an invalid pointer.

I am with lanz, perhaps you should be using standard memcpy() rather than some compiler internal function (any name starting with two underscores is compiler implementation reserved and should not come from user code).

tuli
23rd May 2013, 08:49
Is it huge?

in comparison the the other files, yes! But still only a couple of MB.
In the vast majority of the crashes, the second data() call triggers it, but i've seen the first error out, too (after resizing() to hold a lot of data).

I have replace the dsgin call with this:


memcpy(myArray.data(), start, size);

with the same results.


I am not knowingly sharing the arrray, all i do is reserving() and memcpy()ing into it.

Thanks for the help this far, i'll run some more tests.

wysota
23rd May 2013, 08:53
Do you have worker threads in your app? Does more than one thread have access to the byte array?

lanz
23rd May 2013, 08:57
I'd also looked into loading code as well, maybe something with initialization of "start" variable.

Santosh Reddy
23rd May 2013, 09:06
I am not knowingly sharing the arrray, all i do is reserving() and memcpy()ing into it.
Your code shows a resize() and you say reserve(), I hope you know these are two different functions, and have different behaviour. As data() returns a \0-terminated array, the position of null termination will be different for reserve() and resize() calls.

Make sure when you update(memcpy) the content of data() it is \0-terminated data()[size+1] = '\0';

tuli
25th May 2013, 20:53
There are no threads involved, and the loading code looks fine to me.



Make sure when you update(memcpy) the content of data() it is \0-terminated data()[size+1] = '\0';

This may be the reason. Thanks!
Let me check that...

And yes, i meant resize().

d_stranz
27th May 2013, 23:24
Make sure when you update(memcpy) the content of data() it is \0-terminated data()[size+1] = '\0';

There is no requirement on memcpy() that either the source or destination be null-terminated. memcpy() copies exactly the number of bytes it is told to copy, and those bytes can contain anything.