[ruby-oci8-commit] [536] trunk/ruby-oci8: Fix SEGV when a temporary LOB is GCed while another LOB is read.
nobody at rubyforge.org
nobody at rubyforge.org
Sun Oct 28 04:51:35 UTC 2012
Revision: 536
Author: kubo
Date: 2012-10-28 04:51:34 +0000 (Sun, 28 Oct 2012)
Log Message:
-----------
Fix SEGV when a temporary LOB is GCed while another LOB is read.
(github issue #20 reported by techsplicer)
Modified Paths:
--------------
trunk/ruby-oci8/ChangeLog
trunk/ruby-oci8/ext/oci8/lob.c
trunk/ruby-oci8/ext/oci8/oci8.c
trunk/ruby-oci8/ext/oci8/oci8.h
trunk/ruby-oci8/ext/oci8/oci8lib.c
Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog 2012-10-02 09:09:26 UTC (rev 535)
+++ trunk/ruby-oci8/ChangeLog 2012-10-28 04:51:34 UTC (rev 536)
@@ -1,3 +1,8 @@
+2012-10-28 KUBO Takehiro <kubo at jiubao.org>
+ * ext/oci8/lob.c, ext/oci8/oci8.c, ext/oci8/oci8.h, ext/oci8/oci8lib.c:
+ Fix SEGV when a temporary LOB is GCed while another LOB is read.
+ (github issue #20 reported by techsplicer)
+
2012-10-02 KUBO Takehiro <kubo at jiubao.org>
* ext/oci8/apiwrap.c.tmpl, ext/oci8/connection_pool.c, ext/oci8/env.c,
ext/oci8/extconf.rb, ext/oci8/oci8.c, ext/oci8/oci8.h, ext/oci8/oci8lib.c,
Modified: trunk/ruby-oci8/ext/oci8/lob.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/lob.c 2012-10-02 09:09:26 UTC (rev 535)
+++ trunk/ruby-oci8/ext/oci8/lob.c 2012-10-28 04:51:34 UTC (rev 536)
@@ -113,8 +113,19 @@
&& OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS
&& is_temporary) {
+#ifdef HAVE_RB_THREAD_BLOCKING_REGION
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
+ oci8_temp_lob_t *temp_lob = ALLOC(oci8_temp_lob_t);
+
+ temp_lob->next = svcctx->temp_lobs;
+ temp_lob->lob = lob->base.hp.lob;
+ svcctx->temp_lobs = temp_lob;
+ lob->base.type = 0;
+ lob->base.hp.ptr = NULL;
+#else
/* FIXME: This may stall the GC. */
OCILobFreeTemporary(lob->svchp, oci8_errhp, lob->base.hp.lob);
+#endif
}
lob->svc = Qnil;
lob->svchp = NULL;
Modified: trunk/ruby-oci8/ext/oci8/oci8.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8.c 2012-10-02 09:09:26 UTC (rev 535)
+++ trunk/ruby-oci8/ext/oci8/oci8.c 2012-10-28 04:51:34 UTC (rev 536)
@@ -101,6 +101,18 @@
static void oci8_svcctx_free(oci8_base_t *base)
{
oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
+ oci8_temp_lob_t *lob;
+
+ lob = svcctx->temp_lobs;
+ while (lob != NULL) {
+ oci8_temp_lob_t *lob_next = lob->next;
+
+ OCIDescriptorFree(lob->lob, OCI_DTYPE_LOB);
+ xfree(lob);
+ lob = lob_next;
+ }
+ svcctx->temp_lobs = NULL;
+
if (svcctx->logoff_strategy != NULL) {
const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
void *data = strategy->prepare(svcctx);
Modified: trunk/ruby-oci8/ext/oci8/oci8.h
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8.h 2012-10-02 09:09:26 UTC (rev 535)
+++ trunk/ruby-oci8/ext/oci8/oci8.h 2012-10-28 04:51:34 UTC (rev 536)
@@ -334,6 +334,11 @@
typedef struct oci8_logoff_strategy oci8_logoff_strategy_t;
+typedef struct oci8_temp_lob {
+ struct oci8_temp_lob *next;
+ OCILobLocator *lob;
+} oci8_temp_lob_t;
+
typedef struct oci8_svcctx {
oci8_base_t base;
volatile VALUE executing_thread;
@@ -347,6 +352,7 @@
char non_blocking;
#endif
VALUE long_read_len;
+ oci8_temp_lob_t *temp_lobs;
} oci8_svcctx_t;
struct oci8_logoff_strategy {
Modified: trunk/ruby-oci8/ext/oci8/oci8lib.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8lib.c 2012-10-02 09:09:26 UTC (rev 535)
+++ trunk/ruby-oci8/ext/oci8/oci8lib.c 2012-10-28 04:51:34 UTC (rev 536)
@@ -210,15 +210,68 @@
OCIBreak(svcctx->base.hp.ptr, oci8_errhp);
}
+typedef struct free_temp_lob_arg_t {
+ oci8_svcctx_t *svcctx;
+ OCISvcCtx *svchp;
+ OCIError *errhp;
+ OCILobLocator *lob;
+} free_temp_lob_arg_t;
+
+static void *free_temp_lob(void *user_data)
+{
+ free_temp_lob_arg_t *data = (free_temp_lob_arg_t *)user_data;
+ sword rv = OCILobFreeTemporary(data->svchp, data->errhp, data->lob);
+
+ data->svcctx->executing_thread = Qnil;
+ return (void*)(VALUE)rv;
+}
+
/* ruby 1.9 */
sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data)
{
+ oci8_temp_lob_t *lob;
+ OCIError *errhp = oci8_errhp;
+
+ if (!NIL_P(svcctx->executing_thread)) {
+ rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
+ }
+
+ lob = svcctx->temp_lobs;
+ while (lob != NULL) {
+ oci8_temp_lob_t *lob_next = lob->next;
+
+ if (svcctx->non_blocking) {
+ free_temp_lob_arg_t arg;
+ sword rv;
+
+ arg.svcctx = svcctx;
+ arg.svchp = svcctx->base.hp.svc;
+ arg.errhp = errhp;
+ arg.lob = lob->lob;
+
+ svcctx->executing_thread = rb_thread_current();
+#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
+ rv = (sword)(VALUE)rb_thread_call_without_gvl(free_temp_lob, &arg, oci8_unblock_func, svcctx);
+#else
+ rv = (sword)rb_thread_blocking_region(free_temp_lob, &arg, oci8_unblock_func, svcctx);
+#endif
+ if (rv == OCI_ERROR) {
+ if (oci8_get_error_code(errhp) == 1013) {
+ rb_raise(eOCIBreak, "Canceled by user request.");
+ }
+ }
+ } else {
+ OCILobFreeTemporary(svcctx->base.hp.svc, errhp, lob->lob);
+ }
+ OCIDescriptorFree(lob->lob, OCI_DTYPE_LOB);
+
+ xfree(lob);
+ svcctx->temp_lobs = lob = lob_next;
+ }
+
if (svcctx->non_blocking) {
sword rv;
- if (!NIL_P(svcctx->executing_thread)) {
- rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
- }
svcctx->executing_thread = rb_thread_current();
/* Note: executing_thread is cleard at the end of the blocking function. */
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
@@ -227,7 +280,7 @@
rv = (sword)rb_thread_blocking_region(func, (rb_blocking_function_t)data, oci8_unblock_func, svcctx);
#endif
if (rv == OCI_ERROR) {
- if (oci8_get_error_code(oci8_errhp) == 1013) {
+ if (oci8_get_error_code(errhp) == 1013) {
rb_raise(eOCIBreak, "Canceled by user request.");
}
}
More information about the ruby-oci8-commit
mailing list