Re: Thread safe programming
Re: Thread safe programming
- Subject: Re: Thread safe programming
- From: Nat! <email@hidden>
- Date: Wed, 5 Jun 2002 21:20:39 +0200
Am Mittwoch den, 5. Juni 2002, um 15:00, schrieb Jens Bauer:
Hi all,
I'd like to inform you about a problem I've seen recently, so you can
avoid this kind of programming.
Many of you out there know this already, but for those who are not
familiar with interrupt programming and thread programming, I'd like to
make sure that you can avoid such problems and spot them easily.
void *memchr(void *src, unsigned char chr, size_t size)
{
unsigned char *s, *e, save;
s = (unsigned char *) src;
e = s + size;
save = *e; /* save last character */
*e = chr; /* patch it */
while(chr != *s)
{
s++;
}
*e = save; /* restore last char */
return((e == s) ? NULL : s);
}
Lame and buggy implementation of stdlib memchr.
First problem:
The byte after the string is being patched.
If the string was allocated using malloc(10), the character patched is
character number 11, which is *outside* the buffer.
If you're lucky, you'll always get a crash here, and then be able
to find
the bug quickly.
Yeah, but that's a bug. It has nothing to do with thread safety.
Second problem:
If you are using threads, and thread 2 calls memchr while thread 1 is
inside the while loop, this is what is going to happen:
1: thread1 saves the end-char ('0')
2: thread1 sets the last character to be '+'
3: thread2 saves the end-char ('+')
4: thread2 sets the last character to be '-'
5: thread1 searches way beyond the end of the buffer or finds what it's
searching for
6: thread1 finds something interesting and restores the end-char ('0')
7: thread2 searches way beyond the end of the buffer or finds what it's
searching for
8: thread2 restores the end-char ('+')
In addition to the incorrect searching, the last character now changed.
We didn't *own* that character.
This only happens when you have two threads accessing the same
buffer. The main problem here is not that the function does this
(alas buggy), but that the routine is called memchr and this
implies a certain functionality.
-So what's the solution ?
If you only read the buffer, you should change the function call
to this:
void *memchr(const void *src, unsigned char chr, size_t size)
Adding const will indicate that you are not modifying the buffer.
This is not enough, because you will have to change the code as
well, but
using const parameters will in many cases make the compiler warn you
about illegal implicit const to non-const casts.
The key solution here is "change the code as well" not the addition
of const. If you only need to read the buffer, then only read the
buffer. Don't write into it. No one would expect memchr (a stdlib
function with defined semantics) to actually change the buffer
contents, if only temporary. Temporary changes to shared resources
are bad, see also the "isa" thread from yesterday or so.
Another solution would be semaphore programming, but you do not want to
do that to the above routine, because that means you would waste a
bunch
of CPU cycles on finding a character in memory.
Another solution is to document the behaviour of your routine. Just
document it to be non-threadsafe for multiple threads to peruse the
same buffer. Lay the burden on the application programmer.
Ciao
Nat!
Jedenfalls sind zehn Fehlstarts hintereinander [E. Fuchs]
ein sehr interessanter Beweis
f|r unsere Theorie
von der nat|rlichen \berlegenheit des Dezimalsystems
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.