[Maria-developers] table_share->field vs table->field
![](https://secure.gravatar.com/avatar/94ab4b0efa01a23cd1ed1aa1406c11a0.jpg?s=120&d=mm&r=g)
Hi all, I ran into a strange problem: I am working on a storage engine for MariaDB. To access field information I usually do as written in the documentation: for (Field** field = table->field; *field; ++field) { /* some code here */ } This works fine in most cases (for writing - read handler::write_row - it seems to work always) but sometimes (I think always in the index_next method) accessing **(table->field) results in a segmentation fault (but *(table->field) is not null, but something like 0x5e6f4c6d4578244d). Strange enough, this error does not happen always. In the debugger I saw, that table_share->field points to the correct location there so I replaces table->field in the above loop with table_share->field. But this also seems to not work - it now crashes on other queries (also on updates, but after restarting MariaDB it also crashes on a full table scan). So my question: how can I access the fields in a reliable manner? I need to do that to set/get the BLOB/TEXT fields. We have a method in our handler called set_blobs that resets the pointer in the record to the blobs, which looks like the following: void ha_kvstore::set_blobs(uchar *buf, kvid key, btree::buffer &raw_data) { auto current_read_pos = raw_data.const_ptr() + table_share->reclength; for (Field** field = table->field; *field; ++field) { if (!((*field)->flags & BLOB_FLAG)) continue; (*field)->table = table; Field_blob* blob = *((Field_blob**)field); uint32 packlength = blob->pack_length_no_ptr(); bmove((*field)->ptr + packlength, ¤t_read_pos, sizeof(char*)); current_read_pos += blob->get_length(); } } The storage engine always crashes in this code. What are we doing wrong? Any help is appreciated! Best Markus
![](https://secure.gravatar.com/avatar/3c2329333dd5898f2e72818af773243d.jpg?s=120&d=mm&r=g)
Hi, Markus! On Aug 16, Markus Pilman wrote:
Hi all,
I ran into a strange problem:
I am working on a storage engine for MariaDB. To access field information I usually do as written in the documentation:
for (Field** field = table->field; *field; ++field) { /* some code here */ }
This works fine in most cases (for writing - read handler::write_row - it seems to work always) but sometimes (I think always in the index_next method) accessing **(table->field) results in a segmentation fault (but *(table->field) is not null, but something like 0x5e6f4c6d4578244d). Strange enough, this error does not happen always. In the debugger I saw, that table_share->field points to the correct location there so I replaces table->field in the above loop with table_share->field. But this also seems to not work - it now crashes on other queries (also on updates, but after restarting MariaDB it also crashes on a full table scan).
Normaly you should always use table->field, not table_share->field. If a table is used by many threads, or by the same thread many times - in other words, if many instances of your handler class are created - they will use different TABLE objects, but the same TABLE_SHARE. So, table_share->field objects necessarily will have the same ptr in all threads, it's not what you usually want. A strange value of *(table->field) looks like a memory corruption. May be your code writes to a free'd memory somewhere, or dereferences a dangled pointer. Can you show the stack trace of the crash? Regards, Sergei
![](https://secure.gravatar.com/avatar/94ab4b0efa01a23cd1ed1aa1406c11a0.jpg?s=120&d=mm&r=g)
Hi Sergei,
Yes you have been right: one of our master students made a small
refacoring error: he copied more data into the "uchar *row" than the
actual record length. He copied also the BLOBs to this location -
which explains why the error did only occur from time to time (only if
you queried records that have BLOB or TEXT fields).
Thanks for your answer!
Best Markus
On Tue, Aug 21, 2012 at 2:38 PM, Sergei Golubchik
Hi, Markus!
On Aug 16, Markus Pilman wrote:
Hi all,
I ran into a strange problem:
I am working on a storage engine for MariaDB. To access field information I usually do as written in the documentation:
for (Field** field = table->field; *field; ++field) { /* some code here */ }
This works fine in most cases (for writing - read handler::write_row - it seems to work always) but sometimes (I think always in the index_next method) accessing **(table->field) results in a segmentation fault (but *(table->field) is not null, but something like 0x5e6f4c6d4578244d). Strange enough, this error does not happen always. In the debugger I saw, that table_share->field points to the correct location there so I replaces table->field in the above loop with table_share->field. But this also seems to not work - it now crashes on other queries (also on updates, but after restarting MariaDB it also crashes on a full table scan).
Normaly you should always use table->field, not table_share->field. If a table is used by many threads, or by the same thread many times - in other words, if many instances of your handler class are created - they will use different TABLE objects, but the same TABLE_SHARE.
So, table_share->field objects necessarily will have the same ptr in all threads, it's not what you usually want.
A strange value of *(table->field) looks like a memory corruption. May be your code writes to a free'd memory somewhere, or dereferences a dangled pointer. Can you show the stack trace of the crash?
Regards, Sergei
participants (2)
-
Markus Pilman
-
Sergei Golubchik