-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OCI_GetStruct calculates incorrect offset when a properly aligned Double is followed by an Int #12
Comments
Hi, Can you indicate the ocilib version , the oracle version and the platform (32/64bits) ? The following code (taken from you) give the expected results on Win32/Oracle 12c: int main()
{
OCI_Connection* cn;
OCI_Statement* st;
OCI_Resultset* rs;
int i;
OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT);
cn = OCI_ConnectionCreate("db12c", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
OCI_ExecuteStmtFmt(st, OTEXT("select val_char_1, val_char_2, val_double, val_long, val_char_3 from test_fetch_struct2"));
rs = OCI_GetResultset(st);
OCI_SetStructNumericType(rs, 3, OCI_NUM_DOUBLE);
OCI_SetStructNumericType(rs, 4, OCI_NUM_INT);
i = 0;
while (OCI_FetchNext(rs))
{
prd.val_char_1 = 0;
prd.val_char_2 = 0;
prd.val_double = 0.0;
prd.val_long = 0;
prd.val_char_3 = 0;
prd.extra = 0;
OCI_GetStruct(rs, &prd, &ind);
i++;
printf("\nrow %d\n", i);
printf(" > val_char_1 : %08X: %s\n", prd.val_char_1, prd.val_char_1);
printf(" > val_char_2 : %08X: %s\n", prd.val_char_2, prd.val_char_2);
printf(" > val_double : %Lf\n", prd.val_double);
printf(" > val_long : %d\n", prd.val_long);
printf(" > val_char_3 : %08X %s\n", prd.val_char_3, prd.val_char_3);
printf(" > extra : %08X: %s\n", prd.extra, prd.extra);
printf("\n");
}
OCI_Cleanup();
return EXIT_SUCCESS;
} the output is : row 1
row 2
row 3
Vincent |
Changelog.txt: 2015-05-05 Version 4.1.0 Vincent Rogier vince.rogier@ocilib.net Using Windows, lib32, ociliba.dll, Oracle 11.2g #define OCI_CHARSET_ANSI |
Hi, Can you try the code I've posted and tell me what results you got ? Thanks |
Posted code modified to: output results:
Execute: create table test_fetch_struct2(val_char_1 varchar2(30),val_char_2 varchar2(30),val_double number,val_long number(10),val_char_3 varchar2(30)) Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row1', 123.45, 1, 'col5 row1') Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row2', 234.56, 2, 'col5 row2') Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row3', 345.67, 3, 'col5 row3') row 1
A segment fault (signal 11) occurs attempting to print the string referenced by prd.val_char_3. int main(int argc, oarg* argv[])
// define the structure expected for the retrieval
// cn = OCI_ConnectionCreate("db12c", "usr", "pwd", OCI_SESSION_DEFAULT);
} |
What compiler are you using ? |
MSVC 2010 generating 32bit executable. |
Print statements added before the fetch loop:
produces:
Print statements added to the OCI_GetStruct function (around the existing ROUNDUP logic):
produces the following, where the 2nd roundup should be 4 instead of 8:
|
Hi, You were right indeed. My test and posted code were done using an 64bits build of OCILIB by mistake. Thanks :) Regards, Vincent |
Hi, Is that alright fro you ? Thanks Vincent |
A fix to the issue is good. While I am not using these functions, I did notice the same logic is used in the OCI_ObjectGetStructSize and OCI_ObjectGetUserStructSize functions, in case they also need an update. |
The existing OCI_GetStruct alignment calculation needs to be updated.
Summary:
For the table:
create table test_fetch_struct2(val_char_1 varchar2(30),val_char_2 varchar2(30),val_double number,val_long number(10),val_char_3 varchar2(30));
Expected C structure:
struct product_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
double val_double; // offset 8 :: column is natually aligned - no adjustment needed
int val_long; // offset 16
char *val_char_3; // offset 20
char *extra; // offset 24 :: don't abend on buffer overflow
} prd;
Actual C structure needed for OCI_GetStruct:
struct product2_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
char *bad_align; // offset 8 :: structure alignment calculation is skipping 4 extra bytes
float val_double; // offset 12 :: cheat to get the alignment being calculated
float val_double2; // offset 16
int val_long; // offset 20
char *val_char_3; // offset 24
char *extra; // offset 28 :: don't abend on buffer overflow
} prd2;
Details:
New OCI_GetStruct function:
/* --------------------------------------------------------------------------------------------- *
boolean OCI_API OCI_GetStructNew
(
OCI_Resultset *rs,
void *row_struct,
void *row_struct_ind
)
{
char *ptr = NULL;
boolean *inds = NULL;
// size_t alignForMax = 0;
// ptr should start at a proper double (8 byte) alignment
if (ptr)
{
size_t structSize = 0;
size_t size1 = 0;
size_t align1 = 0;
ub4 i;
// if (alignForMax < align1)
// {
// alignForMax = align1; // remember the largest alignment for this structure
// }
// if (alignForMax)
// {
// alignOffset = ptr % alignForMax; // how far off is the alignment?
// if (alignOffset)
// {
// ptr += (alignForMax - alignOffset); // adjust the pointer for this field
// }
// }
}
}
Test Code:
/*-----------
test_setup
-----------/
int test_setup (OCI_Connection *ociConn, OCI_Statement *ociStmt, OCI_Resultset *ociRset)
{
int retval = 0;
otext *sqlString;
prnlog("\n- test setup...\n");
sqlString = OTEXT("create table test_fetch_struct2")
OTEXT("(val_char_1 varchar2(30)")
OTEXT(",val_char_2 varchar2(30)")
OTEXT(",val_double number")
OTEXT(",val_long number(10)")
OTEXT(",val_char_3 varchar2(30)")
OTEXT(")")
;
prnlog("\nExecute: %s\n", sqlString);
OCI_ExecuteStmt(ociStmt, sqlString);
sqlString = OTEXT("insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) ")
OTEXT("values ('col1 row1', 'col2 row1', 123.45, 1, 'col5 row1')")
;
prnlog("\nExecute: %s\n", sqlString);
OCI_ExecuteStmt(ociStmt, sqlString);
sqlString = OTEXT("insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) ")
OTEXT("values ('col1 row1', 'col2 row2', 234.56, 2, 'col5 row2')")
;
prnlog("\nExecute: %s\n", sqlString);
OCI_ExecuteStmt(ociStmt, sqlString);
sqlString = OTEXT("insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) ")
OTEXT("values ('col1 row1', 'col2 row3', 345.67, 3, 'col5 row3')")
;
prnlog("\nExecute: %s\n", sqlString);
OCI_ExecuteStmt(ociStmt, sqlString);
OCI_Commit(ociConn);
OCI_ReleaseResultsets(ociStmt);
return(retval);
}
/*-------------
test cleanup
-------------/
int test_cleanup (OCI_Connection *ociConn, OCI_Statement *ociStmt, OCI_Resultset *ociRset)
{
int retval = 0;
prnlog("\n- test cleanup...\n");
oci_nofail = 1; /* ignore errors */
OCI_ExecuteStmt(ociStmt, OTEXT("drop table test_fetch_struct2"));
OCI_ReleaseResultsets(ociStmt);
oci_nofail = 0;
return(retval);
}
/*------------------
------------------/
int test_fetch_struct_bad (OCI_Connection *ociConn, OCI_Statement *ociStmt, OCI_Resultset *ociRset)
{
int retval = 0;
int iCnt;
// define the structure expected for the retrieval
struct product_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
double val_double; // offset 8 :: column is natually aligned - no adjustment needed
int val_long; // offset 16
char *val_char_3; // offset 20
char *extra; // offset 24 :: don't abend on buffer overflow
} prd;
// define the structure as mapped by the OCI_GetStruct function
struct product2_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
char *bad_align; // offset 8 :: structure alignment calculation is skipping 4 extra bytes
float val_double; // offset 12 :: cheat to get the alignment being calculated
float val_double2; // offset 16
int val_long; // offset 20
char *val_char_3; // offset 24
char *extra; // offset 28 :: don't abend on buffer overflow
} prd2;
// //////////////////////////
}
/*------------------
test_fetch_struct
------------------/
int test_fetch_struct_new (OCI_Connection *ociConn, OCI_Statement *ociStmt, OCI_Resultset *ociRset)
{
int retval = 0;
int iCnt;
struct product_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
double val_double; // offset 8
int val_long; // offset 16
char *val_char_3; // offset 20
char *extra; // don't abend on overflow
} prd;
struct prodind_t
{
boolean val_char_1;
boolean val_char_2;
boolean val_double;
boolean val_long;
boolean val_char_3;
} ind;
prnlog("\n- test fetch struct new: prd...\n"
" This shows the structure properly mapped by the updated logic\n");
OCI_ExecuteStmtFmt(ociStmt, OTEXT("select val_char_1, val_char_2, val_double, val_long, val_char_3 from test_fetch_struct2"));
ociRset = OCI_GetResultset(ociStmt);
OCI_SetStructNumericType(ociRset, 3, OCI_NUM_DOUBLE);
OCI_SetStructNumericType(ociRset, 4, OCI_NUM_INT);
iCnt = 0;
while (OCI_FetchNext(ociRset))
{
prd.extra = 0;
}
prnlog(" + %d row(s) fetched\n", OCI_GetRowCount(ociRset));
OCI_ReleaseResultsets(ociStmt);
retval = oci_rc;
return(retval);
}
Test output:
OCI Test
Oracle User : xxxxxxxx
Oracle DBName : myOraDB
Connect Role :
INFO-ORA-00942: table or view does not exist
Execute: create table test_fetch_struct2(val_char_1 varchar2(30),val_char_2 varchar2(30),val_double number,val_long number(10),val_char_3 varchar2(30))
Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row1', 123.45, 1, 'col5 row1')
Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row2', 234.56, 2, 'col5 row2')
Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row3', 345.67, 3, 'col5 row3')
This shows the val_long, and val_char_3, values shifted to the next column
row 1
row 2
row 3
This shows the structure as mapped by the OCI_GetStruct logic
row 1
row 2
row 3
This shows the structure properly mapped by the updated logic
row 1
row 2
row 3
OCILib Errors = 0
Oracle Errors = 0
Oracle Warnings= 0
The text was updated successfully, but these errors were encountered: