From ff0e077c4cdf88fa20d92910a479ba13632570d7 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 8 Jul 2026 15:26:25 +0300 Subject: [PATCH] Handle uncaught NumberFormatException at 20 parse sites (CodeQL java/uncaught-number-format-exception) Each site called Integer/Long/Double parsing on a value that reaches it without a surrounding catch, so malformed input escaped as a raw NumberFormatException. Every site is now routed to the failure mode that already fits its method contract, so callers get a controlled result instead of a leaking runtime exception. Untrusted / client input -> proper error: - MemoryBackend.Cookie.valueOf: an invalid pagedResultsCookie now yields BadRequestException (HTTP 400) instead of a 500; the caller maps it to a failed promise. - ElasticsearchAuditEventHandler.queryEvents: an invalid pagedResultsCookie now returns BadRequestException.asPromise() (400) instead of a 500. - QueryFilterParser: a non-numeric assertion value now returns the parser's existing valueOfIllegalArgument() result instead of throwing. - JwtClaimsSet: a non-numeric "exp" string claim now throws JwtRuntimeException (the class's own type-checking exception) with a clear message. Configuration input -> clear message / documented default: - AbstractJwtSessionModule: the token-idle-time and max-token-life settings are parsed via a helper that throws AuthenticationException naming the bad setting instead of a raw NumberFormatException. - AsynchronousTextWriter: an invalid CAPACITY system property now logs a warning and falls back to the default (32000) instead of failing class init. - RhinoScriptEngine: an invalid recompile-interval config value now logs a warning and falls back to the documented default (-1). - CrestIntegerSchema.setExample: a non-integer example now throws ValidationException (the schema classes' idiom) instead of a raw NFE. Sentinel-returning parsers -> existing sentinel: - Key/KeyParser.unicode(): a malformed \uXXXX escape now returns the method's existing -1 "cannot parse" sentinel. - JournalManager.fileToGeneration(): a non-numeric generation now returns the method's existing -1, matching the no-match branch. - Warning.valueOf(): a non-numeric warn-code now returns null, matching the method's documented "null if it could not be parsed" contract. Internal, developer-controlled specs -> loud but described failure: - ManagementTableModel.setup() and AdminUI.addLabeledField(): a malformed column/component specification now throws IllegalArgumentException naming the offending spec instead of a bare NumberFormatException. Behaviour is unchanged for valid input. Compiles: mvn -o -am compile across all eleven affected modules -> BUILD SUCCESS. --- .../writers/AsynchronousTextWriter.java | 19 ++++++++++++++++++- .../ElasticsearchAuditEventHandler.java | 7 ++++++- .../session/jwt/AbstractJwtSessionModule.java | 16 ++++++++++++---- .../org/forgerock/http/header/Warning.java | 8 +++++++- .../forgerock/json/jose/jwt/JwtClaimsSet.java | 7 ++++++- .../api/jackson/CrestIntegerSchema.java | 7 ++++++- .../json/resource/MemoryBackend.java | 16 +++++++++++++--- .../util/query/QueryFilterParser.java | 13 +++++++++++-- .../java/com/persistit/JournalManager.java | 7 ++++++- .../main/java/com/persistit/KeyParser.java | 8 +++++++- .../main/java/com/persistit/ui/AdminUI.java | 15 ++++++++++++--- .../persistit/ui/ManagementTableModel.java | 14 ++++++++++++-- .../script/javascript/RhinoScriptEngine.java | 15 ++++++++++++--- 13 files changed, 128 insertions(+), 24 deletions(-) diff --git a/commons/audit/core/src/main/java/org/forgerock/audit/events/handlers/writers/AsynchronousTextWriter.java b/commons/audit/core/src/main/java/org/forgerock/audit/events/handlers/writers/AsynchronousTextWriter.java index 4c0d3ab0ce..00b5ac2c5f 100644 --- a/commons/audit/core/src/main/java/org/forgerock/audit/events/handlers/writers/AsynchronousTextWriter.java +++ b/commons/audit/core/src/main/java/org/forgerock/audit/events/handlers/writers/AsynchronousTextWriter.java @@ -13,6 +13,7 @@ * * Copyright 2006-2008 Sun Microsystems, Inc. * Portions Copyright 2013-2015 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.forgerock.audit.events.handlers.writers; @@ -42,8 +43,24 @@ public class AsynchronousTextWriter implements TextWriter { private static final Logger logger = LoggerFactory.getLogger(AsynchronousTextWriter.class); + /** System property overriding the default queue capacity. */ + private static final String CAPACITY_PROPERTY = + "org.forgerock.audit.events.handlers.writers.AsynchronousTextWriter.CAPACITY"; + /** Default queue capacity used when {@link #CAPACITY_PROPERTY} is unset or invalid. */ + private static final int DEFAULT_CAPACITY = 32000; /** Maximum number of messages that can be queued before producers start to block. */ - private static final int CAPACITY = Integer.parseInt(System.getProperty("org.forgerock.audit.events.handlers.writers.AsynchronousTextWriter.CAPACITY","32000")); + private static final int CAPACITY = readCapacity(); + + private static int readCapacity() { + final String value = System.getProperty(CAPACITY_PROPERTY, String.valueOf(DEFAULT_CAPACITY)); + try { + return Integer.parseInt(value); + } catch (final NumberFormatException e) { + logger.warn("Invalid value '{}' for system property {}; using default {}.", + value, CAPACITY_PROPERTY, DEFAULT_CAPACITY); + return DEFAULT_CAPACITY; + } + } /** The wrapped Text Writer. */ private final TextWriter writer; diff --git a/commons/audit/handler-elasticsearch/src/main/java/org/forgerock/audit/handlers/elasticsearch/ElasticsearchAuditEventHandler.java b/commons/audit/handler-elasticsearch/src/main/java/org/forgerock/audit/handlers/elasticsearch/ElasticsearchAuditEventHandler.java index 03882b9d64..16ef0b7c22 100644 --- a/commons/audit/handler-elasticsearch/src/main/java/org/forgerock/audit/handlers/elasticsearch/ElasticsearchAuditEventHandler.java +++ b/commons/audit/handler-elasticsearch/src/main/java/org/forgerock/audit/handlers/elasticsearch/ElasticsearchAuditEventHandler.java @@ -54,6 +54,7 @@ import org.forgerock.http.protocol.Responses; import org.forgerock.http.spi.Loader; import org.forgerock.json.JsonValue; +import org.forgerock.json.resource.BadRequestException; import org.forgerock.json.resource.CountPolicy; import org.forgerock.json.resource.InternalServerErrorException; import org.forgerock.json.resource.NotFoundException; @@ -199,7 +200,11 @@ public Promise queryEvents(final Context conte if (query.getPagedResultsOffset() != 0) { offset = query.getPagedResultsOffset(); } else if (query.getPagedResultsCookie() != null) { - offset = Integer.valueOf(query.getPagedResultsCookie()); + try { + offset = Integer.parseInt(query.getPagedResultsCookie()); + } catch (final NumberFormatException e) { + return new BadRequestException("Invalid paged results cookie", e).asPromise(); + } } else { offset = DEFAULT_OFFSET; } diff --git a/commons/auth-filters/authn-filter/jaspi-modules/jwt-session-module/src/main/java/org/forgerock/jaspi/modules/session/jwt/AbstractJwtSessionModule.java b/commons/auth-filters/authn-filter/jaspi-modules/jwt-session-module/src/main/java/org/forgerock/jaspi/modules/session/jwt/AbstractJwtSessionModule.java index 722a8b2a3f..d62a3e1c76 100644 --- a/commons/auth-filters/authn-filter/jaspi-modules/jwt-session-module/src/main/java/org/forgerock/jaspi/modules/session/jwt/AbstractJwtSessionModule.java +++ b/commons/auth-filters/authn-filter/jaspi-modules/jwt-session-module/src/main/java/org/forgerock/jaspi/modules/session/jwt/AbstractJwtSessionModule.java @@ -168,9 +168,9 @@ public void initialize(CallbackHandler handler, Map options) throws Authenticati throw new AuthenticationException("Can't use both " + TOKEN_IDLE_TIME_IN_MINUTES_CLAIM_KEY + " setting and the " + TOKEN_IDLE_TIME_IN_SECONDS_CLAIM_KEY + " setting."); } else if (!isEmpty(tokenIdleTimeMinutes)) { - this.tokenIdleTime = Integer.parseInt(tokenIdleTimeMinutes) * 60; + this.tokenIdleTime = parseIntSetting(TOKEN_IDLE_TIME_IN_MINUTES_CLAIM_KEY, tokenIdleTimeMinutes) * 60; } else if (!isEmpty(tokenIdleTimeSeconds)) { - this.tokenIdleTime = Integer.parseInt(tokenIdleTimeSeconds); + this.tokenIdleTime = parseIntSetting(TOKEN_IDLE_TIME_IN_SECONDS_CLAIM_KEY, tokenIdleTimeSeconds); } else { this.tokenIdleTime = 0; } @@ -180,9 +180,9 @@ public void initialize(CallbackHandler handler, Map options) throws Authenticati throw new AuthenticationException("Can't use both the " + MAX_TOKEN_LIFE_IN_MINUTES_KEY + " setting and the " + MAX_TOKEN_LIFE_IN_SECONDS_KEY + " setting."); } else if (!isEmpty(maxTokenLifeMinutes)) { - this.maxTokenLife = Integer.parseInt(maxTokenLifeMinutes) * 60; + this.maxTokenLife = parseIntSetting(MAX_TOKEN_LIFE_IN_MINUTES_KEY, maxTokenLifeMinutes) * 60; } else if (!isEmpty(maxTokenLifeSeconds)) { - this.maxTokenLife = Integer.parseInt(maxTokenLifeSeconds); + this.maxTokenLife = parseIntSetting(MAX_TOKEN_LIFE_IN_SECONDS_KEY, maxTokenLifeSeconds); } else { this.maxTokenLife = 0; } @@ -204,6 +204,14 @@ public void initialize(CallbackHandler handler, Map options) throws Authenticati Arrays.fill(signingKey, (byte) 0); } + private static int parseIntSetting(final String settingName, final String value) throws AuthenticationException { + try { + return Integer.parseInt(value); + } catch (final NumberFormatException e) { + throw new AuthenticationException("The " + settingName + " setting must be an integer, but was: " + value); + } + } + /** * Checks for the presence of the JWT as a Cookie on the request and validates the signature and decrypts it and * checks the expiration time of the JWT. If all these checks pass then the method return AuthStatus.SUCCESS, diff --git a/commons/http-framework/core/src/main/java/org/forgerock/http/header/Warning.java b/commons/http-framework/core/src/main/java/org/forgerock/http/header/Warning.java index e46e813e6b..11c4d54260 100644 --- a/commons/http-framework/core/src/main/java/org/forgerock/http/header/Warning.java +++ b/commons/http-framework/core/src/main/java/org/forgerock/http/header/Warning.java @@ -12,6 +12,7 @@ * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2016 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.forgerock.http.header; @@ -150,7 +151,12 @@ public int hashCode() { public static Warning valueOf(final String value) { final Matcher m = PATTERN.matcher(value); if (m.matches()) { - final int code = Integer.parseInt(m.group(1)); + final int code; + try { + code = Integer.parseInt(m.group(1)); + } catch (final NumberFormatException e) { + return null; + } final String agent = m.group(2); final String tail = m.group(3); final String text; diff --git a/commons/json-web-token/src/main/java/org/forgerock/json/jose/jwt/JwtClaimsSet.java b/commons/json-web-token/src/main/java/org/forgerock/json/jose/jwt/JwtClaimsSet.java index ec1f9b1994..7376b36b02 100644 --- a/commons/json-web-token/src/main/java/org/forgerock/json/jose/jwt/JwtClaimsSet.java +++ b/commons/json-web-token/src/main/java/org/forgerock/json/jose/jwt/JwtClaimsSet.java @@ -27,6 +27,7 @@ import java.util.Map; import org.forgerock.json.JsonValue; +import org.forgerock.json.jose.exceptions.JwtRuntimeException; import org.forgerock.json.jose.utils.IntDate; import org.forgerock.json.jose.utils.StringOrURI; @@ -397,7 +398,11 @@ public void setClaim(String key, Object value) { if (isValueOfType(value, Number.class)) { setExpirationTime(((Number) value).longValue()); } else if (isValueOfType(value, String.class)) { - setExpirationTime(Long.parseLong((String)value)); + try { + setExpirationTime(Long.parseLong((String) value)); + } catch (final NumberFormatException e) { + throw new JwtRuntimeException("Expiration time claim (exp) is not a valid number: " + value, e); + } } else { checkValueIsOfType(value, Date.class); setExpirationTime((Date) value); diff --git a/commons/rest/api-descriptor/src/main/java/org/forgerock/api/jackson/CrestIntegerSchema.java b/commons/rest/api-descriptor/src/main/java/org/forgerock/api/jackson/CrestIntegerSchema.java index 402fd645d6..c2c3195d5d 100644 --- a/commons/rest/api-descriptor/src/main/java/org/forgerock/api/jackson/CrestIntegerSchema.java +++ b/commons/rest/api-descriptor/src/main/java/org/forgerock/api/jackson/CrestIntegerSchema.java @@ -12,6 +12,7 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2016 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.forgerock.api.jackson; @@ -194,6 +195,10 @@ public Long getExample() { @Override public void setExample(String example) { - this.example = Long.valueOf(example); + try { + this.example = Long.valueOf(example); + } catch (final NumberFormatException e) { + throw new ValidationException("Example value is not a valid integer: " + example); + } } } diff --git a/commons/rest/json-resource/src/main/java/org/forgerock/json/resource/MemoryBackend.java b/commons/rest/json-resource/src/main/java/org/forgerock/json/resource/MemoryBackend.java index 0e1df3f767..822cf5d14c 100644 --- a/commons/rest/json-resource/src/main/java/org/forgerock/json/resource/MemoryBackend.java +++ b/commons/rest/json-resource/src/main/java/org/forgerock/json/resource/MemoryBackend.java @@ -12,6 +12,7 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2012-2015 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.forgerock.json.resource; @@ -68,10 +69,15 @@ private static final class Cookie { this.lastResultIndex = lastResultIndex; } - static Cookie valueOf(String base64) { + static Cookie valueOf(String base64) throws ResourceException { final String decoded = new String(Base64.decode(base64)); final String[] split = decoded.split(":"); - final int lastOffset = Integer.parseInt(split[0]); + final int lastOffset; + try { + lastOffset = Integer.parseInt(split[0]); + } catch (final NumberFormatException e) { + throw new BadRequestException("Invalid paged results cookie", e); + } final List sortKeys = new ArrayList<>(); final String[] splitKeys = split[1].split(","); @@ -596,7 +602,11 @@ public Promise queryCollection(final Context c return new BadRequestException("Cookies and offsets are mutually exclusive").asPromise(); } - firstResultIndex = Cookie.valueOf(pagedResultsCookie).getLastResultIndex(); + try { + firstResultIndex = Cookie.valueOf(pagedResultsCookie).getLastResultIndex(); + } catch (final ResourceException e) { + return e.asPromise(); + } } else { if (request.getPagedResultsOffset() > 0) { firstResultIndex = request.getPagedResultsOffset(); diff --git a/commons/util/util/src/main/java/org/forgerock/util/query/QueryFilterParser.java b/commons/util/util/src/main/java/org/forgerock/util/query/QueryFilterParser.java index 3af587d74c..04ee900941 100644 --- a/commons/util/util/src/main/java/org/forgerock/util/query/QueryFilterParser.java +++ b/commons/util/util/src/main/java/org/forgerock/util/query/QueryFilterParser.java @@ -12,6 +12,7 @@ * information: "Portions copyright [year] [name of copyright owner]". * * Copyright 2015 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.forgerock.util.query; @@ -217,10 +218,18 @@ private QueryFilter valueOfPrimaryExpr(final FilterTokenizer tokenizer, final assertionValue = Boolean.parseBoolean(nextToken); } else if (nextToken.indexOf('.') >= 0) { // Floating point number. - assertionValue = Double.parseDouble(nextToken); + try { + assertionValue = Double.parseDouble(nextToken); + } catch (final NumberFormatException e) { + return valueOfIllegalArgument(tokenizer); + } } else { // Must be an integer. - assertionValue = Long.parseLong(nextToken); + try { + assertionValue = Long.parseLong(nextToken); + } catch (final NumberFormatException e) { + return valueOfIllegalArgument(tokenizer); + } } try { return comparisonFilter(pointer, operator, assertionValue); diff --git a/persistit/core/src/main/java/com/persistit/JournalManager.java b/persistit/core/src/main/java/com/persistit/JournalManager.java index 0ce109579b..f0aa71af04 100644 --- a/persistit/core/src/main/java/com/persistit/JournalManager.java +++ b/persistit/core/src/main/java/com/persistit/JournalManager.java @@ -1,6 +1,7 @@ /** * Copyright 2011-2012 Akiban Technologies, Inc. * Copyright 2015 ForgeRock AS + * Portions Copyrighted 2026 3A Systems, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1261,7 +1262,11 @@ static File journalPath(final String path) { static long fileToGeneration(final File file) { final Matcher matcher = PATH_PATTERN.matcher(file.getName()); if (matcher.matches()) { - return Long.parseLong(matcher.group(2)); + try { + return Long.parseLong(matcher.group(2)); + } catch (final NumberFormatException e) { + return -1; + } } else { return -1; } diff --git a/persistit/core/src/main/java/com/persistit/KeyParser.java b/persistit/core/src/main/java/com/persistit/KeyParser.java index 3fc768a06d..74e9ab1723 100644 --- a/persistit/core/src/main/java/com/persistit/KeyParser.java +++ b/persistit/core/src/main/java/com/persistit/KeyParser.java @@ -1,5 +1,6 @@ /** * Copyright 2005-2012 Akiban Technologies, Inc. + * Portions Copyrighted 2026 3A Systems, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -535,7 +536,12 @@ else if (c == '\"') { private int unicode() { if (_index + 4 > _end) return -1; - final int u = Integer.parseInt(_source.substring(_index, _index + 4), 16); + final int u; + try { + u = Integer.parseInt(_source.substring(_index, _index + 4), 16); + } catch (final NumberFormatException e) { + return -1; + } _index += 4; return u; } diff --git a/persistit/ui/src/main/java/com/persistit/ui/AdminUI.java b/persistit/ui/src/main/java/com/persistit/ui/AdminUI.java index 5a47719ae6..047526f89d 100644 --- a/persistit/ui/src/main/java/com/persistit/ui/AdminUI.java +++ b/persistit/ui/src/main/java/com/persistit/ui/AdminUI.java @@ -1,5 +1,6 @@ /** * Copyright 2005-2012 Akiban Technologies, Inc. + * Portions Copyrighted 2026 3A Systems, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -705,7 +706,7 @@ JComponent addLabeledField(final JPanel panel, final GridBagConstraints gbc, fin JComponent wrappedComponent = component; if (component instanceof JTextField) { final JTextField textField = (JTextField) component; - textField.setColumns(Integer.parseInt(widthStr)); + textField.setColumns(parseDimension("width", widthStr)); textField.setHorizontalAlignment(alignment.equals("R") ? SwingConstants.TRAILING : alignment.equals("C") ? SwingConstants.CENTER : SwingConstants.LEADING); textField.setEditable(false); @@ -713,8 +714,8 @@ JComponent addLabeledField(final JPanel panel, final GridBagConstraints gbc, fin textField.setBackground(Color.white); } else if (component instanceof JTextArea) { final JTextArea textArea = (JTextArea) component; - textArea.setColumns(Integer.parseInt(widthStr)); - textArea.setRows(Integer.parseInt(heightStr)); + textArea.setColumns(parseDimension("width", widthStr)); + textArea.setRows(parseDimension("height", heightStr)); textArea.setEditable(false); textArea.setEnabled(true); textArea.setBackground(Color.white); @@ -736,6 +737,14 @@ JComponent addLabeledField(final JPanel panel, final GridBagConstraints gbc, fin return component; } + private static int parseDimension(final String name, final String value) { + try { + return Integer.parseInt(value); + } catch (final NumberFormatException e) { + throw new IllegalArgumentException("Invalid " + name + " in component specification: " + value, e); + } + } + AdminAction createAction(final AdminCommand command, final String specification) { final StringTokenizer st = new StringTokenizer(specification, ":"); String actionName = st.nextToken(); diff --git a/persistit/ui/src/main/java/com/persistit/ui/ManagementTableModel.java b/persistit/ui/src/main/java/com/persistit/ui/ManagementTableModel.java index 82876ac073..0a14c513e7 100644 --- a/persistit/ui/src/main/java/com/persistit/ui/ManagementTableModel.java +++ b/persistit/ui/src/main/java/com/persistit/ui/ManagementTableModel.java @@ -113,13 +113,23 @@ protected void setup(final Class clazz, final String[] columnSpecs) throws NoSuc for (int index = 0; index < columnSpecs.length; index++) { final StringTokenizer st = new StringTokenizer(columnSpecs[index], ":"); final String methodName = st.nextToken(); - final int width = Integer.parseInt(st.nextToken()); + final int width; + try { + width = Integer.parseInt(st.nextToken()); + } catch (final NumberFormatException e) { + throw new IllegalArgumentException("Invalid width in column specification: " + columnSpecs[index], e); + } final String flags = st.nextToken(); final String header = st.nextToken(); String rendererName = null; int minWidth = width / 2; if (st.hasMoreTokens()) { - minWidth = Integer.parseInt(st.nextToken()); + try { + minWidth = Integer.parseInt(st.nextToken()); + } catch (final NumberFormatException e) { + throw new IllegalArgumentException( + "Invalid minimum width in column specification: " + columnSpecs[index], e); + } } if (st.hasMoreTokens()) { rendererName = st.nextToken(); diff --git a/script/javascript/src/main/java/org/forgerock/script/javascript/RhinoScriptEngine.java b/script/javascript/src/main/java/org/forgerock/script/javascript/RhinoScriptEngine.java index c4a0cd1ab6..d6aca0f5af 100644 --- a/script/javascript/src/main/java/org/forgerock/script/javascript/RhinoScriptEngine.java +++ b/script/javascript/src/main/java/org/forgerock/script/javascript/RhinoScriptEngine.java @@ -18,7 +18,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * * Copyright 2012-2016 ForgeRock AS. - * Portions Copyrighted 2018-2025 3A Systems, LLC + * Portions Copyrighted 2018-2026 3A Systems, LLC */ package org.forgerock.script.javascript; @@ -96,8 +96,17 @@ public class RhinoScriptEngine extends AbstractScriptEngine { this.factory = factory; final JsonValue jsonValueConfig = new JsonValue(configuration); initDebugListener(jsonValueConfig.get(CONFIG_DEBUG_PROPERTY).defaultTo(null).asString()); - minimumRecompilationInterval = Long.valueOf( - jsonValueConfig.get(CONFIG_RECOMPILE_MINIMUM_INTERVAL_PROPERTY).defaultTo("-1").asString()); + final String recompileInterval = + jsonValueConfig.get(CONFIG_RECOMPILE_MINIMUM_INTERVAL_PROPERTY).defaultTo("-1").asString(); + long minimumRecompilationIntervalValue; + try { + minimumRecompilationIntervalValue = Long.parseLong(recompileInterval); + } catch (final NumberFormatException e) { + logger.warn("Invalid {} configuration value '{}'; using default -1.", + CONFIG_RECOMPILE_MINIMUM_INTERVAL_PROPERTY, recompileInterval); + minimumRecompilationIntervalValue = -1; + } + minimumRecompilationInterval = minimumRecompilationIntervalValue; scriptExceptionGenerator = jsonValueConfig.get(CONFIG_EXCEPTION_DEBUG_INFO).defaultTo(true).asBoolean() ? DEBUG_SCRIPT_EXCEPTION_GENERATOR : NON_DEBUG_SCRIPT_EXCEPTION_GENERATOR;