Skip to content

Commit ea99b6a

Browse files
committed
Fix memory corruption in XS functions when Perl stack is reallocated
Macro ST(*) returns pointer to Perl stack. Other Perl functions which use Perl stack (e.g. eval) may reallocate Perl stack and therefore pointer returned by ST(*) macro is invalid. Construction like this: ST(0) = dbd_db_login6_sv(dbh, imp_dbh, dbname, username, password, attribs) ? &PL_sv_yes : &PL_sv_no; where dbd_db_login6_sv() driver function calls eval may lead to reallocating Perl stack and therefore invalidating ST(0) pointer. So that construction would cause memory corruption as left part of assignment is resolved prior executing dbd_db_login6_sv() function. Correct way how to handle this problem: First call dbd_db_login6_sv() function and then call ST(0) to retrieve stack pointer. In this patch are fixes all occurrences of such constructions. When running perl under valgrind I got memory corruption in DBD::ODBC driver in that dbd_db_login6_sv() function due to above problem. Exactly same problem was present in Encode module which was fixed in pull request: dankogai/p5-encode#72
1 parent a0e1755 commit ea99b6a

File tree

2 files changed

+65
-36
lines changed

2 files changed

+65
-36
lines changed

DBI.xs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5237,9 +5237,12 @@ bind_col(sth, col, ref, attribs=Nullsv)
52375237
SV * col
52385238
SV * ref
52395239
SV * attribs
5240+
PREINIT:
5241+
SV *ret;
52405242
CODE:
52415243
DBD_ATTRIBS_CHECK("bind_col", sth, attribs);
5242-
ST(0) = boolSV(dbih_sth_bind_col(sth, col, ref, attribs));
5244+
ret = boolSV(dbih_sth_bind_col(sth, col, ref, attribs));
5245+
ST(0) = ret;
52435246
(void)cv;
52445247

52455248

@@ -5477,21 +5480,27 @@ void
54775480
FETCH(h, keysv)
54785481
SV * h
54795482
SV * keysv
5483+
PREINIT:
5484+
SV *ret;
54805485
CODE:
5481-
ST(0) = dbih_get_attr_k(h, keysv, 0);
5486+
ret = dbih_get_attr_k(h, keysv, 0);
5487+
ST(0) = ret;
54825488
(void)cv;
54835489

54845490
void
54855491
DELETE(h, keysv)
54865492
SV * h
54875493
SV * keysv
5494+
PREINIT:
5495+
SV *ret;
54885496
CODE:
54895497
/* only private_* keys can be deleted, for others DELETE acts like FETCH */
54905498
/* because the DBI internals rely on certain handle attributes existing */
54915499
if (strnEQ(SvPV_nolen(keysv),"private_",8))
5492-
ST(0) = hv_delete_ent((HV*)SvRV(h), keysv, 0, 0);
5500+
ret = hv_delete_ent((HV*)SvRV(h), keysv, 0, 0);
54935501
else
5494-
ST(0) = dbih_get_attr_k(h, keysv, 0);
5502+
ret = dbih_get_attr_k(h, keysv, 0);
5503+
ST(0) = ret;
54955504
(void)cv;
54965505

54975506

Driver.xst

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,17 @@ dbixs_revision(...)
6060
#ifdef dbd_discon_all
6161

6262
# disconnect_all renamed and ALIAS'd to avoid length clash on VMS :-(
63-
void
63+
bool
6464
discon_all_(drh)
6565
SV * drh
6666
ALIAS:
6767
disconnect_all = 1
6868
CODE:
6969
D_imp_drh(drh);
7070
PERL_UNUSED_VAR(ix);
71-
ST(0) = dbd_discon_all(drh, imp_drh) ? &PL_sv_yes : &PL_sv_no;
71+
RETVAL = dbd_discon_all(drh, imp_drh);
72+
OUTPUT:
73+
RETVAL
7274

7375
#endif /* dbd_discon_all */
7476

@@ -102,7 +104,7 @@ data_sources(drh, attr = Nullsv)
102104
MODULE = DBD::~DRIVER~ PACKAGE = DBD::~DRIVER~::db
103105

104106

