# Invalid read may occur when raising an exception to a thread that waits for mutex

**URL:** <https://www.ruby-forum.com/t/invalid-read-may-occur-when-raising-an-exception-to-a-thread-that-waits-for-mutex/138863>\
**Category:** Development\
**Created:** [May 28, 2008, 2:44pm UTC](https://www.ruby-forum.com/t/invalid-read-may-occur-when-raising-an-exception-to-a-thread-that-waits-for-mutex/138863 "2008-05-28T14:44:19Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Yusuke\_ENDOH](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/y/c89c15/32.png) [@Yusuke\_ENDOH](https://www.ruby-forum.com/u/Yusuke_ENDOH)\
**Post date:** [May 28, 2008, 2:44pm UTC](https://www.ruby-forum.com/t/invalid-read-may-occur-when-raising-an-exception-to-a-thread-that-waits-for-mutex/138863/1 "2008-05-28T14:44:19Z")

</div>

e$B1sF#$G$9!#e(B

e$B0J2\<$N$h$&$K$9$k$H%O%s%0$9$k$3$H$,$"$j$^$9!#e(B

$ ./ruby -ve ’  
N = 10

m = [Mutex.new]  
m.first.lock

t = Thread.new do  
begin  
m.first.lock # (1)  
rescue  
loop { } # (3)  
end  
end

sleep 1  
t.raise # (2)

m.clear  
sleep 1  
GC.start # (4)

t.raise # (5)  
’  
ruby 1.9.0 (2008-05-28 revision 16675) [i686-linux]  
^Z

e$BN.$l$O$3$s$J46$8$G$9!#e(B

- (1) e$B$G%9%l%C%Ie(B t e$B$Ne(B unblock\_function e$B$,e(B  
lock\_interrupt e$B$Ke(B  
e$B$J$j!"e(Bmutex e$B$N2rJ|BT$A$KF~$k!#e(B

- (2) e$B$G%9%l%C%Ie(B t e$B$Ne(B unblock\_function (= lock\_interrupt)  
e$B$,e(B  
e$B8F$P$l$k!#e(B

- e$B%9%l%C%Ie(B t e$B$Ne(B unblock\_function  
e$B$O%/%j%"$5$l$k$Y$-$@$,!“e(B  
e$B%/%j%”$5$l$J$$$^$^%9%l%C%Ie(B t e$B$N\<B9T$Oe(B (3) e$B$K0$k!#e(B

- (4) e$B$Ge(B mutex e$B$re(B free e$B$9$ke(B (e$B$?$@$74D6-0MB8e(B)  
e$B!#e(B

- (5) e$B$G%9%l%C%Ie(B t e$B$Ne(B unblock\_function (= lock\_interrupt)  
e$B$,e(B  
e$B8F$P$l$k$,!"e(Block\_interrupt e$B$NCf$G2rJ|:Q$\_$Ne(B mutex  
e$B$K?($k!#e(B

e$B\<B:]!"e(Bvalgrind e$B$K$+$1$k$H!"e(Block\_interrupt e$BFb$Ge(B Invalid  
read  
e$B$7$F$$$k$N$,$o$+$j$^$9!#e(B

==15890== Invalid read of size 4  
==15890== at 0x811AA87: lock\_interrupt (thread.c:2439)  
==15890== by 0x81181D9: rb\_thread\_interrupt (thread.c:222)  
==15890== by 0x8119284: rb\_thread\_ready (thread.c:864)  
==15890== by 0x81192EE: rb\_thread\_raise (thread.c:884)  
==15890== by 0x811941F: thread\_raise\_m (thread.c:960)  
==15890== by 0x810A59B: call\_cfunc (vm\_insnhelper.c:286)  
==15890== by 0x8114F32: vm\_call\_cfunc (vm\_insnhelper.c:376)  
==15890== by 0x8114A7C: vm\_call\_method (vm\_insnhelper.c:508)  
==15890== by 0x8110F8B: vm\_eval (insns.def:1048)  
==15890== by 0x8115135: vm\_eval\_body (vm.c:1022)  
==15890== by 0x811575C: rb\_iseq\_eval (vm.c:1226)  
==15890== by 0x805A0FB: ruby\_exec\_node (eval.c:221)  
==15890== Address 0x44B6F04 is 76 bytes inside a block of size 80  
free’d  
==15890== at 0x401CFA5: free (vg\_replace\_malloc.c:233)  
==15890== by 0x805EA4E: ruby\_xfree (gc.c:425)  
==15890== by 0x811A899: mutex\_free (thread.c:2340)  
==15890== by 0x80606C4: obj\_free (gc.c:1498)  
==15890== by 0x8060214: gc\_sweep (gc.c:1371)  
==15890== by 0x8060B0C: garbage\_collect (gc.c:1704)  
==15890== by 0x80614AF: rb\_gc (gc.c:2119)  
==15890== by 0x8060B6B: rb\_gc\_start (gc.c:1751)  
==15890== by 0x810A5B1: call\_cfunc (vm\_insnhelper.c:289)  
==15890== by 0x8114F32: vm\_call\_cfunc (vm\_insnhelper.c:376)  
==15890== by 0x8114A7C: vm\_call\_method (vm\_insnhelper.c:508)  
==15890== by 0x8110F8B: vm\_eval (insns.def:1048)

unblock\_function e$B$,%/%j%"$5$l$J$$$N$Oe(B set\_unblock\_function  
e$BFb$Ge(B  
RUBY\_VM\_CHECK\_INTS e$B$r$7$F$$$F!"$=$3$+$ie(B longjmp  
e$B$9$k$;$$$G$9!#e(B  
e$B$3$Ne(B RUBY\_VM\_CHECK\_INTS e$B$OI,MW$J$s$G$7$g$&$+!#e(B

# Index: thread.c

— thread.c (revision 16676)  
+++ thread.c (working copy)  
@@ -197,19 +197,11 @@  
set\_unblock\_function(rb\_thread\_t \*th, rb\_unblock\_function\_t \*func, void  
\*arg,  
rb\_unblock\_function\_t \*\*oldfunc, void \*\*oldarg)  
{

- check\_ints:
- RUBY\_VM\_CHECK\_INTS(); /\* check signal or so \*/  
native\_mutex\_lock(&th-\>interrupt\_lock);
- if (th-\>interrupt\_flag) {
- native\_mutex\_unlock(&th-\>interrupt\_lock);
- goto check\_ints;
- }
- else {
- if (oldfunc) \*oldfunc = th-\>unblock\_function;
- if (oldarg) \*oldarg = th-\>unblock\_function\_arg;
- th-\>unblock\_function = func;
- th-\>unblock\_function\_arg = arg;
- }

- if (oldfunc) \*oldfunc = th-\>unblock\_function;
- if (oldarg) \*oldarg = th-\>unblock\_function\_arg;
- th-\>unblock\_function = func;
- th-\>unblock\_function\_arg = arg;  
native\_mutex\_unlock(&th-\>interrupt\_lock);  
}

---

<div class="post-metadata">

**Author:** ![Yusuke\_ENDOH](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/y/c89c15/32.png) [@Yusuke\_ENDOH](https://www.ruby-forum.com/u/Yusuke_ENDOH)\
**Post date:** [May 29, 2008, 9:17am UTC](https://www.ruby-forum.com/t/invalid-read-may-occur-when-raising-an-exception-to-a-thread-that-waits-for-mutex/138863/2 "2008-05-29T09:17:04Z")

</div>

e$B$J$+$@$G$9!#e(B

At Wed, 28 May 2008 21:42:48 +0900,  
Yusuke ENDOH wrote in [ruby-dev:34874]:

> unblock\_function e$B$,%/%j%"$5$l$J$$$N$Oe(B set\_unblock\_function e$BFb$Ge(B  
> RUBY\_VM\_CHECK\_INTS e$B$r$7$F$$$F!"$=$3$+$ie(B longjmp e$B$9$k$;$$$G$9!#e(B  
> e$B$3$Ne(B RUBY\_VM\_CHECK\_INTS e$B$OI,MW$J$s$G$7$g$&$+!#e(B

BLOCKING\_REGIONe$B$KF~$k$H$-$K$Oe(Bchecke$B$7$F$bLdBj$J$$$s$8$c$J$$$G$7$ge(B  
e$B$&$+!#LdBj$,5/$-$k$N$OH4$1$k$H$-$G$9$h$M!#e(B

# Index: vm\_core.h

— vm\_core.h (revision 16676)  
+++ vm\_core.h (working copy)  
@@ -374,4 +374,9 @@ struct rb\_vm\_trap\_tag {  
#define USE\_VALUE\_CACHE 0

+struct rb\_unblock\_callback {

- rb\_unblock\_function\_t \*func;
- void \*arg;  
+};
- 

typedef struct rb\_thread\_struct rb\_thread\_t;

@@ -419,7 +424,6 @@ struct rb\_thread\_struct

```
 int interrupt_flag;

```

- rb\_unblock\_function\_t \*unblock\_function;
- void \*unblock\_function\_arg;  
rb\_thread\_lock\_t interrupt\_lock;

- struct rb\_unblock\_callback unblock;

-static void set\_unblock\_function(rb\_thread\_t \*th, rb\_unblock\_function\_t  
\*func, void \*ptr,

- 

```
    rb_unblock_function_t **oldfunc, void** oldptr);

```

+static void set\_unblock\_function(rb\_thread\_t \*th, rb\_unblock\_function\_t  
\*func, void \*arg,

- 

```
    struct rb_unblock_callback *old);

```

+static void reset\_unblock\_function(rb\_thread\_t \*th, const struct  
rb\_unblock\_callback \*old);

#define GVL\_UNLOCK\_BEGIN() do {   
@@ -96,7 +97,6 @@ static void set\_unblock\_function(rb\_thre  
rb\_thread\_t \*\_\_th = GET\_THREAD();   
int \_\_prev\_status = \_\_th-\>status; \

- rb\_unblock\_function\_t \*\_\_oldubf; \
- void \*\_\_oldubfarg; \
- set\_unblock\_function(\_\_th, ubf, ubfarg, &\_\_oldubf, &\_\_oldubfarg); \

- struct rb\_unblock\_callback \_\_oldubf; \
- set\_unblock\_function(\_\_th, ubf, ubfarg, &\_\_oldubf);   
\_\_th-\>status = THREAD\_STOPPED;   
thread\_debug(“enter blocking region (%p)\n”, \_\_th);   
@@ -107,5 +107,5 @@ static void set\_unblock\_function(rb\_thre  
thread\_debug(“leave blocking region (%p)\n”, \_\_th);   
remove\_signal\_thread\_list(\_\_th); \

- set\_unblock\_function(\_\_th, \_\_oldubf, \_\_oldubfarg, 0, 0); \

- reset\_unblock\_function(\_\_th, &\_\_oldubf);   
if (\_\_th-\>status == THREAD\_STOPPED) {   
\_\_th-\>status = \_\_prev\_status;   
@@ -196,5 +196,5 @@ rb\_thread\_debug(const char \*fmt, …)  
static void  
set\_unblock\_function(rb\_thread\_t \*th, rb\_unblock\_function\_t \*func, void  
\*arg,

- 

```
    rb_unblock_function_t **oldfunc, void** oldarg)

```

- 

```
    struct rb_unblock_callback *old)

```

{  
check\_ints:  
@@ -206,8 +206,7 @@ set\_unblock\_function(rb\_thread\_t \*th, rb  
}  
else {

- if (oldfunc) \*oldfunc = th-\>unblock\_function;
- if (oldarg) \*oldarg = th-\>unblock\_function\_arg;
- th-\>unblock\_function = func;
- th-\>unblock\_function\_arg = arg;

- if (old) \*old = th-\>unblock;
- th-\>unblock.func = func;
- th-\>unblock.arg = arg;  
}  
native\_mutex\_unlock(&th-\>interrupt\_lock);  
@@ -215,10 +214,18 @@ set\_unblock\_function(rb\_thread\_t \*th, rb

static void  
+reset\_unblock\_function(rb\_thread\_t \*th, const struct  
rb\_unblock\_callback \*old)  
+{

- native\_mutex\_lock(&th-\>interrupt\_lock);
- th-\>unblock = \*old;
- native\_mutex\_unlock(&th-\>interrupt\_lock);  
+}
- 

+static void  
rb\_thread\_interrupt(rb\_thread\_t \*th)  
{  
native\_mutex\_lock(&th-\>interrupt\_lock);  
RUBY\_VM\_SET\_INTERRUPT(th);

- if (th-\>unblock\_function) {
- (th-\>unblock\_function)(th-\>unblock\_function\_arg);

- if (th-\>unblock.func) {
- (th-\>unblock.func)(th-\>unblock.arg);  
}  
else {  
Index: thread\_pthread.c  
===================================================================  
— thread\_pthread.c (revision 16676)  
+++ thread\_pthread.c (working copy)  
@@ -425,6 +425,6 @@ native\_sleep(rb\_thread\_t \*th, struct tim  
{  
pthread\_mutex\_lock(&th-\>interrupt\_lock);

- th-\>unblock\_function = ubf\_pthread\_cond\_signal;
- th-\>unblock\_function\_arg = th;

- th-\>unblock.func = ubf\_pthread\_cond\_signal;

- th-\>unblock.arg = th;

- th-\>unblock\_function = 0;
- th-\>unblock\_function\_arg = 0;

- th-\>unblock.func = 0;

- th-\>unblock.arg = 0;

- th-\>unblock\_function = ubf\_handle;
- th-\>unblock\_function\_arg = th;

- th-\>unblock.func = ubf\_handle;

- th-\>unblock.arg = th;

- th-\>unblock\_function = 0;
- th-\>unblock\_function\_arg = 0;

- th-\>unblock.func = 0;
- th-\>unblock.arg = 0;  
th-\>status = status;  
}

---

<div class="post-metadata">

**Author:** ![Yusuke\_ENDOH](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/y/c89c15/32.png) [@Yusuke\_ENDOH](https://www.ruby-forum.com/u/Yusuke_ENDOH)\
**Post date:** [May 29, 2008, 1:37pm UTC](https://www.ruby-forum.com/t/invalid-read-may-occur-when-raising-an-exception-to-a-thread-that-waits-for-mutex/138863/3 "2008-05-29T13:37:43Z")

</div>

e$B1sF#$G$9!#e(B

08/05/29 e$B$Ke(B Nobuyoshi N.[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
e$B$5$s$O=q$-$^$7$?e(B:

> > unblock\_function e$B$,%/%j%“$5$l$J$$$N$Oe(B set\_unblock\_function e$BFb$Ge(B  
> > RUBY\_VM\_CHECK\_INTS e$B$r$7$F$$$F!”$=$3$+$ie(B longjmp e$B$9$k$;$$$G$9!#e(B  
> > e$B$3$Ne(B RUBY\_VM\_CHECK\_INTS e$B$OI,MW$J$s$G$7$g$&$+!#e(B
> 
> BLOCKING\_REGIONe$B$KF~$k$H$-$K$Oe(Bchecke$B$7$F$bLdBj$J$$$s$8$c$J$$$G$7$ge(B  
> e$B$&$+!#LdBj$,5/$-$k$N$OH4$1$k$H$-$G$9$h$M!#e(B

e$B$=$&$G$9$M!#$=$C$A$NJ}$,$h$5$=$&$G$9!#e(B  
e$B$h$m$7$/$\*4j$$$7$^$9!#e(B
