Skip to content
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

LDEV-4866 fix query parser out of bounds #2382

Open
wants to merge 1 commit into
base: 6.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions core/src/main/java/lucee/commons/lang/ParserString.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,17 @@ public final class ParserString {
* @param text CFML Code
*/
public ParserString(String text) {
init(text);
init(text, false);
}

/**
* This constructor allows stripping comments from SQL Text
*
* @param text SQL Text
* @param doIgnoreComments strip sql comments from text
*/
public ParserString(String text, boolean doIgnoreComments) {
init(text, doIgnoreComments);
}

/**
Expand All @@ -66,7 +76,8 @@ public ParserString(String text) {
*
* @param str
*/
protected void init(String str) {
protected void init(String str, boolean doIgnoreComments) {
if (doIgnoreComments) str = stripSqlComments(str);
int len = str.length();
text = new char[len];
lcText = new char[len];
Expand Down Expand Up @@ -700,6 +711,42 @@ public boolean removeSpace() {
}
return (start < pos);
}
/**
* Strip out all sql comments
*
* @return SQL text with comments stripped out
*/
public String stripSqlComments(String sql) {
char c;
int sqlLen = sql.length();
StringBuilder sb = new StringBuilder();

for (int i = 0; i < sqlLen; i++) {
c = sql.charAt(i);
if ( i < (sqlLen - 1)) {
// handle multi line comment
if (c == '/' && sql.charAt(i + 1) == '*') {
int end = sql.indexOf("*/", i + 2);
if (end != -1) {
i = end + 1;
continue;
}
}

// handle single line comment
if (c == '-' && i < (sqlLen - 1) && sql.charAt(i + 1) == '-') {
int end = sql.indexOf('\n', i + 1);
if (end == -1) {
break; // end of sql string
}
i = end;
continue;
}
}
sb.append(c);
}
return sb.toString().trim();
}

public void revertRemoveSpace() {
while (hasSpaceBefore()) {
Expand Down
8 changes: 5 additions & 3 deletions core/src/main/java/lucee/runtime/db/HSQLDBHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,8 @@ public QueryImpl execute(PageContext pc, final SQL sql, int maxrows, int fetchsi
if (spe.getCause() != null && spe.getCause() instanceof IllegalQoQException) {
throw Caster.toPageException(spe);
}
prettySQL = SQLPrettyfier.prettyfie(sql.getSQLString());
prettySQL = SQLPrettyfier.prettyfie(sql.getSQLString(), true);

try {
QueryImpl query = executer.execute(pc, sql, prettySQL, maxrows);
query.setExecutionTime(stopwatch.time());
Expand Down Expand Up @@ -326,7 +327,7 @@ public QueryImpl execute(PageContext pc, final SQL sql, int maxrows, int fetchsi
tables = hsql2.getInvokedTables();
}
else {
if (prettySQL == null) prettySQL = SQLPrettyfier.prettyfie(sql.getSQLString());
if (prettySQL == null) prettySQL = SQLPrettyfier.prettyfie(sql.getSQLString(),true);
HSQLUtil hsql = new HSQLUtil(prettySQL);
tables = hsql.getInvokedTables();
isUnion = hsql.isUnion();
Expand All @@ -339,7 +340,8 @@ public QueryImpl execute(PageContext pc, final SQL sql, int maxrows, int fetchsi

}
catch (ParseException e) {
throw new DatabaseException(e.getMessage(), null, sql, null);
throw (IllegalQoQException) (new IllegalQoQException("QoQ: error executing sql statement on query, " + e.getMessage(), null, sql, null).initCause(e));
//throw new DatabaseException(e.getMessage(), e, sql, null);
}

}
Expand Down
21 changes: 12 additions & 9 deletions core/src/main/java/lucee/runtime/db/SQLImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public String toString() {
int index = 0;
for (int i = 0; i < sqlLen; i++) {
c = strSQL.charAt(i);
if (!inQuotes && sqlLen + 1 > i) {
if (!inQuotes && i < (sqlLen - 1)) {
// read multi line
if (c == '/' && strSQL.charAt(i + 1) == '*') {
int end = strSQL.indexOf("*/", i + 2);
Expand All @@ -118,14 +118,16 @@ public String toString() {
}

// read single line
if (c == '-' && strSQL.charAt(i + 1) == '-') {
if (c == '-' && i < (sqlLen - 1) && strSQL.charAt(i + 1) == '-') {
int end = strSQL.indexOf('\n', i + 1);
if (end != -1) {
i = end + 1;
if (i == sqlLen) break;
c = strSQL.charAt(i);
}
else break;
if (end == -1) {
i = sqlLen; // end of sql string
} else {
i = end;
}
if (i == sqlLen) break;
//c = strSQL.charAt(i);
continue;
}
}

Expand All @@ -142,7 +144,8 @@ public String toString() {
sb.append(c);
}
else if (!inQuotes && c == '?') {
if ((index + 1) > items.length) throw new RuntimeException("there are more question marks in the SQL than params defined, in the SQL String: [" + strSQL + "]");
if ((index + 1) > items.length) throw new RuntimeException("There are more question marks [" + (index+1)
+ "] in the SQL than params defined [" + items.length + "], in the SQL String: [" + strSQL + "]");
if (items[index].isNulls()) sb.append("null");
else sb.append(SQLCaster.toString(items[index]));
index++;
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/lucee/runtime/db/SQLPrettyfier.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static String prettyfie(String sql) {

public static String prettyfie(String sql, boolean validZql) {

ParserString ps = new ParserString(sql.trim());
ParserString ps = new ParserString(sql.trim(),true);
boolean insideString = false;
// short insideKlammer=0;
StringBuilder sb = new StringBuilder(sql.length());
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/lucee/runtime/sql/SelectParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class SelectParser {
// select <select-statement> from <tables> where <where-statement>
public Selects parse(String sql) throws SQLParserException {
columnIndex = 0;
ParserString raw = new ParserString(sql.trim());
ParserString raw = new ParserString(sql.trim(),true);
Selects selects = new Selects();
Select select = new Select();

Expand Down Expand Up @@ -160,7 +160,7 @@ public Selects parse(String sql) throws SQLParserException {

if (raw.forwardIfCurrent(';')) raw.removeSpace();

if (!raw.isAfterLast()) throw new SQLParserException("can not read the full sql statement (stop at:" + raw.getCurrent() + ")");
if (!raw.isAfterLast()) throw new SQLParserException("Error parsing SQL statement (stop at char:" + raw.getCurrent() + ", pos: " + raw.getPos() + "), sql: [" + raw.toString() + "]");
return selects;
}

Expand Down
19 changes: 10 additions & 9 deletions core/src/main/java/lucee/runtime/tag/util/QueryParamConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,26 +146,27 @@ private static SQL convert(String sql, List<SQLItems<SQLItem>> items, List<SQLIt

for (int i = 0; i < sqlLen; i++) {
c = sql.charAt(i);
if (!inQuotes && sqlLen + 1 > i) {
if (!inQuotes && i < (sqlLen - 1)) {
// read multi line
if (c == '/' && sql.charAt(i + 1) == '*') {
int end = sql.indexOf("*/", i + 2);
if (end != -1) {
sb.append(sql.substring(i, end+2));
i = end + 2;
if (i == sqlLen) break;
c = sql.charAt(i);
}
}

// read single line
if (c == '-' && sql.charAt(i + 1) == '-') {
if (c == '-' && i < (sqlLen - 1) && sql.charAt(i + 1) == '-') {
int end = sql.indexOf('\n', i + 1);
if (end != -1) {
i = end + 1;
if (i == sqlLen) break;
c = sql.charAt(i);
}
else break;
if (end == -1) {
end = sqlLen-1; // end of sql string
}
sb.append(sql.substring(i, end+1));
i = end;
continue;
}
}

Expand All @@ -190,7 +191,7 @@ else if (!inQuotes) {
continue;
}

if (++_qm > initialParamSize) throw new ApplicationException("there are more question marks in the SQL than params defined", "SQL: " + sql + "");
if (++_qm > initialParamSize) throw new ApplicationException("There are more question marks ["+(qm+1)+"] in the SQL than params defined ["+initialParamSize+"], at position ["+ i +"]", "SQL: " + sql + ", ParsedSQL:" + sb.toString());
}
else if (c == ':') {

Expand Down
5 changes: 4 additions & 1 deletion test/_testRunner.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,17 @@ component {
}
*/
}
if ( !isNull( specStat.error.sql ) && !isEmpty( trim(specStat.error.sql) ) ){
systemOutput( TAB & "SQL: [" & specStat.error.sql & "]", true );
}
if ( !isNull( specStat.error.StackTrace ) && !isEmpty( specStat.error.StackTrace ) ){
systemOutput( TAB & specStat.error.type, true );
// printStackTrace( specStat.error.StackTrace );
systemOutput( TAB & specStat.error.StackTrace, true );
systemOutput( NL );
}

// systemOutput(NL & serialize(specStat.error), true);
//systemOutput(NL & serializeJson(specStat.error), true);

} // if !isNull
}
Expand Down
2 changes: 1 addition & 1 deletion test/tickets/LDEV1508.cfc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
component extends="org.lucee.cfml.test.LuceeTestCase" labels="mysql" {
component extends="org.lucee.cfml.test.LuceeTestCase" labels="mysql,qoq" {
// skip closure
function isNotSupported() {
var mySql = getCredentials();
Expand Down
3 changes: 1 addition & 2 deletions test/tickets/LDEV2754/test.cfm
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@
params = {
id : { value : 2, type : "integer" }
},
queryoptions = { dbtype = "query" }
queryoptions = { dbtype = "query", name="usingQOQ" }
);
writeOutput(usingQOQ.name);
}

</cfscript>
41 changes: 41 additions & 0 deletions test/tickets/LDEV4866.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
component extends="org.lucee.cfml.test.LuceeTestCase" labels="query" {

variables.ds = server.getDatasource( service="h2", dbFile=server._getTempDir( "LDEV4866" ) );
variables.params = { a:1, b:2 };

function run( testResults , testBox ) {
describe( title='LDEV-4866' , body=function(){
it( title='test query parsing, /* */-' , body=function() {
doQuery("#chr(13)# /* */- ");
doQuery("#chr(13)# /* */- ");
doQuery("/* */-");
});
it( title='test query parsing, just a - whitespace' , body=function() {
doQuery("#chr(9)# - #chr(13)# ");
});

it( title='test query parsing, just a -' , body=function() {
doQuery("-");
});

it( title='test query parsing, just a / whitespace' , body=function() {
doQuery("#chr(9)# / #chr(13)# ");
});
it( title='test query parsing, just a /' , body=function() {
doQuery("/");
});
});
}

private function doQuery(sql){
try {
query name="test" datasource="#ds#" params="#params#" {
echo( sql );
}
} catch (e) {
if ( e.stackTrace.indexOf("lucee.runtime.exp.DatabaseException:") neq 0 )
rethrow;
}
}

}
Loading