105-
void
107+
bool
106108
_login(dbh, dbname, username, password, attribs=Nullsv)
107109
SV * dbh
108110
SV * dbname
@@ -118,14 +120,16 @@ _login(dbh, dbname, username, password, attribs=Nullsv)
118120
char *p = (SvOK(password)) ? SvPV(password,lna) : (char*)"";
119121
#endif
120122
#ifdef dbd_db_login6_sv
121-
ST(0) = dbd_db_login6_sv(dbh, imp_dbh, dbname, username, password, attribs) ? &PL_sv_yes : &PL_sv_no;
123+
RETVAL = dbd_db_login6_sv(dbh, imp_dbh, dbname, username, password, attribs);
122124
#elif defined(dbd_db_login6)
123-
ST(0) = dbd_db_login6(dbh, imp_dbh, SvPV_nolen(dbname), u, p, attribs) ? &PL_sv_yes : &PL_sv_no;
125+
RETVAL = dbd_db_login6(dbh, imp_dbh, SvPV_nolen(dbname), u, p, attribs);
124126
#else
125127
PERL_UNUSED_ARG(attribs);
126-
ST(0) = dbd_db_login( dbh, imp_dbh, SvPV_nolen(dbname), u, p) ? &PL_sv_yes : &PL_sv_no;
128+
RETVAL = dbd_db_login( dbh, imp_dbh, SvPV_nolen(dbname), u, p);
127129
#endif
128130
}
131+
OUTPUT:
132+
RETVAL
129133

130134

131135
void
@@ -297,33 +301,38 @@ last_insert_id(dbh, catalog=&PL_sv_undef, schema=&PL_sv_undef, table=&PL_sv_unde
297301
CODE:
298302
{
299303
D_imp_dbh(dbh);
300-
ST(0) = dbd_db_last_insert_id(dbh, imp_dbh, catalog, schema, table, field, attr);
304+
SV *ret = dbd_db_last_insert_id(dbh, imp_dbh, catalog, schema, table, field, attr);
305+
ST(0) = ret;
301306
}
302307

303308
#endif
304309

305310

306-
void
311+
bool
307312
commit(dbh)
308313
SV * dbh
309314
CODE:
310315
D_imp_dbh(dbh);
311316
if (DBIc_has(imp_dbh,DBIcf_AutoCommit) && DBIc_WARN(imp_dbh))
312317
warn("commit ineffective with AutoCommit enabled");
313-
ST(0) = dbd_db_commit(dbh, imp_dbh) ? &PL_sv_yes : &PL_sv_no;
318+
RETVAL = dbd_db_commit(dbh, imp_dbh);
319+
OUTPUT:
320+
RETVAL
314321

315322

316-
void
323+
bool
317324
rollback(dbh)
318325
SV * dbh
319326
CODE:
320327
D_imp_dbh(dbh);
321328
if (DBIc_has(imp_dbh,DBIcf_AutoCommit) && DBIc_WARN(imp_dbh))
322329
warn("rollback ineffective with AutoCommit enabled");
323-
ST(0) = dbd_db_rollback(dbh, imp_dbh) ? &PL_sv_yes : &PL_sv_no;
330+
RETVAL = dbd_db_rollback(dbh, imp_dbh);
331+
OUTPUT:
332+
RETVAL
324333

325334

326-
void
335+
bool
327336
disconnect(dbh)
328337
SV * dbh
329338
CODE:
@@ -340,8 +349,10 @@ disconnect(dbh)
340349
SvPV(dbh,lna), (int)DBIc_ACTIVE_KIDS(imp_dbh), plural,
341350
"(either destroy statement handles or call finish on them before disconnecting)");
342351
}
343-
ST(0) = dbd_db_disconnect(dbh, imp_dbh) ? &PL_sv_yes : &PL_sv_no;
352+
RETVAL = dbd_db_disconnect(dbh, imp_dbh);
344353
DBIc_ACTIVE_off(imp_dbh); /* ensure it's off, regardless */
354+
OUTPUT:
355+
RETVAL
345356

346357

347358
void
@@ -475,7 +486,7 @@ data_sources(dbh, attr = Nullsv)
475486
MODULE = DBD::~DRIVER~ PACKAGE = DBD::~DRIVER~::st
476487

477488

478-
void
489+
bool
479490
_prepare(sth, statement, attribs=Nullsv)
480491
SV * sth
481492
SV * statement
@@ -485,11 +496,13 @@ _prepare(sth, statement, attribs=Nullsv)
485496
D_imp_sth(sth);
486497
DBD_ATTRIBS_CHECK("_prepare", sth, attribs);
487498
#ifdef dbd_st_prepare_sv
488-
ST(0) = dbd_st_prepare_sv(sth, imp_sth, statement, attribs) ? &PL_sv_yes : &PL_sv_no;
499+
RETVAL = dbd_st_prepare_sv(sth, imp_sth, statement, attribs);
489500
#else
490-
ST(0) = dbd_st_prepare(sth, imp_sth, SvPV_nolen(statement), attribs) ? &PL_sv_yes : &PL_sv_no;
501+
RETVAL = dbd_st_prepare(sth, imp_sth, SvPV_nolen(statement), attribs);
491502
#endif
492503
}
504+
OUTPUT:
505+
RETVAL
493506

494507

495508
#ifdef dbd_st_rows
@@ -506,7 +519,7 @@ rows(sth)
506519

507520
#ifdef dbd_st_bind_col
508521

509-
void
522+
bool
510523
bind_col(sth, col, ref, attribs=Nullsv)
511524
SV * sth
512525
SV * col
@@ -531,20 +544,21 @@ bind_col(sth, col, ref, attribs=Nullsv)
531544
}
532545
}
533546
switch(dbd_st_bind_col(sth, imp_sth, col, ref, sql_type, attribs)) {
534-
case 2: ST(0) = &PL_sv_yes; /* job done completely */
547+
case 2: RETVAL = TRUE; /* job done completely */
535548
break;
536549
case 1: /* fallback to DBI default */
537-
ST(0) = (DBIc_DBISTATE(imp_sth)->bind_col(sth, col, ref, attribs))
538-
? &PL_sv_yes : &PL_sv_no;
550+
RETVAL = DBIc_DBISTATE(imp_sth)->bind_col(sth, col, ref, attribs);
539551
break;
540-
default: ST(0) = &PL_sv_no; /* dbd_st_bind_col has called set_err */
552+
default: RETVAL = FALSE; /* dbd_st_bind_col has called set_err */
541553
break;
542554
}
543555
}
556+
OUTPUT:
557+
RETVAL
544558

545559
#endif /* dbd_st_bind_col */
546560

547-
void
561+
bool
548562
bind_param(sth, param, value, attribs=Nullsv)
549563
SV * sth
550564
SV * param
@@ -568,12 +582,13 @@ bind_param(sth, param, value, attribs=Nullsv)
568582
DBD_ATTRIB_GET_IV(attribs, "TYPE",4, svp, sql_type);
569583
}
570584
}
571-
ST(0) = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, FALSE, 0)
572-
? &PL_sv_yes : &PL_sv_no;
585+
RETVAL = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, FALSE, 0);
573586
}
587+
OUTPUT:
588+
RETVAL
574589

575590

576-
void
591+
bool
577592
bind_param_inout(sth, param, value_ref, maxlen, attribs=Nullsv)
578593
SV * sth
579594
SV * param
@@ -603,9 +618,10 @@ bind_param_inout(sth, param, value_ref, maxlen, attribs=Nullsv)
603618
DBD_ATTRIB_GET_IV(attribs, "TYPE",4, svp, sql_type);
604619
}
605620
}
606-
ST(0) = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, TRUE, maxlen)
607-
? &PL_sv_yes : &PL_sv_no;
621+
RETVAL = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, TRUE, maxlen);
608622
}
623+
OUTPUT:
624+
RETVAL
609625

610626

611627
void
@@ -641,7 +657,8 @@ execute_for_fetch(sth, fetch_tuple_sub, tuple_status = Nullsv)
641657
CODE:
642658
{
643659
D_imp_sth(sth);
644-
ST(0) = dbd_st_execute_for_fetch(sth, imp_sth, fetch_tuple_sub, tuple_status);
660+
SV *ret = dbd_st_execute_for_fetch(sth, imp_sth, fetch_tuple_sub, tuple_status);
661+
ST(0) = ret;
645662
}
646663

647664
#endif
@@ -660,7 +677,8 @@ last_insert_id(sth, catalog=&PL_sv_undef, schema=&PL_sv_undef, table=&PL_sv_unde
660677
CODE:
661678
{
662679
D_imp_sth(sth);
663-
ST(0) = dbd_st_last_insert_id(sth, imp_sth, catalog, schema, table, field, attr);
680+
SV *ret = dbd_st_last_insert_id(sth, imp_sth, catalog, schema, table, field, attr);
681+
ST(0) = ret;
664682
}
665683

666684
#endif
@@ -717,7 +735,7 @@ fetchall_arrayref(sth, slice=&PL_sv_undef, batch_row_count=&PL_sv_undef)
717735
}
718736

719737

720-
void
738+
bool
721739
finish(sth)
722740
SV * sth
723741
CODE:
@@ -734,10 +752,12 @@ finish(sth)
734752
XSRETURN_YES;
735753
}
736754
#ifdef dbd_st_finish3
737-
ST(0) = dbd_st_finish3(sth, imp_sth, 0) ? &PL_sv_yes : &PL_sv_no;
755+
RETVAL = dbd_st_finish3(sth, imp_sth, 0);
738756
#else
739-
ST(0) = dbd_st_finish(sth, imp_sth) ? &PL_sv_yes : &PL_sv_no;
757+
RETVAL = dbd_st_finish(sth, imp_sth);
740758
#endif
759+
OUTPUT:
760+
RETVAL
741761

742762

743763
void

0 commit comments

Comments
 (0)