From e190739b5a188f74114bfdaecc7ed5645c131017 Mon Sep 17 00:00:00 2001 From: Henry Lee Date: Thu, 30 Nov 2023 19:52:22 +0900 Subject: [PATCH] refactor(java): logging-log4j-audit --- .../Dockerfile | 18 + .../buggy.java | 217 +++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 85 ++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 87 ++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 87 ++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 82 ++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 185 ++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 209 +++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 211 +++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 209 +++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 212 +++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 85 ++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 100 ++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 102 +++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 91 ++++ .../metadata.json | 21 + .../npe.json | 7 + Java/logging-log4j-audit-Event_178/Dockerfile | 18 + Java/logging-log4j-audit-Event_178/buggy.java | 193 ++++++++ .../metadata.json | 21 + Java/logging-log4j-audit-Event_178/npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 308 +++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 305 +++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 308 +++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 420 +++++++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 420 +++++++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 429 ++++++++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 417 +++++++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 417 +++++++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + .../Dockerfile | 18 + .../buggy.java | 416 +++++++++++++++++ .../metadata.json | 21 + .../npe.json | 7 + 96 files changed, 6699 insertions(+) create mode 100644 Java/logging-log4j-audit-AbstractEventLogger_113/Dockerfile create mode 100644 Java/logging-log4j-audit-AbstractEventLogger_113/buggy.java create mode 100644 Java/logging-log4j-audit-AbstractEventLogger_113/metadata.json create mode 100644 Java/logging-log4j-audit-AbstractEventLogger_113/npe.json create mode 100644 Java/logging-log4j-audit-AttributeConverter_48/Dockerfile create mode 100644 Java/logging-log4j-audit-AttributeConverter_48/buggy.java create mode 100644 Java/logging-log4j-audit-AttributeConverter_48/metadata.json create mode 100644 Java/logging-log4j-audit-AttributeConverter_48/npe.json create mode 100644 Java/logging-log4j-audit-AttributeConverter_65/Dockerfile create mode 100644 Java/logging-log4j-audit-AttributeConverter_65/buggy.java create mode 100644 Java/logging-log4j-audit-AttributeConverter_65/metadata.json create mode 100644 Java/logging-log4j-audit-AttributeConverter_65/npe.json create mode 100644 Java/logging-log4j-audit-AttributeConverter_69/Dockerfile create mode 100644 Java/logging-log4j-audit-AttributeConverter_69/buggy.java create mode 100644 Java/logging-log4j-audit-AttributeConverter_69/metadata.json create mode 100644 Java/logging-log4j-audit-AttributeConverter_69/npe.json create mode 100644 Java/logging-log4j-audit-AttributeConverter_73/Dockerfile create mode 100644 Java/logging-log4j-audit-AttributeConverter_73/buggy.java create mode 100644 Java/logging-log4j-audit-AttributeConverter_73/metadata.json create mode 100644 Java/logging-log4j-audit-AttributeConverter_73/npe.json create mode 100644 Java/logging-log4j-audit-AuditCatalogManager_94/Dockerfile create mode 100644 Java/logging-log4j-audit-AuditCatalogManager_94/buggy.java create mode 100644 Java/logging-log4j-audit-AuditCatalogManager_94/metadata.json create mode 100644 Java/logging-log4j-audit-AuditCatalogManager_94/npe.json create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_140/Dockerfile create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_140/buggy.java create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_140/metadata.json create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_140/npe.json create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_168/Dockerfile create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_168/buggy.java create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_168/metadata.json create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_168/npe.json create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_172/Dockerfile create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_172/buggy.java create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_172/metadata.json create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_172/npe.json create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_90/Dockerfile create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_90/buggy.java create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_90/metadata.json create mode 100644 Java/logging-log4j-audit-CatalogManagerImpl_90/npe.json create mode 100644 Java/logging-log4j-audit-ConstraintModel_80/Dockerfile create mode 100644 Java/logging-log4j-audit-ConstraintModel_80/buggy.java create mode 100644 Java/logging-log4j-audit-ConstraintModel_80/metadata.json create mode 100644 Java/logging-log4j-audit-ConstraintModel_80/npe.json create mode 100644 Java/logging-log4j-audit-EventConverter_55/Dockerfile create mode 100644 Java/logging-log4j-audit-EventConverter_55/buggy.java create mode 100644 Java/logging-log4j-audit-EventConverter_55/metadata.json create mode 100644 Java/logging-log4j-audit-EventConverter_55/npe.json create mode 100644 Java/logging-log4j-audit-EventConverter_70/Dockerfile create mode 100644 Java/logging-log4j-audit-EventConverter_70/buggy.java create mode 100644 Java/logging-log4j-audit-EventConverter_70/metadata.json create mode 100644 Java/logging-log4j-audit-EventConverter_70/npe.json create mode 100644 Java/logging-log4j-audit-EventConverter_74/Dockerfile create mode 100644 Java/logging-log4j-audit-EventConverter_74/buggy.java create mode 100644 Java/logging-log4j-audit-EventConverter_74/metadata.json create mode 100644 Java/logging-log4j-audit-EventConverter_74/npe.json create mode 100644 Java/logging-log4j-audit-Event_178/Dockerfile create mode 100644 Java/logging-log4j-audit-Event_178/buggy.java create mode 100644 Java/logging-log4j-audit-Event_178/metadata.json create mode 100644 Java/logging-log4j-audit-Event_178/npe.json create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_169/Dockerfile create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_169/buggy.java create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_169/metadata.json create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_169/npe.json create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_172/Dockerfile create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_172/buggy.java create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_172/metadata.json create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_172/npe.json create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_268/Dockerfile create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_268/buggy.java create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_268/metadata.json create mode 100644 Java/logging-log4j-audit-InterfacesGenerator_268/npe.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_102/Dockerfile create mode 100644 Java/logging-log4j-audit-LogEventFactory_102/buggy.java create mode 100644 Java/logging-log4j-audit-LogEventFactory_102/metadata.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_102/npe.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_107/Dockerfile create mode 100644 Java/logging-log4j-audit-LogEventFactory_107/buggy.java create mode 100644 Java/logging-log4j-audit-LogEventFactory_107/metadata.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_107/npe.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_137/Dockerfile create mode 100644 Java/logging-log4j-audit-LogEventFactory_137/buggy.java create mode 100644 Java/logging-log4j-audit-LogEventFactory_137/metadata.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_137/npe.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_378/Dockerfile create mode 100644 Java/logging-log4j-audit-LogEventFactory_378/buggy.java create mode 100644 Java/logging-log4j-audit-LogEventFactory_378/metadata.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_378/npe.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_389/Dockerfile create mode 100644 Java/logging-log4j-audit-LogEventFactory_389/buggy.java create mode 100644 Java/logging-log4j-audit-LogEventFactory_389/metadata.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_389/npe.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_395/Dockerfile create mode 100644 Java/logging-log4j-audit-LogEventFactory_395/buggy.java create mode 100644 Java/logging-log4j-audit-LogEventFactory_395/metadata.json create mode 100644 Java/logging-log4j-audit-LogEventFactory_395/npe.json diff --git a/Java/logging-log4j-audit-AbstractEventLogger_113/Dockerfile b/Java/logging-log4j-audit-AbstractEventLogger_113/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-AbstractEventLogger_113/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-AbstractEventLogger_113/buggy.java b/Java/logging-log4j-audit-AbstractEventLogger_113/buggy.java new file mode 100644 index 000000000..4fb1bd858 --- /dev/null +++ b/Java/logging-log4j-audit-AbstractEventLogger_113/buggy.java @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit; + +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.audit.catalog.CatalogManager; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.exception.ConstraintValidationException; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.Constraint; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; +import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins; +import org.apache.logging.log4j.message.StructuredDataMessage; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; + +/** + * This class is used to log events generated remotely. + */ +public abstract class AbstractEventLogger { + + private static final int DEFAULT_MAX_LENGTH = 32; + + private static final ConstraintPlugins constraintPlugins = ConstraintPlugins.getInstance(); + + public CatalogManager catalogManager; + + private static final AuditExceptionHandler DEFAULT_EXCEPTION_HANDLER = (message, ex) -> { + throw new AuditException("Error logging event " + message.getId().getName(), ex); + }; + + private static final AuditExceptionHandler NOOP_EXCEPTION_HANDLER = (message, ex) -> { + }; + + private AuditExceptionHandler defaultAuditExceptionHandler = DEFAULT_EXCEPTION_HANDLER; + + private final int maxLength; + + protected AbstractEventLogger() { + maxLength = DEFAULT_MAX_LENGTH; + } + + protected AbstractEventLogger(int maxLength) { + this.maxLength = maxLength; + } + + public void setCatalogManager(CatalogManager catalogManager) { + this.catalogManager = catalogManager; + } + + public List getAttributeNames(String eventId) { + return catalogManager.getAttributeNames(eventId); + } + + public void setDefaultAuditExceptionHandler(AuditExceptionHandler auditExceptionHandler) { + defaultAuditExceptionHandler = auditExceptionHandler == null ? NOOP_EXCEPTION_HANDLER : auditExceptionHandler; + } + + public void logEvent(String eventName, Map attributes) { + logEvent(eventName, null, attributes, defaultAuditExceptionHandler); + } + + public void logEvent(String eventName, String catalogId, Map attributes) { + logEvent(eventName, catalogId, attributes, defaultAuditExceptionHandler); + } + + public void logEvent(String eventName, Map attributes, AuditExceptionHandler exceptionHandler) { + logEvent(eventName, null, attributes, exceptionHandler); + } + + private void logEvent(String eventName, String catalogId, Map attributes, AuditExceptionHandler exceptionHandler) { + Event event = catalogId == null ? catalogManager.getEvent(eventName) : catalogManager.getEvent(eventName, catalogId); + if (event == null) { + throw new AuditException("Unable to locate definition of audit event " + eventName); + } + logEvent(eventName, attributes, event, exceptionHandler); + } + + protected abstract void logEvent(StructuredDataMessage message); + +private void logEvent(java.lang.String eventName, java.util.Map attributes, org.apache.logging.log4j.catalog.api.Event event, org.apache.logging.log4j.audit.AuditExceptionHandler exceptionHandler) { + org.apache.logging.log4j.audit.AuditMessage msg = new org.apache.logging.log4j.audit.AuditMessage(eventName, maxLength); + if (attributes == null) { + attributes = java.util.Collections.emptyMap(); + } + java.lang.StringBuilder missingAttributes = new java.lang.StringBuilder(); + java.lang.StringBuilder errors = new java.lang.StringBuilder(); + java.util.List eventAttributes = /* NPEX_NULL_EXP */ + event.getAttributes(); + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : eventAttributes) { + org.apache.logging.log4j.catalog.api.Attribute attr = catalogManager.getAttribute(eventAttribute.getName(), event.getCatalogId()); + if (((!attr.isRequestContext()) && attr.isRequired()) || ((eventAttribute.isRequired() != null) && eventAttribute.isRequired())) { + java.lang.String name = attr.getName(); + if (!attributes.containsKey(name)) { + if (missingAttributes.length() > 0) { + missingAttributes.append(", "); + } + missingAttributes.append(name); + } else if ((attr.getConstraints() != null) && (attr.getConstraints().size() > 0)) { + org.apache.logging.log4j.audit.AbstractEventLogger.validateConstraints(false, attr.getConstraints(), name, attributes.get(name), errors); + } + } + } + java.util.Map attributeMap = catalogManager.getAttributes(eventName, event.getCatalogId()); + for (java.lang.String name : attributes.keySet()) { + if ((!attributeMap.containsKey(name)) && (!name.equals("completionStatus"))) { + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append("Attribute ").append(name).append(" is not defined for ").append(eventName); + } + } + if (missingAttributes.length() > 0) { + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append("Event ").append(eventName).append(" is missing required attribute(s) ").append(missingAttributes.toString()); + } + if (errors.length() > 0) { + throw new org.apache.logging.log4j.audit.exception.ConstraintValidationException(errors.toString()); + } + java.util.List attributeNames = catalogManager.getAttributeNames(eventName, event.getCatalogId()); + java.lang.StringBuilder buf = new java.lang.StringBuilder(); + for (java.lang.String attribute : attributes.keySet()) { + if (!attributeNames.contains(attribute)) { + if (buf.length() > 0) { + buf.append(", "); + } + buf.append(attribute); + } + } + if (buf.length() > 0) { + throw new org.apache.logging.log4j.audit.exception.ConstraintValidationException((("Event " + eventName) + " contains invalid attribute(s) ") + buf.toString()); + } + java.util.List reqCtxAttrs = catalogManager.getRequiredContextAttributes(eventName, event.getCatalogId()); + if ((reqCtxAttrs != null) && (!reqCtxAttrs.isEmpty())) { + java.lang.StringBuilder sb = new java.lang.StringBuilder(); + for (java.lang.String attr : reqCtxAttrs) { + if (!org.apache.logging.log4j.ThreadContext.containsKey(attr)) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(attr); + } + } + if (sb.length() > 0) { + throw new org.apache.logging.log4j.audit.exception.ConstraintValidationException((("Event " + msg.getId().getName()) + " is missing required RequestContextMapping values for ") + sb.toString()); + } + } + java.util.Map reqCtxAttributes = catalogManager.getRequestContextAttributes(); + for (java.util.Map.Entry entry : reqCtxAttributes.entrySet()) { + org.apache.logging.log4j.catalog.api.Attribute attribute = entry.getValue(); + java.lang.String attr = entry.getKey(); + if (attribute.isRequired() && (!org.apache.logging.log4j.ThreadContext.containsKey(attr))) { + if (errors.length() > 0) { + errors.append(", "); + } + errors.append(attr); + } + } + if (errors.length() > 0) { + throw new org.apache.logging.log4j.audit.exception.ConstraintValidationException((("Event " + eventName) + " is missing required Thread Context values for ") + errors.toString()); + } + for (java.util.Map.Entry entry : reqCtxAttributes.entrySet()) { + org.apache.logging.log4j.catalog.api.Attribute attribute = reqCtxAttributes.get(entry.getKey()); + if (!org.apache.logging.log4j.ThreadContext.containsKey(entry.getKey())) { + continue; + } + java.util.Set constraintList = attribute.getConstraints(); + if ((constraintList != null) && (constraintList.size() > 0)) { + org.apache.logging.log4j.audit.AbstractEventLogger.validateConstraints(true, constraintList, entry.getKey(), org.apache.logging.log4j.ThreadContext.get(entry.getKey()), errors); + } + } + if (errors.length() > 0) { + throw new org.apache.logging.log4j.audit.exception.ConstraintValidationException((("Event " + eventName) + " has incorrect data in the Thread Context: ") + errors.toString()); + } + msg.putAll(attributes); + try { + logEvent(msg); + } catch (java.lang.Throwable ex) { + if (exceptionHandler == null) { + defaultAuditExceptionHandler.handleException(msg, ex); + } else { + exceptionHandler.handleException(msg, ex); + } + } +} + + private static void validateConstraints(boolean isRequestContext, Collection constraints, String name, + String value, StringBuilder errors) { + for (Constraint constraint : constraints) { + constraintPlugins.validateConstraint(isRequestContext, constraint.getConstraintType().getName(), name, value, + constraint.getValue(), errors); + } + } +} diff --git a/Java/logging-log4j-audit-AbstractEventLogger_113/metadata.json b/Java/logging-log4j-audit-AbstractEventLogger_113/metadata.json new file mode 100644 index 000000000..64fa1df17 --- /dev/null +++ b/Java/logging-log4j-audit-AbstractEventLogger_113/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-AbstractEventLogger_113", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/AbstractEventLogger.java", + "line": 110, + "npe_method": "logEvent", + "deref_field": "getAttributes", + "npe_class": "AbstractEventLogger", + "repo": "logging-log4j-audit", + "bug_id": "AbstractEventLogger_113" + } +} diff --git a/Java/logging-log4j-audit-AbstractEventLogger_113/npe.json b/Java/logging-log4j-audit-AbstractEventLogger_113/npe.json new file mode 100644 index 000000000..87ee485c1 --- /dev/null +++ b/Java/logging-log4j-audit-AbstractEventLogger_113/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/AbstractEventLogger.java", + "line": 110, + "npe_method": "logEvent", + "deref_field": "getAttributes", + "npe_class": "AbstractEventLogger" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-AttributeConverter_48/Dockerfile b/Java/logging-log4j-audit-AttributeConverter_48/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_48/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-AttributeConverter_48/buggy.java b/Java/logging-log4j-audit-AttributeConverter_48/buggy.java new file mode 100644 index 000000000..059c6d6e1 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_48/buggy.java @@ -0,0 +1,85 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.catalog.jpa.converter; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.Constraint; +import org.apache.logging.log4j.catalog.jpa.model.AttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.ConstraintModel; +import org.apache.logging.log4j.catalog.jpa.service.AttributeService; +import org.modelmapper.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class AttributeConverter extends AbstractConverter { + private static final Logger LOGGER = LogManager.getLogger(AttributeConverter.class); + + @Autowired + private AttributeService attributeService; + +public org.apache.logging.log4j.catalog.jpa.model.AttributeModel convert(org.apache.logging.log4j.catalog.api.Attribute attribute) { + org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter.LOGGER.traceEntry(attribute.getName()); + org.apache.logging.log4j.catalog.jpa.model.AttributeModel model; + { + model = attributeService.getAttribute(/* NPEX_NULL_EXP */ + attribute.getId()).orElseGet(org.apache.logging.log4j.catalog.jpa.model.AttributeModel::new); + } + model.setName(attribute.getName()); + model.setAliases(attribute.getAliases()); + model.setDescription(attribute.getDescription()); + model.setDisplayName(attribute.getDisplayName()); + model.setDataType(attribute.getDataType()); + model.setId(attribute.getId()); + model.setCatalogId(attribute.getCatalogId()); + model.setIndexed(attribute.isIndexed()); + model.setRequestContext(attribute.isRequestContext()); + model.setRequired(attribute.isRequired()); + model.setSortable(attribute.isSortable()); + model.setExamples(attribute.getExamples()); + java.util.Set constraintModels = (model.getConstraints() != null) ? model.getConstraints() : new java.util.HashSet<>(); + java.util.Map constraintMap = constraintModels.stream().collect(java.util.stream.Collectors.toMap(org.apache.logging.log4j.catalog.jpa.model.ConstraintModel::getId, java.util.function.Function.identity())); + if (attribute.getConstraints() != null) { + constraintModels.removeIf(( a) -> attribute.getConstraints().stream().noneMatch(( b) -> b.getId().equals(a.getId()))); + for (org.apache.logging.log4j.catalog.api.Constraint constraint : attribute.getConstraints()) { + org.apache.logging.log4j.catalog.jpa.model.ConstraintModel constraintModel; + if (constraint.getId() != null) { + constraintModel = constraintMap.get(constraint.getId()); + constraintModel.setConstraintType(constraint.getConstraintType().getName()); + constraintModel.setValue(constraint.getValue()); + } else { + constraintModel = new org.apache.logging.log4j.catalog.jpa.model.ConstraintModel(); + constraintModel.setConstraintType(constraint.getConstraintType().getName()); + constraintModel.setValue(constraint.getValue()); + constraintModels.add(constraintModel); + } + } + } + model.setConstraints(constraintModels); + return org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter.LOGGER.traceExit(model); +} +} diff --git a/Java/logging-log4j-audit-AttributeConverter_48/metadata.json b/Java/logging-log4j-audit-AttributeConverter_48/metadata.json new file mode 100644 index 000000000..384260485 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_48/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-AttributeConverter_48", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/AttributeConverter.java", + "line": 50, + "npe_method": "convert", + "deref_field": "getId", + "npe_class": "AttributeConverter", + "repo": "logging-log4j-audit", + "bug_id": "AttributeConverter_48" + } +} diff --git a/Java/logging-log4j-audit-AttributeConverter_48/npe.json b/Java/logging-log4j-audit-AttributeConverter_48/npe.json new file mode 100644 index 000000000..1f854c311 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_48/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/AttributeConverter.java", + "line": 50, + "npe_method": "convert", + "deref_field": "getId", + "npe_class": "AttributeConverter" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-AttributeConverter_65/Dockerfile b/Java/logging-log4j-audit-AttributeConverter_65/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_65/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-AttributeConverter_65/buggy.java b/Java/logging-log4j-audit-AttributeConverter_65/buggy.java new file mode 100644 index 000000000..8bd2db514 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_65/buggy.java @@ -0,0 +1,87 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.catalog.jpa.converter; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.Constraint; +import org.apache.logging.log4j.catalog.jpa.model.AttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.ConstraintModel; +import org.apache.logging.log4j.catalog.jpa.service.AttributeService; +import org.modelmapper.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class AttributeConverter extends AbstractConverter { + private static final Logger LOGGER = LogManager.getLogger(AttributeConverter.class); + + @Autowired + private AttributeService attributeService; + +public org.apache.logging.log4j.catalog.jpa.model.AttributeModel convert(org.apache.logging.log4j.catalog.api.Attribute attribute) { + org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter.LOGGER.traceEntry(attribute.getName()); + org.apache.logging.log4j.catalog.jpa.model.AttributeModel model; + if (attribute.getId() != null) { + model = attributeService.getAttribute(attribute.getId()).orElseGet(org.apache.logging.log4j.catalog.jpa.model.AttributeModel::new); + } else { + model = new org.apache.logging.log4j.catalog.jpa.model.AttributeModel(); + } + model.setName(attribute.getName()); + model.setAliases(attribute.getAliases()); + model.setDescription(attribute.getDescription()); + model.setDisplayName(attribute.getDisplayName()); + model.setDataType(attribute.getDataType()); + model.setId(attribute.getId()); + model.setCatalogId(attribute.getCatalogId()); + model.setIndexed(attribute.isIndexed()); + model.setRequestContext(attribute.isRequestContext()); + model.setRequired(attribute.isRequired()); + model.setSortable(attribute.isSortable()); + model.setExamples(attribute.getExamples()); + java.util.Set constraintModels = /* NPEX_NULL_EXP */ + model.getConstraints(); + java.util.Map constraintMap = constraintModels.stream().collect(java.util.stream.Collectors.toMap(org.apache.logging.log4j.catalog.jpa.model.ConstraintModel::getId, java.util.function.Function.identity())); + if (attribute.getConstraints() != null) { + constraintModels.removeIf(( a) -> attribute.getConstraints().stream().noneMatch(( b) -> b.getId().equals(a.getId()))); + for (org.apache.logging.log4j.catalog.api.Constraint constraint : attribute.getConstraints()) { + org.apache.logging.log4j.catalog.jpa.model.ConstraintModel constraintModel; + if (constraint.getId() != null) { + constraintModel = constraintMap.get(constraint.getId()); + constraintModel.setConstraintType(constraint.getConstraintType().getName()); + constraintModel.setValue(constraint.getValue()); + } else { + constraintModel = new org.apache.logging.log4j.catalog.jpa.model.ConstraintModel(); + constraintModel.setConstraintType(constraint.getConstraintType().getName()); + constraintModel.setValue(constraint.getValue()); + constraintModels.add(constraintModel); + } + } + } + model.setConstraints(constraintModels); + return org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter.LOGGER.traceExit(model); +} +} diff --git a/Java/logging-log4j-audit-AttributeConverter_65/metadata.json b/Java/logging-log4j-audit-AttributeConverter_65/metadata.json new file mode 100644 index 000000000..66babfcb8 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_65/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-AttributeConverter_65", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/AttributeConverter.java", + "line": 66, + "npe_method": "convert", + "deref_field": "getConstraints", + "npe_class": "AttributeConverter", + "repo": "logging-log4j-audit", + "bug_id": "AttributeConverter_65" + } +} diff --git a/Java/logging-log4j-audit-AttributeConverter_65/npe.json b/Java/logging-log4j-audit-AttributeConverter_65/npe.json new file mode 100644 index 000000000..e3c45d033 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_65/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/AttributeConverter.java", + "line": 66, + "npe_method": "convert", + "deref_field": "getConstraints", + "npe_class": "AttributeConverter" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-AttributeConverter_69/Dockerfile b/Java/logging-log4j-audit-AttributeConverter_69/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_69/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-AttributeConverter_69/buggy.java b/Java/logging-log4j-audit-AttributeConverter_69/buggy.java new file mode 100644 index 000000000..19e095a8d --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_69/buggy.java @@ -0,0 +1,87 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.catalog.jpa.converter; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.Constraint; +import org.apache.logging.log4j.catalog.jpa.model.AttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.ConstraintModel; +import org.apache.logging.log4j.catalog.jpa.service.AttributeService; +import org.modelmapper.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class AttributeConverter extends AbstractConverter { + private static final Logger LOGGER = LogManager.getLogger(AttributeConverter.class); + + @Autowired + private AttributeService attributeService; + +public org.apache.logging.log4j.catalog.jpa.model.AttributeModel convert(org.apache.logging.log4j.catalog.api.Attribute attribute) { + org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter.LOGGER.traceEntry(attribute.getName()); + org.apache.logging.log4j.catalog.jpa.model.AttributeModel model; + if (attribute.getId() != null) { + model = attributeService.getAttribute(attribute.getId()).orElseGet(org.apache.logging.log4j.catalog.jpa.model.AttributeModel::new); + } else { + model = new org.apache.logging.log4j.catalog.jpa.model.AttributeModel(); + } + model.setName(attribute.getName()); + model.setAliases(attribute.getAliases()); + model.setDescription(attribute.getDescription()); + model.setDisplayName(attribute.getDisplayName()); + model.setDataType(attribute.getDataType()); + model.setId(attribute.getId()); + model.setCatalogId(attribute.getCatalogId()); + model.setIndexed(attribute.isIndexed()); + model.setRequestContext(attribute.isRequestContext()); + model.setRequired(attribute.isRequired()); + model.setSortable(attribute.isSortable()); + model.setExamples(attribute.getExamples()); + java.util.Set constraintModels = (model.getConstraints() != null) ? model.getConstraints() : new java.util.HashSet<>(); + java.util.Map constraintMap = constraintModels.stream().collect(java.util.stream.Collectors.toMap(org.apache.logging.log4j.catalog.jpa.model.ConstraintModel::getId, java.util.function.Function.identity())); + { + constraintModels.removeIf(( a) -> /* NPEX_NULL_EXP */ + attribute.getConstraints().stream().noneMatch(( b) -> b.getId().equals(a.getId()))); + for (org.apache.logging.log4j.catalog.api.Constraint constraint : attribute.getConstraints()) { + org.apache.logging.log4j.catalog.jpa.model.ConstraintModel constraintModel; + if (constraint.getId() != null) { + constraintModel = constraintMap.get(constraint.getId()); + constraintModel.setConstraintType(constraint.getConstraintType().getName()); + constraintModel.setValue(constraint.getValue()); + } else { + constraintModel = new org.apache.logging.log4j.catalog.jpa.model.ConstraintModel(); + constraintModel.setConstraintType(constraint.getConstraintType().getName()); + constraintModel.setValue(constraint.getValue()); + constraintModels.add(constraintModel); + } + } + } + model.setConstraints(constraintModels); + return org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter.LOGGER.traceExit(model); +} +} diff --git a/Java/logging-log4j-audit-AttributeConverter_69/metadata.json b/Java/logging-log4j-audit-AttributeConverter_69/metadata.json new file mode 100644 index 000000000..541168765 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_69/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-AttributeConverter_69", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/AttributeConverter.java", + "line": 69, + "npe_method": "convert", + "deref_field": "getConstraints", + "npe_class": "AttributeConverter", + "repo": "logging-log4j-audit", + "bug_id": "AttributeConverter_69" + } +} diff --git a/Java/logging-log4j-audit-AttributeConverter_69/npe.json b/Java/logging-log4j-audit-AttributeConverter_69/npe.json new file mode 100644 index 000000000..4e7432335 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_69/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/AttributeConverter.java", + "line": 69, + "npe_method": "convert", + "deref_field": "getConstraints", + "npe_class": "AttributeConverter" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-AttributeConverter_73/Dockerfile b/Java/logging-log4j-audit-AttributeConverter_73/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_73/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-AttributeConverter_73/buggy.java b/Java/logging-log4j-audit-AttributeConverter_73/buggy.java new file mode 100644 index 000000000..8ce2a24b3 --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_73/buggy.java @@ -0,0 +1,82 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.catalog.jpa.converter; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.Constraint; +import org.apache.logging.log4j.catalog.jpa.model.AttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.ConstraintModel; +import org.apache.logging.log4j.catalog.jpa.service.AttributeService; +import org.modelmapper.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class AttributeConverter extends AbstractConverter { + private static final Logger LOGGER = LogManager.getLogger(AttributeConverter.class); + + @Autowired + private AttributeService attributeService; + +public org.apache.logging.log4j.catalog.jpa.model.AttributeModel convert(org.apache.logging.log4j.catalog.api.Attribute attribute) { + org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter.LOGGER.traceEntry(attribute.getName()); + org.apache.logging.log4j.catalog.jpa.model.AttributeModel model; + if (attribute.getId() != null) { + model = attributeService.getAttribute(attribute.getId()).orElseGet(org.apache.logging.log4j.catalog.jpa.model.AttributeModel::new); + } else { + model = new org.apache.logging.log4j.catalog.jpa.model.AttributeModel(); + } + model.setName(attribute.getName()); + model.setAliases(attribute.getAliases()); + model.setDescription(attribute.getDescription()); + model.setDisplayName(attribute.getDisplayName()); + model.setDataType(attribute.getDataType()); + model.setId(attribute.getId()); + model.setCatalogId(attribute.getCatalogId()); + model.setIndexed(attribute.isIndexed()); + model.setRequestContext(attribute.isRequestContext()); + model.setRequired(attribute.isRequired()); + model.setSortable(attribute.isSortable()); + model.setExamples(attribute.getExamples()); + java.util.Set constraintModels = (model.getConstraints() != null) ? model.getConstraints() : new java.util.HashSet<>(); + java.util.Map constraintMap = constraintModels.stream().collect(java.util.stream.Collectors.toMap(org.apache.logging.log4j.catalog.jpa.model.ConstraintModel::getId, java.util.function.Function.identity())); + { + constraintModels.removeIf(( a) -> attribute.getConstraints().stream().noneMatch(( b) -> b.getId().equals(a.getId()))); + for (org.apache.logging.log4j.catalog.api.Constraint constraint : attribute.getConstraints()) { + org.apache.logging.log4j.catalog.jpa.model.ConstraintModel constraintModel; + { + constraintModel = constraintMap.get(/* NPEX_NULL_EXP */ + constraint.getId()); + constraintModel.setConstraintType(constraint.getConstraintType().getName()); + constraintModel.setValue(constraint.getValue()); + } + } + } + model.setConstraints(constraintModels); + return org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter.LOGGER.traceExit(model); +} +} diff --git a/Java/logging-log4j-audit-AttributeConverter_73/metadata.json b/Java/logging-log4j-audit-AttributeConverter_73/metadata.json new file mode 100644 index 000000000..9c90610bd --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_73/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-AttributeConverter_73", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/AttributeConverter.java", + "line": 73, + "npe_method": "convert", + "deref_field": "getId", + "npe_class": "AttributeConverter", + "repo": "logging-log4j-audit", + "bug_id": "AttributeConverter_73" + } +} diff --git a/Java/logging-log4j-audit-AttributeConverter_73/npe.json b/Java/logging-log4j-audit-AttributeConverter_73/npe.json new file mode 100644 index 000000000..72aac5d5a --- /dev/null +++ b/Java/logging-log4j-audit-AttributeConverter_73/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/AttributeConverter.java", + "line": 73, + "npe_method": "convert", + "deref_field": "getId", + "npe_class": "AttributeConverter" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-AuditCatalogManager_94/Dockerfile b/Java/logging-log4j-audit-AuditCatalogManager_94/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-AuditCatalogManager_94/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-AuditCatalogManager_94/buggy.java b/Java/logging-log4j-audit-AuditCatalogManager_94/buggy.java new file mode 100644 index 000000000..4f7c379a0 --- /dev/null +++ b/Java/logging-log4j-audit-AuditCatalogManager_94/buggy.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit.service.catalog; + +import javax.annotation.PostConstruct; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.audit.catalog.CatalogManagerImpl; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.CatalogReader; +import org.apache.logging.log4j.catalog.api.Category; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.Product; +import org.apache.logging.log4j.catalog.jpa.model.CatalogModel; +import org.apache.logging.log4j.catalog.jpa.service.CatalogService; +import org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter; +import org.apache.logging.log4j.catalog.jpa.converter.CategoryConverter; +import org.apache.logging.log4j.catalog.jpa.converter.EventConverter; +import org.apache.logging.log4j.catalog.jpa.converter.ProductConverter; +import org.apache.logging.log4j.catalog.jpa.model.AttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.CategoryModel; +import org.apache.logging.log4j.catalog.jpa.model.EventModel; +import org.apache.logging.log4j.catalog.jpa.model.ProductModel; +import org.apache.logging.log4j.catalog.jpa.service.AttributeService; +import org.apache.logging.log4j.catalog.jpa.service.CategoryService; +import org.apache.logging.log4j.catalog.jpa.service.EventService; +import org.apache.logging.log4j.catalog.jpa.service.ProductService; +import org.springframework.beans.factory.annotation.Autowired; + +public class AuditCatalogManager extends CatalogManagerImpl implements AuditManager { + + private static final Logger logger = LogManager.getLogger(); + + @Autowired + private CatalogService catalogService; + + @Autowired + AttributeService attributeService; + + @Autowired + EventService eventService; + + @Autowired + CategoryService categoryService; + + @Autowired + ProductService productService; + + @Autowired + AttributeConverter attributeConverter; + + @Autowired + EventConverter eventConverter; + + @Autowired + CategoryConverter categoryConverter; + + @Autowired + ProductConverter productConverter; + + private final CatalogReader catalogReader; + + + public AuditCatalogManager(CatalogReader catalogReader) { + super(catalogReader); + this.catalogReader = catalogReader; + } + + @PostConstruct +public void initialize() { + org.apache.logging.log4j.catalog.jpa.model.CatalogModel catalogModel = catalogService.getCatalogModel(); + { + if (/* NPEX_NULL_EXP */ + catalogModel.getLastUpdate().toLocalDateTime().isBefore(catalogReader.getLastUpdated())) { + initialize(catalogModel); + } + } +} + + @Override + public EventModel saveEvent(Event event) { + EventModel model = eventConverter.convert(event); + model = eventService.saveEvent(model); + Map> infoMap = getInfoMap(); + addEntry(infoMap, event); + return model; + } + + @Override + public void saveAttribute(Attribute attribute) { + Map attrMap = attributeMap.get(attribute.getCatalogId()); + if (attrMap == null) { + attrMap = new ConcurrentHashMap<>(); + attributeMap.put(attribute.getCatalogId(), attrMap); + } + attrMap.put(attribute.getName(), attribute); + } + + private void initialize(CatalogModel catalogModel) { + logger.debug("Updating static catalog"); + + logger.debug("Loading attributes"); + List attributeModels = new ArrayList<>(); + Map attributeMap = new HashMap<>(); + for (Attribute attribute : catalogData.getAttributes()) { + AttributeModel model = attributeConverter.convert(attribute); + attributeService.saveAttribute(model); + attributeModels.add(model); + attributeMap.put(attribute.getName(), attribute); + } + for (AttributeModel attributeModel : attributeModels) { + if (!attributeMap.containsKey(attributeModel.getName())) { + attributeService.deleteAttribute(attributeModel.getId()); + } + } + Map eventMap = new HashMap<>(); + List eventModels = new ArrayList<>(); + logger.debug("Loading events"); + for (Event event : catalogData.getEvents()) { + logger.debug("Processing Event: {}", event); + EventModel model = eventConverter.convert(event); + eventMap.put(event.getName(), event); + eventModels.add(model); + eventService.saveEvent(model); + } + for (EventModel eventModel : eventModels) { + if (!eventMap.containsKey(eventModel.getName())) { + eventService.deleteEvent(eventModel.getId()); + } + } + List categoryModels = new ArrayList<>(); + Map categoryMap = new HashMap<>(); + logger.debug("Loading categories"); + for (Category category : catalogData.getCategories()) { + CategoryModel model = categoryConverter.convert(category); + categoryModels.add(model); + categoryMap.put(category.getName(), category); + categoryService.saveCategory(model); + } + for (CategoryModel categoryModel : categoryModels) { + if (!categoryMap.containsKey(categoryModel.getName())) { + categoryService.deleteCategory(categoryModel.getId()); + } + } + List productModels = new ArrayList<>(); + Map productMap = new HashMap<>(); + logger.debug("loading products"); + for (Product product : catalogData.getProducts()) { + ProductModel model = productConverter.convert(product); + productModels.add(model); + productMap.put(product.getName(), product); + productService.saveProduct(model); + } + for (ProductModel productModel : productModels) { + if (!productMap.containsKey(productModel.getName())) { + productService.deleteProduct(productModel.getId()); + } + } + + catalogModel.setLastUpdate(Timestamp.from(Instant.now())); + catalogService.saveCatalog(catalogModel); + } +} diff --git a/Java/logging-log4j-audit-AuditCatalogManager_94/metadata.json b/Java/logging-log4j-audit-AuditCatalogManager_94/metadata.json new file mode 100644 index 000000000..ceac2cd65 --- /dev/null +++ b/Java/logging-log4j-audit-AuditCatalogManager_94/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-AuditCatalogManager_94", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/catalog/AuditCatalogManager.java", + "line": 96, + "npe_method": "initialize", + "deref_field": "catalogModel", + "npe_class": "AuditCatalogManager", + "repo": "logging-log4j-audit", + "bug_id": "AuditCatalogManager_94" + } +} diff --git a/Java/logging-log4j-audit-AuditCatalogManager_94/npe.json b/Java/logging-log4j-audit-AuditCatalogManager_94/npe.json new file mode 100644 index 000000000..27154c26c --- /dev/null +++ b/Java/logging-log4j-audit-AuditCatalogManager_94/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/catalog/AuditCatalogManager.java", + "line": 96, + "npe_method": "initialize", + "deref_field": "catalogModel", + "npe_class": "AuditCatalogManager" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_140/Dockerfile b/Java/logging-log4j-audit-CatalogManagerImpl_140/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_140/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_140/buggy.java b/Java/logging-log4j-audit-CatalogManagerImpl_140/buggy.java new file mode 100644 index 000000000..18062f7ef --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_140/buggy.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit.catalog; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.CatalogData; +import org.apache.logging.log4j.catalog.api.CatalogReader; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; + +import static java.util.Collections.emptyList; +import static org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG; + +/** + * + */ +public class CatalogManagerImpl implements CatalogManager { + + private static final Logger logger = LogManager.getLogger(CatalogManagerImpl.class); + + private volatile Map> infoMap; + + private final Map requestContextAttributes = new HashMap<>(); + + protected final Map> attributeMap = new ConcurrentHashMap<>(); + + private static final String REQCTX = "ReqCtx_"; + + protected CatalogData catalogData; + + public CatalogManagerImpl(CatalogReader catalogReader) { + try { + infoMap = initializeData(catalogReader); + } catch (Exception ex) { + throw new AuditException("Unable to initialize catalog data", ex); + } + } + + protected Map> getInfoMap() { + return infoMap; + } + + @Override + public Event getEvent(String eventName, String catalogId) { + CatalogInfo info = getCatalogInfo(eventName, catalogId); + return info != null ? info.event : null; + } + + @Override + public List getRequiredContextAttributes(String eventName, String catalogId) { + Map catalogMap = infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId); + return catalogMap != null ? catalogMap.get(eventName).requiredContextAttributes : null; + } + + @Override + public Map getAttributes(String eventName, String catalogId) { + Event event = getEvent(eventName, catalogId); + if (event == null) { + logger.warn("The event named {} could not be found in catalog {}", eventName, catalogId); + return null; + } + List eventAttributes = event.getAttributes() == null ? emptyList() : event.getAttributes(); + Map attributes = new HashMap<>(eventAttributes.size()); + for (EventAttribute eventAttribute : eventAttributes) { + Attribute attr = getAttribute(eventAttribute.getName(), event.getCatalogId()); + if (attr != null) { + attributes.put(attr.getName(), attr); + } + } + return attributes; + } + + @Override + public List getAttributeNames(String eventName, String catalogId) { + return infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId).get(eventName).attributeNames; + } + + @Override + public Attribute getAttribute(String name) { + Map attrMap = attributeMap.get(DEFAULT_CATALOG); + return attrMap != null ? attrMap.get(name) : null; + } + + public Attribute getAttribute(String name, String catalogId) { + Map attrMap = attributeMap.get(catalogId); + if (attrMap == null || !attrMap.containsKey(name)) { + attrMap = attributeMap.get(DEFAULT_CATALOG); + } + return attrMap != null ? attrMap.get(name) : null; + } + + @Override + public Map getRequestContextAttributes() { + return requestContextAttributes; + } + + private CatalogInfo getCatalogInfo(String eventName, String catalogId) { + Map defaultCatalog = infoMap.get(DEFAULT_CATALOG); + Map catalog = catalogId != null ? infoMap.get(catalogId) : null; + return catalog != null && catalog.containsKey(eventName) ? catalog.get(eventName) : + defaultCatalog.get(eventName); + } + +private java.util.Map> initializeData(org.apache.logging.log4j.catalog.api.CatalogReader catalogReader) throws java.lang.Exception { + com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory(); + factory.enable(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_COMMENTS); + com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(factory); + java.lang.String catalog = catalogReader.readCatalog(); + catalogData = mapper.readValue(catalog, org.apache.logging.log4j.catalog.api.CatalogData.class); + { + for (org.apache.logging.log4j.catalog.api.Attribute attr : /* NPEX_NULL_EXP */ + catalogData.getAttributes()) { + if (attr.isRequestContext()) { + requestContextAttributes.put(attr.getName(), attr); + } + java.util.Map attrMap = attributeMap.computeIfAbsent(attr.getCatalogId(), ( k) -> new java.util.HashMap<>()); + attrMap.put(attr.getName(), attr); + } + } + java.util.Map> map = new java.util.HashMap<>(); + map.put(org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG, new java.util.HashMap<>()); + for (org.apache.logging.log4j.catalog.api.Event event : catalogData.getEvents()) { + addEntry(map, event); + } + return map; +} + + protected void addEntry(Map> map, Event event) { + CatalogInfo info = new CatalogInfo(); + info.event = event; + String catalogId = event.getCatalogId(); + if (catalogId != null && catalogId.length() > 0 && !map.containsKey(catalogId)) { + map.put(catalogId, new HashMap<>()); + } + List required = new ArrayList<>(); + List names = new ArrayList<>(); + info.attributes = new HashMap<>(names.size()); + if (event.getAttributes() != null) { + for (EventAttribute eventAttribute : event.getAttributes()) { + String name = eventAttribute.getName(); + Attribute attribute = getAttribute(name, event.getCatalogId()); + if (attribute != null) { + info.attributes.put(name, attribute); + if (name.indexOf('.') != -1) { + name = name.replaceAll("\\.", ""); + } + if (name.indexOf('/') != -1) { + name = name.replaceAll("/", ""); + } + if (attribute.isRequestContext()) { + if (attribute.isRequired()) { + if (name.startsWith(REQCTX)) { + name = name.substring(REQCTX.length()); + } + required.add(name); + } + } else { + names.add(name); + } + } else { + throw new IllegalStateException("Attribute " + name + " is not defined"); + } + } + } + info.requiredContextAttributes = required; + info.attributeNames = names; + Map catalogMap = catalogId == null ? + map.get(DEFAULT_CATALOG) : map.get(catalogId); + catalogMap.put(NamingUtils.getFieldName(event.getName()), info); + } + + protected class CatalogInfo { + private Event event; + + private List requiredContextAttributes; + + private List attributeNames; + + private Map attributes; + } +} diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_140/metadata.json b/Java/logging-log4j-audit-CatalogManagerImpl_140/metadata.json new file mode 100644 index 000000000..bc2d89cfa --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_140/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-CatalogManagerImpl_140", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java", + "line": 140, + "npe_method": "initializeData", + "deref_field": "getAttributes", + "npe_class": "CatalogManagerImpl", + "repo": "logging-log4j-audit", + "bug_id": "CatalogManagerImpl_140" + } +} diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_140/npe.json b/Java/logging-log4j-audit-CatalogManagerImpl_140/npe.json new file mode 100644 index 000000000..655cefea0 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_140/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java", + "line": 140, + "npe_method": "initializeData", + "deref_field": "getAttributes", + "npe_class": "CatalogManagerImpl" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_168/Dockerfile b/Java/logging-log4j-audit-CatalogManagerImpl_168/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_168/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_168/buggy.java b/Java/logging-log4j-audit-CatalogManagerImpl_168/buggy.java new file mode 100644 index 000000000..550558672 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_168/buggy.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit.catalog; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.CatalogData; +import org.apache.logging.log4j.catalog.api.CatalogReader; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; + +import static java.util.Collections.emptyList; +import static org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG; + +/** + * + */ +public class CatalogManagerImpl implements CatalogManager { + + private static final Logger logger = LogManager.getLogger(CatalogManagerImpl.class); + + private volatile Map> infoMap; + + private final Map requestContextAttributes = new HashMap<>(); + + protected final Map> attributeMap = new ConcurrentHashMap<>(); + + private static final String REQCTX = "ReqCtx_"; + + protected CatalogData catalogData; + + public CatalogManagerImpl(CatalogReader catalogReader) { + try { + infoMap = initializeData(catalogReader); + } catch (Exception ex) { + throw new AuditException("Unable to initialize catalog data", ex); + } + } + + protected Map> getInfoMap() { + return infoMap; + } + + @Override + public Event getEvent(String eventName, String catalogId) { + CatalogInfo info = getCatalogInfo(eventName, catalogId); + return info != null ? info.event : null; + } + + @Override + public List getRequiredContextAttributes(String eventName, String catalogId) { + Map catalogMap = infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId); + return catalogMap != null ? catalogMap.get(eventName).requiredContextAttributes : null; + } + + @Override + public Map getAttributes(String eventName, String catalogId) { + Event event = getEvent(eventName, catalogId); + if (event == null) { + logger.warn("The event named {} could not be found in catalog {}", eventName, catalogId); + return null; + } + List eventAttributes = event.getAttributes() == null ? emptyList() : event.getAttributes(); + Map attributes = new HashMap<>(eventAttributes.size()); + for (EventAttribute eventAttribute : eventAttributes) { + Attribute attr = getAttribute(eventAttribute.getName(), event.getCatalogId()); + if (attr != null) { + attributes.put(attr.getName(), attr); + } + } + return attributes; + } + + @Override + public List getAttributeNames(String eventName, String catalogId) { + return infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId).get(eventName).attributeNames; + } + + @Override + public Attribute getAttribute(String name) { + Map attrMap = attributeMap.get(DEFAULT_CATALOG); + return attrMap != null ? attrMap.get(name) : null; + } + + public Attribute getAttribute(String name, String catalogId) { + Map attrMap = attributeMap.get(catalogId); + if (attrMap == null || !attrMap.containsKey(name)) { + attrMap = attributeMap.get(DEFAULT_CATALOG); + } + return attrMap != null ? attrMap.get(name) : null; + } + + @Override + public Map getRequestContextAttributes() { + return requestContextAttributes; + } + + private CatalogInfo getCatalogInfo(String eventName, String catalogId) { + Map defaultCatalog = infoMap.get(DEFAULT_CATALOG); + Map catalog = catalogId != null ? infoMap.get(catalogId) : null; + return catalog != null && catalog.containsKey(eventName) ? catalog.get(eventName) : + defaultCatalog.get(eventName); + } + + private Map> initializeData(CatalogReader catalogReader) throws Exception { + JsonFactory factory = new JsonFactory(); + factory.enable(JsonParser.Feature.ALLOW_COMMENTS); + ObjectMapper mapper = new ObjectMapper(factory); + + String catalog = catalogReader.readCatalog(); + catalogData = mapper.readValue(catalog, CatalogData.class); + + if (catalogData.getAttributes() != null) { + for (Attribute attr : catalogData.getAttributes()) { + if (attr.isRequestContext()) { + requestContextAttributes.put(attr.getName(), attr); + } + Map attrMap = attributeMap.computeIfAbsent(attr.getCatalogId(), k -> new HashMap<>()); + attrMap.put(attr.getName(), attr); + } + } + + Map> map = new HashMap<>(); + map.put(DEFAULT_CATALOG, new HashMap<>()); + for (Event event : catalogData.getEvents()) { + addEntry(map, event); + } + return map; + } + +protected void addEntry(java.util.Map> map, org.apache.logging.log4j.catalog.api.Event event) { + org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.CatalogInfo info = new org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.CatalogInfo(); + info.event = event; + java.lang.String catalogId = event.getCatalogId(); + if (((catalogId != null) && (catalogId.length() > 0)) && (!map.containsKey(catalogId))) { + map.put(catalogId, new java.util.HashMap<>()); + } + java.util.List required = new java.util.ArrayList<>(); + java.util.List names = new java.util.ArrayList<>(); + info.attributes = new java.util.HashMap<>(names.size()); + { + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : /* NPEX_NULL_EXP */ + event.getAttributes()) { + java.lang.String name = eventAttribute.getName(); + org.apache.logging.log4j.catalog.api.Attribute attribute = getAttribute(name, event.getCatalogId()); + if (attribute != null) { + info.attributes.put(name, attribute); + if (name.indexOf('.') != (-1)) { + name = name.replaceAll("\\.", ""); + } + if (name.indexOf('/') != (-1)) { + name = name.replaceAll("/", ""); + } + if (attribute.isRequestContext()) { + if (attribute.isRequired()) { + if (name.startsWith(org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.REQCTX.length()); + } + required.add(name); + } + } else { + names.add(name); + } + } else { + throw new java.lang.IllegalStateException(("Attribute " + name) + " is not defined"); + } + } + } + info.requiredContextAttributes = required; + info.attributeNames = names; + java.util.Map catalogMap = (catalogId == null) ? map.get(org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG) : map.get(catalogId); + catalogMap.put(org.apache.logging.log4j.audit.util.NamingUtils.getFieldName(event.getName()), info); +} + + protected class CatalogInfo { + private Event event; + + private List requiredContextAttributes; + + private List attributeNames; + + private Map attributes; + } +} diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_168/metadata.json b/Java/logging-log4j-audit-CatalogManagerImpl_168/metadata.json new file mode 100644 index 000000000..162d0c198 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_168/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-CatalogManagerImpl_168", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java", + "line": 170, + "npe_method": "addEntry", + "deref_field": "getAttributes", + "npe_class": "CatalogManagerImpl", + "repo": "logging-log4j-audit", + "bug_id": "CatalogManagerImpl_168" + } +} diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_168/npe.json b/Java/logging-log4j-audit-CatalogManagerImpl_168/npe.json new file mode 100644 index 000000000..36a12ae25 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_168/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java", + "line": 170, + "npe_method": "addEntry", + "deref_field": "getAttributes", + "npe_class": "CatalogManagerImpl" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_172/Dockerfile b/Java/logging-log4j-audit-CatalogManagerImpl_172/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_172/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_172/buggy.java b/Java/logging-log4j-audit-CatalogManagerImpl_172/buggy.java new file mode 100644 index 000000000..db2092440 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_172/buggy.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit.catalog; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.CatalogData; +import org.apache.logging.log4j.catalog.api.CatalogReader; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; + +import static java.util.Collections.emptyList; +import static org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG; + +/** + * + */ +public class CatalogManagerImpl implements CatalogManager { + + private static final Logger logger = LogManager.getLogger(CatalogManagerImpl.class); + + private volatile Map> infoMap; + + private final Map requestContextAttributes = new HashMap<>(); + + protected final Map> attributeMap = new ConcurrentHashMap<>(); + + private static final String REQCTX = "ReqCtx_"; + + protected CatalogData catalogData; + + public CatalogManagerImpl(CatalogReader catalogReader) { + try { + infoMap = initializeData(catalogReader); + } catch (Exception ex) { + throw new AuditException("Unable to initialize catalog data", ex); + } + } + + protected Map> getInfoMap() { + return infoMap; + } + + @Override + public Event getEvent(String eventName, String catalogId) { + CatalogInfo info = getCatalogInfo(eventName, catalogId); + return info != null ? info.event : null; + } + + @Override + public List getRequiredContextAttributes(String eventName, String catalogId) { + Map catalogMap = infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId); + return catalogMap != null ? catalogMap.get(eventName).requiredContextAttributes : null; + } + + @Override + public Map getAttributes(String eventName, String catalogId) { + Event event = getEvent(eventName, catalogId); + if (event == null) { + logger.warn("The event named {} could not be found in catalog {}", eventName, catalogId); + return null; + } + List eventAttributes = event.getAttributes() == null ? emptyList() : event.getAttributes(); + Map attributes = new HashMap<>(eventAttributes.size()); + for (EventAttribute eventAttribute : eventAttributes) { + Attribute attr = getAttribute(eventAttribute.getName(), event.getCatalogId()); + if (attr != null) { + attributes.put(attr.getName(), attr); + } + } + return attributes; + } + + @Override + public List getAttributeNames(String eventName, String catalogId) { + return infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId).get(eventName).attributeNames; + } + + @Override + public Attribute getAttribute(String name) { + Map attrMap = attributeMap.get(DEFAULT_CATALOG); + return attrMap != null ? attrMap.get(name) : null; + } + + public Attribute getAttribute(String name, String catalogId) { + Map attrMap = attributeMap.get(catalogId); + if (attrMap == null || !attrMap.containsKey(name)) { + attrMap = attributeMap.get(DEFAULT_CATALOG); + } + return attrMap != null ? attrMap.get(name) : null; + } + + @Override + public Map getRequestContextAttributes() { + return requestContextAttributes; + } + + private CatalogInfo getCatalogInfo(String eventName, String catalogId) { + Map defaultCatalog = infoMap.get(DEFAULT_CATALOG); + Map catalog = catalogId != null ? infoMap.get(catalogId) : null; + return catalog != null && catalog.containsKey(eventName) ? catalog.get(eventName) : + defaultCatalog.get(eventName); + } + + private Map> initializeData(CatalogReader catalogReader) throws Exception { + JsonFactory factory = new JsonFactory(); + factory.enable(JsonParser.Feature.ALLOW_COMMENTS); + ObjectMapper mapper = new ObjectMapper(factory); + + String catalog = catalogReader.readCatalog(); + catalogData = mapper.readValue(catalog, CatalogData.class); + + if (catalogData.getAttributes() != null) { + for (Attribute attr : catalogData.getAttributes()) { + if (attr.isRequestContext()) { + requestContextAttributes.put(attr.getName(), attr); + } + Map attrMap = attributeMap.computeIfAbsent(attr.getCatalogId(), k -> new HashMap<>()); + attrMap.put(attr.getName(), attr); + } + } + + Map> map = new HashMap<>(); + map.put(DEFAULT_CATALOG, new HashMap<>()); + for (Event event : catalogData.getEvents()) { + addEntry(map, event); + } + return map; + } + +protected void addEntry(java.util.Map> map, org.apache.logging.log4j.catalog.api.Event event) { + org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.CatalogInfo info = new org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.CatalogInfo(); + info.event = event; + java.lang.String catalogId = event.getCatalogId(); + if (((catalogId != null) && (catalogId.length() > 0)) && (!map.containsKey(catalogId))) { + map.put(catalogId, new java.util.HashMap<>()); + } + java.util.List required = new java.util.ArrayList<>(); + java.util.List names = new java.util.ArrayList<>(); + info.attributes = new java.util.HashMap<>(names.size()); + { + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : event.getAttributes()) { + java.lang.String name = eventAttribute.getName(); + org.apache.logging.log4j.catalog.api.Attribute attribute = getAttribute(name, event.getCatalogId()); + { + info.attributes.put(name, /* NPEX_NULL_EXP */ + attribute); + if (name.indexOf('.') != (-1)) { + name = name.replaceAll("\\.", ""); + } + if (name.indexOf('/') != (-1)) { + name = name.replaceAll("/", ""); + } + if (attribute.isRequestContext()) { + if (attribute.isRequired()) { + if (name.startsWith(org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.REQCTX.length()); + } + required.add(name); + } + } else { + names.add(name); + } + } + } + } + info.requiredContextAttributes = required; + info.attributeNames = names; + java.util.Map catalogMap = (catalogId == null) ? map.get(org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG) : map.get(catalogId); + catalogMap.put(org.apache.logging.log4j.audit.util.NamingUtils.getFieldName(event.getName()), info); +} + + protected class CatalogInfo { + private Event event; + + private List requiredContextAttributes; + + private List attributeNames; + + private Map attributes; + } +} diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_172/metadata.json b/Java/logging-log4j-audit-CatalogManagerImpl_172/metadata.json new file mode 100644 index 000000000..3b5edb6fd --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_172/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-CatalogManagerImpl_172", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java", + "line": 174, + "npe_method": "addEntry", + "deref_field": "attribute", + "npe_class": "CatalogManagerImpl", + "repo": "logging-log4j-audit", + "bug_id": "CatalogManagerImpl_172" + } +} diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_172/npe.json b/Java/logging-log4j-audit-CatalogManagerImpl_172/npe.json new file mode 100644 index 000000000..f2f5143d7 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_172/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java", + "line": 174, + "npe_method": "addEntry", + "deref_field": "attribute", + "npe_class": "CatalogManagerImpl" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_90/Dockerfile b/Java/logging-log4j-audit-CatalogManagerImpl_90/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_90/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_90/buggy.java b/Java/logging-log4j-audit-CatalogManagerImpl_90/buggy.java new file mode 100644 index 000000000..b1adc52cb --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_90/buggy.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit.catalog; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.CatalogData; +import org.apache.logging.log4j.catalog.api.CatalogReader; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; + +import static java.util.Collections.emptyList; +import static org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG; + +/** + * + */ +public class CatalogManagerImpl implements CatalogManager { + + private static final Logger logger = LogManager.getLogger(CatalogManagerImpl.class); + + private volatile Map> infoMap; + + private final Map requestContextAttributes = new HashMap<>(); + + protected final Map> attributeMap = new ConcurrentHashMap<>(); + + private static final String REQCTX = "ReqCtx_"; + + protected CatalogData catalogData; + + public CatalogManagerImpl(CatalogReader catalogReader) { + try { + infoMap = initializeData(catalogReader); + } catch (Exception ex) { + throw new AuditException("Unable to initialize catalog data", ex); + } + } + + protected Map> getInfoMap() { + return infoMap; + } + + @Override + public Event getEvent(String eventName, String catalogId) { + CatalogInfo info = getCatalogInfo(eventName, catalogId); + return info != null ? info.event : null; + } + + @Override + public List getRequiredContextAttributes(String eventName, String catalogId) { + Map catalogMap = infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId); + return catalogMap != null ? catalogMap.get(eventName).requiredContextAttributes : null; + } + + @Override +public java.util.Map getAttributes(java.lang.String eventName, java.lang.String catalogId) { + org.apache.logging.log4j.catalog.api.Event event = getEvent(eventName, catalogId); + if (event == null) { + org.apache.logging.log4j.audit.catalog.CatalogManagerImpl.logger.warn("The event named {} could not be found in catalog {}", eventName, catalogId); + return null; + } + java.util.List eventAttributes = /* NPEX_NULL_EXP */ + event.getAttributes(); + java.util.Map attributes = new java.util.HashMap<>(eventAttributes.size()); + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : eventAttributes) { + org.apache.logging.log4j.catalog.api.Attribute attr = getAttribute(eventAttribute.getName(), event.getCatalogId()); + if (attr != null) { + attributes.put(attr.getName(), attr); + } + } + return attributes; +} + + @Override + public List getAttributeNames(String eventName, String catalogId) { + return infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId).get(eventName).attributeNames; + } + + @Override + public Attribute getAttribute(String name) { + Map attrMap = attributeMap.get(DEFAULT_CATALOG); + return attrMap != null ? attrMap.get(name) : null; + } + + public Attribute getAttribute(String name, String catalogId) { + Map attrMap = attributeMap.get(catalogId); + if (attrMap == null || !attrMap.containsKey(name)) { + attrMap = attributeMap.get(DEFAULT_CATALOG); + } + return attrMap != null ? attrMap.get(name) : null; + } + + @Override + public Map getRequestContextAttributes() { + return requestContextAttributes; + } + + private CatalogInfo getCatalogInfo(String eventName, String catalogId) { + Map defaultCatalog = infoMap.get(DEFAULT_CATALOG); + Map catalog = catalogId != null ? infoMap.get(catalogId) : null; + return catalog != null && catalog.containsKey(eventName) ? catalog.get(eventName) : + defaultCatalog.get(eventName); + } + + private Map> initializeData(CatalogReader catalogReader) throws Exception { + JsonFactory factory = new JsonFactory(); + factory.enable(JsonParser.Feature.ALLOW_COMMENTS); + ObjectMapper mapper = new ObjectMapper(factory); + + String catalog = catalogReader.readCatalog(); + catalogData = mapper.readValue(catalog, CatalogData.class); + + if (catalogData.getAttributes() != null) { + for (Attribute attr : catalogData.getAttributes()) { + if (attr.isRequestContext()) { + requestContextAttributes.put(attr.getName(), attr); + } + Map attrMap = attributeMap.computeIfAbsent(attr.getCatalogId(), k -> new HashMap<>()); + attrMap.put(attr.getName(), attr); + } + } + + Map> map = new HashMap<>(); + map.put(DEFAULT_CATALOG, new HashMap<>()); + for (Event event : catalogData.getEvents()) { + addEntry(map, event); + } + return map; + } + + protected void addEntry(Map> map, Event event) { + CatalogInfo info = new CatalogInfo(); + info.event = event; + String catalogId = event.getCatalogId(); + if (catalogId != null && catalogId.length() > 0 && !map.containsKey(catalogId)) { + map.put(catalogId, new HashMap<>()); + } + List required = new ArrayList<>(); + List names = new ArrayList<>(); + info.attributes = new HashMap<>(names.size()); + if (event.getAttributes() != null) { + for (EventAttribute eventAttribute : event.getAttributes()) { + String name = eventAttribute.getName(); + Attribute attribute = getAttribute(name, event.getCatalogId()); + if (attribute != null) { + info.attributes.put(name, attribute); + if (name.indexOf('.') != -1) { + name = name.replaceAll("\\.", ""); + } + if (name.indexOf('/') != -1) { + name = name.replaceAll("/", ""); + } + if (attribute.isRequestContext()) { + if (attribute.isRequired()) { + if (name.startsWith(REQCTX)) { + name = name.substring(REQCTX.length()); + } + required.add(name); + } + } else { + names.add(name); + } + } else { + throw new IllegalStateException("Attribute " + name + " is not defined"); + } + } + } + info.requiredContextAttributes = required; + info.attributeNames = names; + Map catalogMap = catalogId == null ? + map.get(DEFAULT_CATALOG) : map.get(catalogId); + catalogMap.put(NamingUtils.getFieldName(event.getName()), info); + } + + protected class CatalogInfo { + private Event event; + + private List requiredContextAttributes; + + private List attributeNames; + + private Map attributes; + } +} diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_90/metadata.json b/Java/logging-log4j-audit-CatalogManagerImpl_90/metadata.json new file mode 100644 index 000000000..3aaf3470d --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_90/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-CatalogManagerImpl_90", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java", + "line": 91, + "npe_method": "getAttributes", + "deref_field": "getAttributes", + "npe_class": "CatalogManagerImpl", + "repo": "logging-log4j-audit", + "bug_id": "CatalogManagerImpl_90" + } +} diff --git a/Java/logging-log4j-audit-CatalogManagerImpl_90/npe.json b/Java/logging-log4j-audit-CatalogManagerImpl_90/npe.json new file mode 100644 index 000000000..088d5f67e --- /dev/null +++ b/Java/logging-log4j-audit-CatalogManagerImpl_90/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java", + "line": 91, + "npe_method": "getAttributes", + "deref_field": "getAttributes", + "npe_class": "CatalogManagerImpl" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-ConstraintModel_80/Dockerfile b/Java/logging-log4j-audit-ConstraintModel_80/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-ConstraintModel_80/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-ConstraintModel_80/buggy.java b/Java/logging-log4j-audit-ConstraintModel_80/buggy.java new file mode 100644 index 000000000..26cb9d8e5 --- /dev/null +++ b/Java/logging-log4j-audit-ConstraintModel_80/buggy.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.catalog.jpa.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import java.io.Serializable; + +/** + * A Catalog Attribute Constraint. + */ +@Entity +@Table(name = "ATTRIBUTE_CONSTRAINT") +public class ConstraintModel implements Serializable { + + private static final long serialVersionUID = 6836453963830996541L; + + @Id + @GeneratedValue(strategy= GenerationType.IDENTITY) + @Column(name = "ID") + private Long id; + @ManyToOne + @JoinColumn(name = "ATTRIBUTE_ID") + private AttributeModel attribute; + @Column(name = "CONSTRAINT_TYPE") + private String constraintType; + @Column(name = "VALUE") + private String value; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getConstraintType() { + return constraintType; + } + + public void setConstraintType(String constraintType) { + this.constraintType = constraintType; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public AttributeModel getAttribute() { + return attribute; + } + +public void setAttribute(org.apache.logging.log4j.catalog.jpa.model.AttributeModel attribute) { + this.attribute = attribute; + { + /* NPEX_NULL_EXP */ + attribute.getConstraints().add(this); + } +} +} diff --git a/Java/logging-log4j-audit-ConstraintModel_80/metadata.json b/Java/logging-log4j-audit-ConstraintModel_80/metadata.json new file mode 100644 index 000000000..b47300350 --- /dev/null +++ b/Java/logging-log4j-audit-ConstraintModel_80/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-ConstraintModel_80", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/model/ConstraintModel.java", + "line": 82, + "npe_method": "setAttribute", + "deref_field": "getConstraints", + "npe_class": "ConstraintModel", + "repo": "logging-log4j-audit", + "bug_id": "ConstraintModel_80" + } +} diff --git a/Java/logging-log4j-audit-ConstraintModel_80/npe.json b/Java/logging-log4j-audit-ConstraintModel_80/npe.json new file mode 100644 index 000000000..42ac03dd8 --- /dev/null +++ b/Java/logging-log4j-audit-ConstraintModel_80/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/model/ConstraintModel.java", + "line": 82, + "npe_method": "setAttribute", + "deref_field": "getConstraints", + "npe_class": "ConstraintModel" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-EventConverter_55/Dockerfile b/Java/logging-log4j-audit-EventConverter_55/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_55/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-EventConverter_55/buggy.java b/Java/logging-log4j-audit-EventConverter_55/buggy.java new file mode 100644 index 000000000..64386b408 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_55/buggy.java @@ -0,0 +1,100 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.catalog.jpa.converter; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; +import org.apache.logging.log4j.catalog.api.constant.Constants; +import org.apache.logging.log4j.catalog.api.exception.CatalogModificationException; +import org.apache.logging.log4j.catalog.jpa.model.AttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.EventModel; +import org.apache.logging.log4j.catalog.jpa.service.AttributeService; +import org.apache.logging.log4j.catalog.jpa.service.EventService; +import org.modelmapper.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class EventConverter extends AbstractConverter { + private static final Logger LOGGER = LogManager.getLogger(EventConverter.class); + + @Autowired + private EventService eventService; + + @Autowired + private AttributeService attributeService; + +public org.apache.logging.log4j.catalog.jpa.model.EventModel convert(org.apache.logging.log4j.catalog.api.Event event) { + org.apache.logging.log4j.catalog.jpa.converter.EventConverter.LOGGER.traceEntry(event.getName()); + org.apache.logging.log4j.catalog.jpa.model.EventModel model; + { + model = eventService.getEvent(/* NPEX_NULL_EXP */ + event.getId()).orElseGet(org.apache.logging.log4j.catalog.jpa.model.EventModel::new); + } + model.setCatalogId(event.getCatalogId()); + model.setName(event.getName()); + model.setAliases(event.getAliases()); + model.setDescription(event.getDescription()); + model.setDisplayName(event.getDisplayName()); + if (model.getAttributes() == null) { + model.setAttributes(new java.util.HashSet<>()); + } + java.util.Set eventAttributeModels = (model.getAttributes() != null) ? model.getAttributes() : new java.util.HashSet<>(); + java.util.List eventAttributes = (event.getAttributes() != null) ? event.getAttributes() : new java.util.ArrayList<>(); + if (!eventAttributes.isEmpty()) { + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : eventAttributes) { + org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel eventAttributeModel = model.getAttribute(eventAttribute.getName()); + if (eventAttributeModel != null) { + eventAttributeModel.setRequired(eventAttribute.isRequired()); + } else { + java.util.Optional optional = getAttribute(event.getCatalogId(), eventAttribute.getName()); + if (optional.isPresent()) { + eventAttributeModel = new org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel(); + eventAttributeModel.setRequired(eventAttribute.isRequired()); + eventAttributeModel.setEvent(model); + eventAttributeModel.setAttribute(optional.get()); + eventAttributeModels.add(eventAttributeModel); + } else { + throw new org.apache.logging.log4j.catalog.api.exception.CatalogModificationException("No catalog entry for " + eventAttribute.getName()); + } + } + } + } + eventAttributeModels.removeIf(( a) -> eventAttributes.stream().noneMatch(( b) -> b.getName().equals(a.getAttribute().getName()))); + model.setAttributes(eventAttributeModels); + return org.apache.logging.log4j.catalog.jpa.converter.EventConverter.LOGGER.traceExit(model); +} + + private Optional getAttribute(String catalogId, String name) { + Optional optional = attributeService.getAttribute(catalogId, name); + if (!optional.isPresent()) { + optional = attributeService.getAttribute(Constants.DEFAULT_CATALOG, name); + } + return optional; + } +} diff --git a/Java/logging-log4j-audit-EventConverter_55/metadata.json b/Java/logging-log4j-audit-EventConverter_55/metadata.json new file mode 100644 index 000000000..bf87a1099 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_55/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-EventConverter_55", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/EventConverter.java", + "line": 57, + "npe_method": "convert", + "deref_field": "getId", + "npe_class": "EventConverter", + "repo": "logging-log4j-audit", + "bug_id": "EventConverter_55" + } +} diff --git a/Java/logging-log4j-audit-EventConverter_55/npe.json b/Java/logging-log4j-audit-EventConverter_55/npe.json new file mode 100644 index 000000000..6fc9aad14 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_55/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/EventConverter.java", + "line": 57, + "npe_method": "convert", + "deref_field": "getId", + "npe_class": "EventConverter" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-EventConverter_70/Dockerfile b/Java/logging-log4j-audit-EventConverter_70/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_70/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-EventConverter_70/buggy.java b/Java/logging-log4j-audit-EventConverter_70/buggy.java new file mode 100644 index 000000000..7e387180f --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_70/buggy.java @@ -0,0 +1,102 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.catalog.jpa.converter; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; +import org.apache.logging.log4j.catalog.api.constant.Constants; +import org.apache.logging.log4j.catalog.api.exception.CatalogModificationException; +import org.apache.logging.log4j.catalog.jpa.model.AttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.EventModel; +import org.apache.logging.log4j.catalog.jpa.service.AttributeService; +import org.apache.logging.log4j.catalog.jpa.service.EventService; +import org.modelmapper.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class EventConverter extends AbstractConverter { + private static final Logger LOGGER = LogManager.getLogger(EventConverter.class); + + @Autowired + private EventService eventService; + + @Autowired + private AttributeService attributeService; + +public org.apache.logging.log4j.catalog.jpa.model.EventModel convert(org.apache.logging.log4j.catalog.api.Event event) { + org.apache.logging.log4j.catalog.jpa.converter.EventConverter.LOGGER.traceEntry(event.getName()); + org.apache.logging.log4j.catalog.jpa.model.EventModel model; + if (event.getId() != null) { + model = eventService.getEvent(event.getId()).orElseGet(org.apache.logging.log4j.catalog.jpa.model.EventModel::new); + } else { + model = new org.apache.logging.log4j.catalog.jpa.model.EventModel(); + } + model.setCatalogId(event.getCatalogId()); + model.setName(event.getName()); + model.setAliases(event.getAliases()); + model.setDescription(event.getDescription()); + model.setDisplayName(event.getDisplayName()); + if (model.getAttributes() == null) { + model.setAttributes(new java.util.HashSet<>()); + } + java.util.Set eventAttributeModels = (model.getAttributes() != null) ? model.getAttributes() : new java.util.HashSet<>(); + java.util.List eventAttributes = /* NPEX_NULL_EXP */ + event.getAttributes(); + if (!eventAttributes.isEmpty()) { + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : eventAttributes) { + org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel eventAttributeModel = model.getAttribute(eventAttribute.getName()); + if (eventAttributeModel != null) { + eventAttributeModel.setRequired(eventAttribute.isRequired()); + } else { + java.util.Optional optional = getAttribute(event.getCatalogId(), eventAttribute.getName()); + if (optional.isPresent()) { + eventAttributeModel = new org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel(); + eventAttributeModel.setRequired(eventAttribute.isRequired()); + eventAttributeModel.setEvent(model); + eventAttributeModel.setAttribute(optional.get()); + eventAttributeModels.add(eventAttributeModel); + } else { + throw new org.apache.logging.log4j.catalog.api.exception.CatalogModificationException("No catalog entry for " + eventAttribute.getName()); + } + } + } + } + eventAttributeModels.removeIf(( a) -> eventAttributes.stream().noneMatch(( b) -> b.getName().equals(a.getAttribute().getName()))); + model.setAttributes(eventAttributeModels); + return org.apache.logging.log4j.catalog.jpa.converter.EventConverter.LOGGER.traceExit(model); +} + + private Optional getAttribute(String catalogId, String name) { + Optional optional = attributeService.getAttribute(catalogId, name); + if (!optional.isPresent()) { + optional = attributeService.getAttribute(Constants.DEFAULT_CATALOG, name); + } + return optional; + } +} diff --git a/Java/logging-log4j-audit-EventConverter_70/metadata.json b/Java/logging-log4j-audit-EventConverter_70/metadata.json new file mode 100644 index 000000000..2ddea751c --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_70/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-EventConverter_70", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/EventConverter.java", + "line": 70, + "npe_method": "convert", + "deref_field": "getAttributes", + "npe_class": "EventConverter", + "repo": "logging-log4j-audit", + "bug_id": "EventConverter_70" + } +} diff --git a/Java/logging-log4j-audit-EventConverter_70/npe.json b/Java/logging-log4j-audit-EventConverter_70/npe.json new file mode 100644 index 000000000..9c9a58a19 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_70/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/EventConverter.java", + "line": 70, + "npe_method": "convert", + "deref_field": "getAttributes", + "npe_class": "EventConverter" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-EventConverter_74/Dockerfile b/Java/logging-log4j-audit-EventConverter_74/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_74/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-EventConverter_74/buggy.java b/Java/logging-log4j-audit-EventConverter_74/buggy.java new file mode 100644 index 000000000..f7b1a800d --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_74/buggy.java @@ -0,0 +1,91 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.catalog.jpa.converter; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; +import org.apache.logging.log4j.catalog.api.constant.Constants; +import org.apache.logging.log4j.catalog.api.exception.CatalogModificationException; +import org.apache.logging.log4j.catalog.jpa.model.AttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel; +import org.apache.logging.log4j.catalog.jpa.model.EventModel; +import org.apache.logging.log4j.catalog.jpa.service.AttributeService; +import org.apache.logging.log4j.catalog.jpa.service.EventService; +import org.modelmapper.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class EventConverter extends AbstractConverter { + private static final Logger LOGGER = LogManager.getLogger(EventConverter.class); + + @Autowired + private EventService eventService; + + @Autowired + private AttributeService attributeService; + +public org.apache.logging.log4j.catalog.jpa.model.EventModel convert(org.apache.logging.log4j.catalog.api.Event event) { + org.apache.logging.log4j.catalog.jpa.converter.EventConverter.LOGGER.traceEntry(event.getName()); + org.apache.logging.log4j.catalog.jpa.model.EventModel model; + if (event.getId() != null) { + model = eventService.getEvent(event.getId()).orElseGet(org.apache.logging.log4j.catalog.jpa.model.EventModel::new); + } else { + model = new org.apache.logging.log4j.catalog.jpa.model.EventModel(); + } + model.setCatalogId(event.getCatalogId()); + model.setName(event.getName()); + model.setAliases(event.getAliases()); + model.setDescription(event.getDescription()); + model.setDisplayName(event.getDisplayName()); + if (model.getAttributes() == null) { + model.setAttributes(new java.util.HashSet<>()); + } + java.util.Set eventAttributeModels = (model.getAttributes() != null) ? model.getAttributes() : new java.util.HashSet<>(); + java.util.List eventAttributes = (event.getAttributes() != null) ? event.getAttributes() : new java.util.ArrayList<>(); + if (!eventAttributes.isEmpty()) { + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : eventAttributes) { + org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel eventAttributeModel = model.getAttribute(eventAttribute.getName()); + { + /* NPEX_NULL_EXP */ + eventAttributeModel.setRequired(eventAttribute.isRequired()); + } + } + } + eventAttributeModels.removeIf(( a) -> eventAttributes.stream().noneMatch(( b) -> b.getName().equals(a.getAttribute().getName()))); + model.setAttributes(eventAttributeModels); + return org.apache.logging.log4j.catalog.jpa.converter.EventConverter.LOGGER.traceExit(model); +} + + private Optional getAttribute(String catalogId, String name) { + Optional optional = attributeService.getAttribute(catalogId, name); + if (!optional.isPresent()) { + optional = attributeService.getAttribute(Constants.DEFAULT_CATALOG, name); + } + return optional; + } +} diff --git a/Java/logging-log4j-audit-EventConverter_74/metadata.json b/Java/logging-log4j-audit-EventConverter_74/metadata.json new file mode 100644 index 000000000..d99e70fa6 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_74/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-EventConverter_74", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/EventConverter.java", + "line": 75, + "npe_method": "convert", + "deref_field": "eventAttributeModel", + "npe_class": "EventConverter", + "repo": "logging-log4j-audit", + "bug_id": "EventConverter_74" + } +} diff --git a/Java/logging-log4j-audit-EventConverter_74/npe.json b/Java/logging-log4j-audit-EventConverter_74/npe.json new file mode 100644 index 000000000..16837d1e7 --- /dev/null +++ b/Java/logging-log4j-audit-EventConverter_74/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/converter/EventConverter.java", + "line": 75, + "npe_method": "convert", + "deref_field": "eventAttributeModel", + "npe_class": "EventConverter" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-Event_178/Dockerfile b/Java/logging-log4j-audit-Event_178/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-Event_178/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-Event_178/buggy.java b/Java/logging-log4j-audit-Event_178/buggy.java new file mode 100644 index 000000000..bfcd0585d --- /dev/null +++ b/Java/logging-log4j-audit-Event_178/buggy.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.catalog.api; + +import java.io.Serializable; +import java.util.List; +import java.util.Set; + +import com.fasterxml.jackson.annotation.JsonFilter; + +import static org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG; + +/** + * Basic attributes common to all events. + */ +@JsonFilter("catalogEvent") +public class Event implements Serializable { + + private static final long serialVersionUID = 1512172827909901054L; + private Long id; + private String name; + private String displayName; + private String description; + private Set aliases; + private String catalogId; + private List attributes; + + /** + * Set default values. + */ + public Event() { + catalogId = DEFAULT_CATALOG; + } + + /** + * Return the id or the event. + * @return the Event's id. + */ + public Long getId() { + return id; + } + + /** + * Set the event's id. + * @param id the Event's id. + */ + public void setId(Long id) { + this.id = id; + } + + /** + * Return the name of the event. + * @return the name of the event. + */ + public String getName() { + return name; + } + + /** + * Sets the name of the event. + * @param name The name of the event. + * @return this Event. + */ + public Event setName(String name) { + this.name = name; + return this; + } + + /** + * Returns the name to display for this event. + * @return the display name for this event. + */ + public String getDisplayName() { + return displayName; + } + + /** + * Set the display name for this event. + * @param name the name to display for this event. + * @return this Event. + */ + public Event setDisplayName(String name) { + this.displayName = name; + return this; + } + + /** + * Return the description of the event. + * @return the event description. + */ + public String getDescription() { + return description; + } + + /** + * Set the event description. + * @param description The description of the event. + * @return this Event. + */ + public Event setDescription(String description) { + this.description = description; + return this; + } + + /** + * Get the Catalog Id this Event is associated with. + * @return the catalog id or null. + */ + public String getCatalogId() { + return catalogId; + } + + /** + * Set the catalog id this Event is associated with. + * @param catalogId The catalog id or null. + */ + public Event setCatalogId(String catalogId) { + if (catalogId != null) { + this.catalogId = catalogId; + } + return this; + } + + /** + * Returns the Set of alias Strings. + * @return the Set of alias Strings. + */ + public Set getAliases() { + return aliases; + } + + /** + * Sets the Set of alias Strings. + * @param aliases the Set of alias Strings. + * @return this Event. + */ + public Event setAliases(Set aliases) { + this.aliases = aliases; + return this; + } + + /** + * Returns the List of Attribute names. + * @return the List of Attribute names. + */ + public List getAttributes() { + return attributes; + } + + /** + * Sets the List of Atribute names. + * @param attributes The List of Attribute names. + * @return this Event. + */ + public Event setAttributes(List attributes) { + this.attributes = attributes; + return this; + } + +public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder(); + sb.append("{\"name\" : \"").append(name).append("\", \"displayName\" : \"").append(displayName).append("\""); + sb.append(", \"description\" : \"").append(description).append("\", \"attributes\" : ["); + { + boolean first = true; + for (org.apache.logging.log4j.catalog.api.EventAttribute attribute : /* NPEX_NULL_EXP */ + attributes) { + if (!first) { + sb.append(", "); + } else { + first = false; + } + sb.append("{\"name\" : \"").append(attribute.getName()).append("\", \"required\" : ").append(attribute.isRequired()).append("}"); + } + } + sb.append("]}"); + return sb.toString(); +} +} diff --git a/Java/logging-log4j-audit-Event_178/metadata.json b/Java/logging-log4j-audit-Event_178/metadata.json new file mode 100644 index 000000000..83a8a3a32 --- /dev/null +++ b/Java/logging-log4j-audit-Event_178/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-Event_178", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/Event.java", + "line": 181, + "npe_method": "toString", + "deref_field": "attributes", + "npe_class": "Event", + "repo": "logging-log4j-audit", + "bug_id": "Event_178" + } +} diff --git a/Java/logging-log4j-audit-Event_178/npe.json b/Java/logging-log4j-audit-Event_178/npe.json new file mode 100644 index 000000000..979a107d7 --- /dev/null +++ b/Java/logging-log4j-audit-Event_178/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/Event.java", + "line": 181, + "npe_method": "toString", + "deref_field": "attributes", + "npe_class": "Event" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-InterfacesGenerator_169/Dockerfile b/Java/logging-log4j-audit-InterfacesGenerator_169/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_169/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-InterfacesGenerator_169/buggy.java b/Java/logging-log4j-audit-InterfacesGenerator_169/buggy.java new file mode 100644 index 000000000..035e65fd5 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_169/buggy.java @@ -0,0 +1,308 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit.generator; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.CatalogData; +import org.apache.logging.log4j.catalog.api.CatalogReader; +import org.apache.logging.log4j.catalog.api.Constraint; +import org.apache.logging.log4j.catalog.api.ConstraintType; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class InterfacesGenerator { + + private static final Logger LOGGER = LogManager.getLogger(InterfacesGenerator.class); + + private static final String CONSTRAINT_IMPORT = "org.apache.logging.log4j.audit.annotation.Constraint"; + private static final String REQUIRED_IMPORT = "org.apache.logging.log4j.audit.annotation.Required"; + private static final String CONSTRAINTS_ATTR = ", constraints={"; + private static final String CONSTRAINT = "@Constraint(constraintType=\"%s\", constraintValue=\"%s\")"; + private static final String KEY = "key=\""; + private static final String REQUIRED_ATTR = "required=true"; + private static final String REQUIRED = "@Required"; + + private static final String REQUEST_CONTEXT_IMPORT = "org.apache.logging.log4j.audit.annotation.RequestContext"; + private static final String PARENT_IMPORT = "org.apache.logging.log4j.audit.AuditEvent"; + private static final String EVENT_NAME_IMPORT = "org.apache.logging.log4j.audit.annotation.EventName"; + private static final String MAX_LENGTH_IMPORT = "org.apache.logging.log4j.audit.annotation.MaxLength"; + private static final String REQCTX_ANN = "@RequestContext("; + + private static final String PARENT_CLASS = "AuditEvent"; + + private static final String REQCTX = "ReqCtx_"; + + private static final String EVENT_ID = "eventID"; + + private static final String EVENT_TYPE = "eventType"; + + private static final String TIMESTAMP = "timeStamp"; + + private static final String CONTEXT = "context"; + + @Autowired + private CatalogReader catalogReader; + + @Value("${packageName:org.apache.logging.log4j.audit.event}") + private String packageName; + + @Value("${outputDirectory:target/generated-sources/log4j-audit}") + private String outputDirectory; + + @Value("${maxKeyLength:32}") + private int maxKeyLength; + + @Value("${enterpriseId:18060}") + private int enterpriseId; + + @Value("${verbose:false}") + private boolean verbose; + + public CatalogReader getCatalogReader() { + return catalogReader; + } + + public void setCatalogReader(CatalogReader catalogReader) { + this.catalogReader = catalogReader; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getOutputDirectory() { + return outputDirectory; + } + + public void setOutputDirectory(String outputDirectory) { + this.outputDirectory = outputDirectory; + } + + public void setMaxKeyLength(int maxKeyLength) { + this.maxKeyLength = maxKeyLength; + } + + public void setEnterpriseId(int enterpriseId) { + this.enterpriseId = enterpriseId; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + +public void generateSource() throws java.lang.Exception { + boolean errors = false; + org.apache.logging.log4j.catalog.api.CatalogData catalogData = catalogReader.read(); + { + java.util.List events = catalogData.getEvents(); + java.util.Map requestContextAttrs = new java.util.HashMap<>(); + java.util.Map requestContextIsRequired = new java.util.HashMap<>(); + java.util.Map attributes = catalogReader.getAttributes(); + java.util.Map importedTypes = new java.util.HashMap<>(); + boolean anyConstraints = false; + for (org.apache.logging.log4j.catalog.api.Attribute attribute : attributes.values()) { + if (attribute.isRequestContext()) { + java.lang.String name = attribute.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + requestContextAttrs.put(name, attribute); + requestContextIsRequired.put(name, attribute.isRequired()); + } + } + for (org.apache.logging.log4j.catalog.api.Event event : events) { + java.lang.String maxLen = java.lang.Integer.toString(enterpriseId); + int maxNameLength = (maxKeyLength - maxLen.length()) - 1; + if (event.getName().length() > maxNameLength) { + org.apache.logging.log4j.audit.generator.InterfacesGenerator.LOGGER.error("{} exceeds maximum length of {} for an event name", event.getName(), maxNameLength); + errors = true; + continue; + } + org.apache.logging.log4j.audit.generator.ClassGenerator classGenerator = new org.apache.logging.log4j.audit.generator.ClassGenerator(org.apache.logging.log4j.audit.util.NamingUtils.getClassName(event.getName()), outputDirectory); + classGenerator.setClass(false); + classGenerator.setPackageName(packageName); + classGenerator.setParentClassName(org.apache.logging.log4j.audit.generator.InterfacesGenerator.PARENT_CLASS); + classGenerator.setJavadocComment(event.getDescription()); + classGenerator.setVerbose(verbose); + java.util.Set imports = classGenerator.getImports(); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.PARENT_IMPORT); + java.lang.StringBuilder annotations = new java.lang.StringBuilder(); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_NAME_IMPORT); + annotations.append("@EventName(\"").append(event.getName()).append("\")\n"); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.MAX_LENGTH_IMPORT); + annotations.append("@MaxLength(").append(maxKeyLength).append(")"); + java.util.List eventAttributes = event.getAttributes(); + boolean anyRequired = false; + { + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : /* NPEX_NULL_EXP */ + eventAttributes) { + org.apache.logging.log4j.catalog.api.Attribute attribute = attributes.get(eventAttribute.getName()); + if (attribute == null) { + org.apache.logging.log4j.audit.generator.InterfacesGenerator.LOGGER.error("Unable to locate attribute name {}", eventAttribute.getName()); + errors = true; + continue; + } + if (attribute.isRequestContext() && attribute.isRequired()) { + java.lang.String name = eventAttribute.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + requestContextIsRequired.put(name, java.lang.Boolean.TRUE); + continue; + } + java.lang.String name = attribute.getName(); + if ((org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_ID.equals(name) || org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_TYPE.equals(name)) || org.apache.logging.log4j.audit.generator.InterfacesGenerator.TIMESTAMP.equals(name)) { + continue; + } + if (name.indexOf('.') != (-1)) { + name = name.replaceAll("\\.", ""); + } + if (name.indexOf('/') != (-1)) { + name = name.replaceAll("/", ""); + } + if (name.length() > maxKeyLength) { + org.apache.logging.log4j.audit.generator.InterfacesGenerator.LOGGER.error("{} exceeds maximum length of {} for an attribute name", name, maxKeyLength); + errors = true; + continue; + } + java.lang.String type = attribute.getDataType().getTypeName(); + org.apache.logging.log4j.audit.generator.MethodDefinition definition = new org.apache.logging.log4j.audit.generator.MethodDefinition("void", org.apache.logging.log4j.audit.util.NamingUtils.getMutatorName(name)); + if ((!attribute.isRequestContext()) && (attribute.getDataType().getImportClass() != null)) { + if (!importedTypes.containsKey(attribute.getDataType().getTypeName())) { + importedTypes.put(attribute.getDataType().getTypeName(), attribute.getDataType().getImportClass()); + } + } + definition.addParameter(new org.apache.logging.log4j.audit.generator.Parameter(name, type, attribute.getDescription())); + definition.setInterface(true); + definition.setVisability("public"); + definition.setJavadocComments((attribute.getDisplayName() + " : ") + attribute.getDescription()); + java.lang.StringBuilder buffer = new java.lang.StringBuilder(); + java.util.Set constraints = attribute.getConstraints(); + boolean first = true; + if (attribute.isRequired() || eventAttribute.isRequired()) { + anyRequired = true; + buffer.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED); + first = false; + } + if ((constraints != null) && (constraints.size() > 0)) { + anyConstraints = true; + for (org.apache.logging.log4j.catalog.api.Constraint constraint : constraints) { + if (!first) { + buffer.append("\n "); + } + first = false; + appendConstraint(constraint, buffer); + } + } + if (buffer.length() > 0) { + definition.setAnnotation(buffer.toString()); + } + classGenerator.addMethod(definition); + } + } + if (importedTypes.size() > 0) { + imports.addAll(importedTypes.values()); + } + if (anyRequired) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED_IMPORT); + } + boolean firstReqCtx = true; + if (requestContextAttrs.size() > 0) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUEST_CONTEXT_IMPORT); + java.lang.StringBuilder reqCtx = new java.lang.StringBuilder(); + for (java.util.Map.Entry entry : requestContextAttrs.entrySet()) { + if (!firstReqCtx) { + reqCtx.append(")\n"); + } + firstReqCtx = false; + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX_ANN); + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.KEY).append(entry.getKey()).append("\""); + org.apache.logging.log4j.catalog.api.Attribute attrib = entry.getValue(); + java.lang.String name = attrib.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + java.lang.Boolean isRequired = null; + final java.lang.String attrName = name; + if (event.getAttributes() != null) { + java.util.Optional optional = event.getAttributes().stream().filter(( a) -> attrName.equals(a.getName())).findFirst(); + if (optional.isPresent()) { + isRequired = optional.get().isRequired(); + } + } + if (((isRequired != null) && isRequired) || ((isRequired == null) && requestContextIsRequired.get(name))) { + reqCtx.append(", ").append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED_ATTR); + } + java.util.Set constraints = entry.getValue().getConstraints(); + if ((constraints != null) && (constraints.size() > 0)) { + anyConstraints = true; + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.CONSTRAINTS_ATTR); + boolean first = true; + for (org.apache.logging.log4j.catalog.api.Constraint constraint : constraints) { + if (!first) { + reqCtx.append(", "); + } + first = false; + appendConstraint(constraint, reqCtx); + } + reqCtx.append("}"); + } + } + reqCtx.append(")"); + if (annotations.length() > 0) { + annotations.append("\n"); + } + annotations.append(reqCtx.toString()); + } + if (anyConstraints) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.CONSTRAINT_IMPORT); + } + if (annotations.length() > 0) { + classGenerator.setAnnotations(annotations.toString()); + } + classGenerator.generate(); + } + } + if (errors) { + throw new java.lang.IllegalStateException("Errors were encountered during code generation"); + } +} + + void appendConstraint(Constraint constraint, StringBuilder buffer) { + ConstraintType type = constraint.getConstraintType(); + // Add the escapes since they have been removed when converting the original data to a Java Strinng. They need to + // be added back for use in the Constraint declaration. + buffer.append(String.format(CONSTRAINT, type.getName(), constraint.getValue().replace("\\", "\\\\"))); + } +} diff --git a/Java/logging-log4j-audit-InterfacesGenerator_169/metadata.json b/Java/logging-log4j-audit-InterfacesGenerator_169/metadata.json new file mode 100644 index 000000000..72eb0ccdd --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_169/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-InterfacesGenerator_169", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/generator/InterfacesGenerator.java", + "line": 169, + "npe_method": "generateSource", + "deref_field": "eventAttributes", + "npe_class": "InterfacesGenerator", + "repo": "logging-log4j-audit", + "bug_id": "InterfacesGenerator_169" + } +} diff --git a/Java/logging-log4j-audit-InterfacesGenerator_169/npe.json b/Java/logging-log4j-audit-InterfacesGenerator_169/npe.json new file mode 100644 index 000000000..f8ecb21a1 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_169/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/generator/InterfacesGenerator.java", + "line": 169, + "npe_method": "generateSource", + "deref_field": "eventAttributes", + "npe_class": "InterfacesGenerator" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-InterfacesGenerator_172/Dockerfile b/Java/logging-log4j-audit-InterfacesGenerator_172/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_172/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-InterfacesGenerator_172/buggy.java b/Java/logging-log4j-audit-InterfacesGenerator_172/buggy.java new file mode 100644 index 000000000..5bbcc2ad7 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_172/buggy.java @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit.generator; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.CatalogData; +import org.apache.logging.log4j.catalog.api.CatalogReader; +import org.apache.logging.log4j.catalog.api.Constraint; +import org.apache.logging.log4j.catalog.api.ConstraintType; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class InterfacesGenerator { + + private static final Logger LOGGER = LogManager.getLogger(InterfacesGenerator.class); + + private static final String CONSTRAINT_IMPORT = "org.apache.logging.log4j.audit.annotation.Constraint"; + private static final String REQUIRED_IMPORT = "org.apache.logging.log4j.audit.annotation.Required"; + private static final String CONSTRAINTS_ATTR = ", constraints={"; + private static final String CONSTRAINT = "@Constraint(constraintType=\"%s\", constraintValue=\"%s\")"; + private static final String KEY = "key=\""; + private static final String REQUIRED_ATTR = "required=true"; + private static final String REQUIRED = "@Required"; + + private static final String REQUEST_CONTEXT_IMPORT = "org.apache.logging.log4j.audit.annotation.RequestContext"; + private static final String PARENT_IMPORT = "org.apache.logging.log4j.audit.AuditEvent"; + private static final String EVENT_NAME_IMPORT = "org.apache.logging.log4j.audit.annotation.EventName"; + private static final String MAX_LENGTH_IMPORT = "org.apache.logging.log4j.audit.annotation.MaxLength"; + private static final String REQCTX_ANN = "@RequestContext("; + + private static final String PARENT_CLASS = "AuditEvent"; + + private static final String REQCTX = "ReqCtx_"; + + private static final String EVENT_ID = "eventID"; + + private static final String EVENT_TYPE = "eventType"; + + private static final String TIMESTAMP = "timeStamp"; + + private static final String CONTEXT = "context"; + + @Autowired + private CatalogReader catalogReader; + + @Value("${packageName:org.apache.logging.log4j.audit.event}") + private String packageName; + + @Value("${outputDirectory:target/generated-sources/log4j-audit}") + private String outputDirectory; + + @Value("${maxKeyLength:32}") + private int maxKeyLength; + + @Value("${enterpriseId:18060}") + private int enterpriseId; + + @Value("${verbose:false}") + private boolean verbose; + + public CatalogReader getCatalogReader() { + return catalogReader; + } + + public void setCatalogReader(CatalogReader catalogReader) { + this.catalogReader = catalogReader; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getOutputDirectory() { + return outputDirectory; + } + + public void setOutputDirectory(String outputDirectory) { + this.outputDirectory = outputDirectory; + } + + public void setMaxKeyLength(int maxKeyLength) { + this.maxKeyLength = maxKeyLength; + } + + public void setEnterpriseId(int enterpriseId) { + this.enterpriseId = enterpriseId; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + +public void generateSource() throws java.lang.Exception { + boolean errors = false; + org.apache.logging.log4j.catalog.api.CatalogData catalogData = catalogReader.read(); + { + java.util.List events = catalogData.getEvents(); + java.util.Map requestContextAttrs = new java.util.HashMap<>(); + java.util.Map requestContextIsRequired = new java.util.HashMap<>(); + java.util.Map attributes = catalogReader.getAttributes(); + java.util.Map importedTypes = new java.util.HashMap<>(); + boolean anyConstraints = false; + for (org.apache.logging.log4j.catalog.api.Attribute attribute : attributes.values()) { + if (attribute.isRequestContext()) { + java.lang.String name = attribute.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + requestContextAttrs.put(name, attribute); + requestContextIsRequired.put(name, attribute.isRequired()); + } + } + for (org.apache.logging.log4j.catalog.api.Event event : events) { + java.lang.String maxLen = java.lang.Integer.toString(enterpriseId); + int maxNameLength = (maxKeyLength - maxLen.length()) - 1; + if (event.getName().length() > maxNameLength) { + org.apache.logging.log4j.audit.generator.InterfacesGenerator.LOGGER.error("{} exceeds maximum length of {} for an event name", event.getName(), maxNameLength); + errors = true; + continue; + } + org.apache.logging.log4j.audit.generator.ClassGenerator classGenerator = new org.apache.logging.log4j.audit.generator.ClassGenerator(org.apache.logging.log4j.audit.util.NamingUtils.getClassName(event.getName()), outputDirectory); + classGenerator.setClass(false); + classGenerator.setPackageName(packageName); + classGenerator.setParentClassName(org.apache.logging.log4j.audit.generator.InterfacesGenerator.PARENT_CLASS); + classGenerator.setJavadocComment(event.getDescription()); + classGenerator.setVerbose(verbose); + java.util.Set imports = classGenerator.getImports(); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.PARENT_IMPORT); + java.lang.StringBuilder annotations = new java.lang.StringBuilder(); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_NAME_IMPORT); + annotations.append("@EventName(\"").append(event.getName()).append("\")\n"); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.MAX_LENGTH_IMPORT); + annotations.append("@MaxLength(").append(maxKeyLength).append(")"); + java.util.List eventAttributes = event.getAttributes(); + boolean anyRequired = false; + { + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : eventAttributes) { + org.apache.logging.log4j.catalog.api.Attribute attribute = attributes.get(eventAttribute.getName()); + { + if (/* NPEX_NULL_EXP */ + attribute.isRequestContext() && attribute.isRequired()) { + java.lang.String name = eventAttribute.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + requestContextIsRequired.put(name, java.lang.Boolean.TRUE); + continue; + } + java.lang.String name = attribute.getName(); + if ((org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_ID.equals(name) || org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_TYPE.equals(name)) || org.apache.logging.log4j.audit.generator.InterfacesGenerator.TIMESTAMP.equals(name)) { + continue; + } + if (name.indexOf('.') != (-1)) { + name = name.replaceAll("\\.", ""); + } + if (name.indexOf('/') != (-1)) { + name = name.replaceAll("/", ""); + } + if (name.length() > maxKeyLength) { + org.apache.logging.log4j.audit.generator.InterfacesGenerator.LOGGER.error("{} exceeds maximum length of {} for an attribute name", name, maxKeyLength); + errors = true; + continue; + } + java.lang.String type = attribute.getDataType().getTypeName(); + org.apache.logging.log4j.audit.generator.MethodDefinition definition = new org.apache.logging.log4j.audit.generator.MethodDefinition("void", org.apache.logging.log4j.audit.util.NamingUtils.getMutatorName(name)); + if ((!attribute.isRequestContext()) && (attribute.getDataType().getImportClass() != null)) { + if (!importedTypes.containsKey(attribute.getDataType().getTypeName())) { + importedTypes.put(attribute.getDataType().getTypeName(), attribute.getDataType().getImportClass()); + } + } + definition.addParameter(new org.apache.logging.log4j.audit.generator.Parameter(name, type, attribute.getDescription())); + definition.setInterface(true); + definition.setVisability("public"); + definition.setJavadocComments((attribute.getDisplayName() + " : ") + attribute.getDescription()); + java.lang.StringBuilder buffer = new java.lang.StringBuilder(); + java.util.Set constraints = attribute.getConstraints(); + boolean first = true; + if (attribute.isRequired() || eventAttribute.isRequired()) { + anyRequired = true; + buffer.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED); + first = false; + } + if ((constraints != null) && (constraints.size() > 0)) { + anyConstraints = true; + for (org.apache.logging.log4j.catalog.api.Constraint constraint : constraints) { + if (!first) { + buffer.append("\n "); + } + first = false; + appendConstraint(constraint, buffer); + } + } + if (buffer.length() > 0) { + definition.setAnnotation(buffer.toString()); + } + classGenerator.addMethod(definition); + } + } + } + if (importedTypes.size() > 0) { + imports.addAll(importedTypes.values()); + } + if (anyRequired) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED_IMPORT); + } + boolean firstReqCtx = true; + if (requestContextAttrs.size() > 0) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUEST_CONTEXT_IMPORT); + java.lang.StringBuilder reqCtx = new java.lang.StringBuilder(); + for (java.util.Map.Entry entry : requestContextAttrs.entrySet()) { + if (!firstReqCtx) { + reqCtx.append(")\n"); + } + firstReqCtx = false; + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX_ANN); + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.KEY).append(entry.getKey()).append("\""); + org.apache.logging.log4j.catalog.api.Attribute attrib = entry.getValue(); + java.lang.String name = attrib.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + java.lang.Boolean isRequired = null; + final java.lang.String attrName = name; + if (event.getAttributes() != null) { + java.util.Optional optional = event.getAttributes().stream().filter(( a) -> attrName.equals(a.getName())).findFirst(); + if (optional.isPresent()) { + isRequired = optional.get().isRequired(); + } + } + if (((isRequired != null) && isRequired) || ((isRequired == null) && requestContextIsRequired.get(name))) { + reqCtx.append(", ").append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED_ATTR); + } + java.util.Set constraints = entry.getValue().getConstraints(); + if ((constraints != null) && (constraints.size() > 0)) { + anyConstraints = true; + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.CONSTRAINTS_ATTR); + boolean first = true; + for (org.apache.logging.log4j.catalog.api.Constraint constraint : constraints) { + if (!first) { + reqCtx.append(", "); + } + first = false; + appendConstraint(constraint, reqCtx); + } + reqCtx.append("}"); + } + } + reqCtx.append(")"); + if (annotations.length() > 0) { + annotations.append("\n"); + } + annotations.append(reqCtx.toString()); + } + if (anyConstraints) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.CONSTRAINT_IMPORT); + } + if (annotations.length() > 0) { + classGenerator.setAnnotations(annotations.toString()); + } + classGenerator.generate(); + } + } + if (errors) { + throw new java.lang.IllegalStateException("Errors were encountered during code generation"); + } +} + + void appendConstraint(Constraint constraint, StringBuilder buffer) { + ConstraintType type = constraint.getConstraintType(); + // Add the escapes since they have been removed when converting the original data to a Java Strinng. They need to + // be added back for use in the Constraint declaration. + buffer.append(String.format(CONSTRAINT, type.getName(), constraint.getValue().replace("\\", "\\\\"))); + } +} diff --git a/Java/logging-log4j-audit-InterfacesGenerator_172/metadata.json b/Java/logging-log4j-audit-InterfacesGenerator_172/metadata.json new file mode 100644 index 000000000..59905b0d4 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_172/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-InterfacesGenerator_172", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/generator/InterfacesGenerator.java", + "line": 172, + "npe_method": "generateSource", + "deref_field": "attribute", + "npe_class": "InterfacesGenerator", + "repo": "logging-log4j-audit", + "bug_id": "InterfacesGenerator_172" + } +} diff --git a/Java/logging-log4j-audit-InterfacesGenerator_172/npe.json b/Java/logging-log4j-audit-InterfacesGenerator_172/npe.json new file mode 100644 index 000000000..915201051 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_172/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/generator/InterfacesGenerator.java", + "line": 172, + "npe_method": "generateSource", + "deref_field": "attribute", + "npe_class": "InterfacesGenerator" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-InterfacesGenerator_268/Dockerfile b/Java/logging-log4j-audit-InterfacesGenerator_268/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_268/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-InterfacesGenerator_268/buggy.java b/Java/logging-log4j-audit-InterfacesGenerator_268/buggy.java new file mode 100644 index 000000000..2c5b69388 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_268/buggy.java @@ -0,0 +1,308 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit.generator; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.Attribute; +import org.apache.logging.log4j.catalog.api.CatalogData; +import org.apache.logging.log4j.catalog.api.CatalogReader; +import org.apache.logging.log4j.catalog.api.Constraint; +import org.apache.logging.log4j.catalog.api.ConstraintType; +import org.apache.logging.log4j.catalog.api.Event; +import org.apache.logging.log4j.catalog.api.EventAttribute; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class InterfacesGenerator { + + private static final Logger LOGGER = LogManager.getLogger(InterfacesGenerator.class); + + private static final String CONSTRAINT_IMPORT = "org.apache.logging.log4j.audit.annotation.Constraint"; + private static final String REQUIRED_IMPORT = "org.apache.logging.log4j.audit.annotation.Required"; + private static final String CONSTRAINTS_ATTR = ", constraints={"; + private static final String CONSTRAINT = "@Constraint(constraintType=\"%s\", constraintValue=\"%s\")"; + private static final String KEY = "key=\""; + private static final String REQUIRED_ATTR = "required=true"; + private static final String REQUIRED = "@Required"; + + private static final String REQUEST_CONTEXT_IMPORT = "org.apache.logging.log4j.audit.annotation.RequestContext"; + private static final String PARENT_IMPORT = "org.apache.logging.log4j.audit.AuditEvent"; + private static final String EVENT_NAME_IMPORT = "org.apache.logging.log4j.audit.annotation.EventName"; + private static final String MAX_LENGTH_IMPORT = "org.apache.logging.log4j.audit.annotation.MaxLength"; + private static final String REQCTX_ANN = "@RequestContext("; + + private static final String PARENT_CLASS = "AuditEvent"; + + private static final String REQCTX = "ReqCtx_"; + + private static final String EVENT_ID = "eventID"; + + private static final String EVENT_TYPE = "eventType"; + + private static final String TIMESTAMP = "timeStamp"; + + private static final String CONTEXT = "context"; + + @Autowired + private CatalogReader catalogReader; + + @Value("${packageName:org.apache.logging.log4j.audit.event}") + private String packageName; + + @Value("${outputDirectory:target/generated-sources/log4j-audit}") + private String outputDirectory; + + @Value("${maxKeyLength:32}") + private int maxKeyLength; + + @Value("${enterpriseId:18060}") + private int enterpriseId; + + @Value("${verbose:false}") + private boolean verbose; + + public CatalogReader getCatalogReader() { + return catalogReader; + } + + public void setCatalogReader(CatalogReader catalogReader) { + this.catalogReader = catalogReader; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getOutputDirectory() { + return outputDirectory; + } + + public void setOutputDirectory(String outputDirectory) { + this.outputDirectory = outputDirectory; + } + + public void setMaxKeyLength(int maxKeyLength) { + this.maxKeyLength = maxKeyLength; + } + + public void setEnterpriseId(int enterpriseId) { + this.enterpriseId = enterpriseId; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + +public void generateSource() throws java.lang.Exception { + boolean errors = false; + org.apache.logging.log4j.catalog.api.CatalogData catalogData = catalogReader.read(); + { + java.util.List events = catalogData.getEvents(); + java.util.Map requestContextAttrs = new java.util.HashMap<>(); + java.util.Map requestContextIsRequired = new java.util.HashMap<>(); + java.util.Map attributes = catalogReader.getAttributes(); + java.util.Map importedTypes = new java.util.HashMap<>(); + boolean anyConstraints = false; + for (org.apache.logging.log4j.catalog.api.Attribute attribute : attributes.values()) { + if (attribute.isRequestContext()) { + java.lang.String name = attribute.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + requestContextAttrs.put(name, attribute); + requestContextIsRequired.put(name, attribute.isRequired()); + } + } + for (org.apache.logging.log4j.catalog.api.Event event : events) { + java.lang.String maxLen = java.lang.Integer.toString(enterpriseId); + int maxNameLength = (maxKeyLength - maxLen.length()) - 1; + if (event.getName().length() > maxNameLength) { + org.apache.logging.log4j.audit.generator.InterfacesGenerator.LOGGER.error("{} exceeds maximum length of {} for an event name", event.getName(), maxNameLength); + errors = true; + continue; + } + org.apache.logging.log4j.audit.generator.ClassGenerator classGenerator = new org.apache.logging.log4j.audit.generator.ClassGenerator(org.apache.logging.log4j.audit.util.NamingUtils.getClassName(event.getName()), outputDirectory); + classGenerator.setClass(false); + classGenerator.setPackageName(packageName); + classGenerator.setParentClassName(org.apache.logging.log4j.audit.generator.InterfacesGenerator.PARENT_CLASS); + classGenerator.setJavadocComment(event.getDescription()); + classGenerator.setVerbose(verbose); + java.util.Set imports = classGenerator.getImports(); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.PARENT_IMPORT); + java.lang.StringBuilder annotations = new java.lang.StringBuilder(); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_NAME_IMPORT); + annotations.append("@EventName(\"").append(event.getName()).append("\")\n"); + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.MAX_LENGTH_IMPORT); + annotations.append("@MaxLength(").append(maxKeyLength).append(")"); + java.util.List eventAttributes = event.getAttributes(); + boolean anyRequired = false; + if (eventAttributes != null) { + for (org.apache.logging.log4j.catalog.api.EventAttribute eventAttribute : eventAttributes) { + org.apache.logging.log4j.catalog.api.Attribute attribute = attributes.get(eventAttribute.getName()); + if (attribute == null) { + org.apache.logging.log4j.audit.generator.InterfacesGenerator.LOGGER.error("Unable to locate attribute name {}", eventAttribute.getName()); + errors = true; + continue; + } + if (attribute.isRequestContext() && attribute.isRequired()) { + java.lang.String name = eventAttribute.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + requestContextIsRequired.put(name, java.lang.Boolean.TRUE); + continue; + } + java.lang.String name = attribute.getName(); + if ((org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_ID.equals(name) || org.apache.logging.log4j.audit.generator.InterfacesGenerator.EVENT_TYPE.equals(name)) || org.apache.logging.log4j.audit.generator.InterfacesGenerator.TIMESTAMP.equals(name)) { + continue; + } + if (name.indexOf('.') != (-1)) { + name = name.replaceAll("\\.", ""); + } + if (name.indexOf('/') != (-1)) { + name = name.replaceAll("/", ""); + } + if (name.length() > maxKeyLength) { + org.apache.logging.log4j.audit.generator.InterfacesGenerator.LOGGER.error("{} exceeds maximum length of {} for an attribute name", name, maxKeyLength); + errors = true; + continue; + } + java.lang.String type = attribute.getDataType().getTypeName(); + org.apache.logging.log4j.audit.generator.MethodDefinition definition = new org.apache.logging.log4j.audit.generator.MethodDefinition("void", org.apache.logging.log4j.audit.util.NamingUtils.getMutatorName(name)); + if ((!attribute.isRequestContext()) && (attribute.getDataType().getImportClass() != null)) { + if (!importedTypes.containsKey(attribute.getDataType().getTypeName())) { + importedTypes.put(attribute.getDataType().getTypeName(), attribute.getDataType().getImportClass()); + } + } + definition.addParameter(new org.apache.logging.log4j.audit.generator.Parameter(name, type, attribute.getDescription())); + definition.setInterface(true); + definition.setVisability("public"); + definition.setJavadocComments((attribute.getDisplayName() + " : ") + attribute.getDescription()); + java.lang.StringBuilder buffer = new java.lang.StringBuilder(); + java.util.Set constraints = attribute.getConstraints(); + boolean first = true; + if (attribute.isRequired() || eventAttribute.isRequired()) { + anyRequired = true; + buffer.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED); + first = false; + } + if ((constraints != null) && (constraints.size() > 0)) { + anyConstraints = true; + for (org.apache.logging.log4j.catalog.api.Constraint constraint : constraints) { + if (!first) { + buffer.append("\n "); + } + first = false; + appendConstraint(constraint, buffer); + } + } + if (buffer.length() > 0) { + definition.setAnnotation(buffer.toString()); + } + classGenerator.addMethod(definition); + } + } + if (importedTypes.size() > 0) { + imports.addAll(importedTypes.values()); + } + if (anyRequired) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED_IMPORT); + } + boolean firstReqCtx = true; + if (requestContextAttrs.size() > 0) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUEST_CONTEXT_IMPORT); + java.lang.StringBuilder reqCtx = new java.lang.StringBuilder(); + for (java.util.Map.Entry entry : requestContextAttrs.entrySet()) { + if (!firstReqCtx) { + reqCtx.append(")\n"); + } + firstReqCtx = false; + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX_ANN); + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.KEY).append(entry.getKey()).append("\""); + org.apache.logging.log4j.catalog.api.Attribute attrib = entry.getValue(); + java.lang.String name = attrib.getName(); + if (name.startsWith(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX)) { + name = name.substring(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQCTX.length()); + } + java.lang.Boolean isRequired = null; + final java.lang.String attrName = name; + { + java.util.Optional optional = /* NPEX_NULL_EXP */ + event.getAttributes().stream().filter(( a) -> attrName.equals(a.getName())).findFirst(); + if (optional.isPresent()) { + isRequired = optional.get().isRequired(); + } + } + if (((isRequired != null) && isRequired) || ((isRequired == null) && requestContextIsRequired.get(name))) { + reqCtx.append(", ").append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.REQUIRED_ATTR); + } + java.util.Set constraints = entry.getValue().getConstraints(); + if ((constraints != null) && (constraints.size() > 0)) { + anyConstraints = true; + reqCtx.append(org.apache.logging.log4j.audit.generator.InterfacesGenerator.CONSTRAINTS_ATTR); + boolean first = true; + for (org.apache.logging.log4j.catalog.api.Constraint constraint : constraints) { + if (!first) { + reqCtx.append(", "); + } + first = false; + appendConstraint(constraint, reqCtx); + } + reqCtx.append("}"); + } + } + reqCtx.append(")"); + if (annotations.length() > 0) { + annotations.append("\n"); + } + annotations.append(reqCtx.toString()); + } + if (anyConstraints) { + imports.add(org.apache.logging.log4j.audit.generator.InterfacesGenerator.CONSTRAINT_IMPORT); + } + if (annotations.length() > 0) { + classGenerator.setAnnotations(annotations.toString()); + } + classGenerator.generate(); + } + } + if (errors) { + throw new java.lang.IllegalStateException("Errors were encountered during code generation"); + } +} + + void appendConstraint(Constraint constraint, StringBuilder buffer) { + ConstraintType type = constraint.getConstraintType(); + // Add the escapes since they have been removed when converting the original data to a Java Strinng. They need to + // be added back for use in the Constraint declaration. + buffer.append(String.format(CONSTRAINT, type.getName(), constraint.getValue().replace("\\", "\\\\"))); + } +} diff --git a/Java/logging-log4j-audit-InterfacesGenerator_268/metadata.json b/Java/logging-log4j-audit-InterfacesGenerator_268/metadata.json new file mode 100644 index 000000000..57b36445e --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_268/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-InterfacesGenerator_268", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/generator/InterfacesGenerator.java", + "line": 259, + "npe_method": "generateSource", + "deref_field": "getAttributes", + "npe_class": "InterfacesGenerator", + "repo": "logging-log4j-audit", + "bug_id": "InterfacesGenerator_268" + } +} diff --git a/Java/logging-log4j-audit-InterfacesGenerator_268/npe.json b/Java/logging-log4j-audit-InterfacesGenerator_268/npe.json new file mode 100644 index 000000000..aaeaecc15 --- /dev/null +++ b/Java/logging-log4j-audit-InterfacesGenerator_268/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/generator/InterfacesGenerator.java", + "line": 259, + "npe_method": "generateSource", + "deref_field": "getAttributes", + "npe_class": "InterfacesGenerator" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-LogEventFactory_102/Dockerfile b/Java/logging-log4j-audit-LogEventFactory_102/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_102/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-LogEventFactory_102/buggy.java b/Java/logging-log4j-audit-LogEventFactory_102/buggy.java new file mode 100644 index 000000000..97905f14f --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_102/buggy.java @@ -0,0 +1,420 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.audit.annotation.Constraint; +import org.apache.logging.log4j.audit.annotation.Constraints; +import org.apache.logging.log4j.audit.annotation.EventName; +import org.apache.logging.log4j.audit.annotation.MaxLength; +import org.apache.logging.log4j.audit.annotation.RequestContext; +import org.apache.logging.log4j.audit.annotation.RequestContextConstraints; +import org.apache.logging.log4j.audit.annotation.Required; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.exception.ConstraintValidationException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins; +import org.apache.logging.log4j.message.StructuredDataMessage; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.logging.log4j.catalog.api.util.StringUtils.appendNewline; + +/** + * Handles logging generated Events. Every Event extends the AuditProxy, which handles construction of the + * Event and logging of the Event. + */ +public class LogEventFactory { + + private static final Logger logger = LogManager.getLogger(LogEventFactory.class); + + private static final AuditLogger AUDIT_LOGGER = new AuditLogger(); + + private static final int DEFAULT_MAX_LENGTH = 32; + + private static final AuditExceptionHandler DEFAULT_HANDLER = (message, ex) -> { + throw new AuditException("Error logging event " + message.getId().getName(), ex); + }; + + private static final AuditExceptionHandler NOOP_EXCEPTION_HANDLER = (message, ex) -> { + }; + + private static AuditExceptionHandler defaultExceptionHandler = DEFAULT_HANDLER; + + private static final ConcurrentMap, List> classMap = new ConcurrentHashMap<>(); + + private static final ConstraintPlugins constraintPlugins = ConstraintPlugins.getInstance(); + + public static void setDefaultHandler(AuditExceptionHandler exceptionHandler) { + defaultExceptionHandler = (exceptionHandler == null) ? NOOP_EXCEPTION_HANDLER : exceptionHandler; + } + + static void resetDefaultHandler() { + defaultExceptionHandler = DEFAULT_HANDLER; + } + + /** + * Constructs an Event object from its interface. + * @param intrface The Event interface. + * @param The Event type. + * @return Returns an instance of the Event. + */ + @SuppressWarnings("unchecked") + public static T getEvent(Class intrface) { + + Class[] interfaces = new Class[] { intrface }; + + AuditMessage msg = buildAuditMessage(intrface); + AuditEvent audit = (AuditEvent) Proxy.newProxyInstance(intrface.getClassLoader(), interfaces, + new AuditProxy(msg, intrface, defaultExceptionHandler)); + + return (T) audit; + } + +private static java.lang.String getEventName(java.lang.Class intrface) { + org.apache.logging.log4j.audit.annotation.EventName eventName = intrface.getAnnotation(org.apache.logging.log4j.audit.annotation.EventName.class); + return /* NPEX_NULL_EXP */ + eventName.value(); +} + + private static int getMaxLength(Class intrface) { + MaxLength maxLength = intrface.getAnnotation(MaxLength.class); + return maxLength == null ? DEFAULT_MAX_LENGTH : maxLength.value(); + } + + private static AuditMessage buildAuditMessage(Class intrface) { + String eventName = getEventName(intrface); + int msgLength = getMaxLength(intrface); + return new AuditMessage(eventName, msgLength); + } + + /** + * + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited using the default error handler. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + */ + public static void logEvent(Class intrface, Map properties) { + logEvent(intrface, properties, DEFAULT_HANDLER); + } + + /** + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(Class intrface, Map properties, AuditExceptionHandler handler) { + AuditMessage msg = buildAuditMessage(intrface); + + if (properties != null) { + for (Map.Entry entry : properties.entrySet()) { + msg.put(entry.getKey(), entry.getValue()); + } + } + + validateEvent(intrface, msg); + logEvent(msg, handler); + } + + private static void validateEvent(Class intrface, AuditMessage msg) { + StringBuilder errors = new StringBuilder(); + validateContextConstraints(intrface, errors); + + List props = getProperties(intrface); + Map propertyMap = new HashMap<>(); + + for (Property property : props) { + propertyMap.put(property.name, property); + if (property.isRequired && !msg.containsKey(property.name)) { + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append("Required attribute ").append(property.name).append(" is missing from ").append(msg.getId().getName()); + } + if (msg.containsKey(property.name)) { + validateConstraints(false, property.constraints, property.name, msg, errors); + } + } + + msg.forEach((key, value) -> { + if (!propertyMap.containsKey(key)) { + if (errors.length() > 0) { + errors.append("Attribute ").append(key).append(" is not defined for ").append(msg.getId().getName()); + } + } + }); + + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + } + + /** + * Used to Log the actual AuditMessage. + * @param msg The AuditMessage. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(AuditMessage msg, AuditExceptionHandler handler) { + runMessageAction(() -> AUDIT_LOGGER.logEvent(msg), msg, handler); + } + + private static void runMessageAction(Runnable action, AuditMessage msg, AuditExceptionHandler handler) { + try { + action.run(); + } catch (Throwable ex) { + if (handler == null) { + handler = defaultExceptionHandler; + } + handler.handleException(msg, ex); + } + } + + public static List getPropertyNames(String className) { + Class intrface = getClass(className); + List names; + if (intrface != null) { + List props = getProperties(intrface); + names = new ArrayList<>(props.size()); + for (Property prop : props) { + names.add(prop.name); + } + } else { + names = new ArrayList<>(); + } + return names; + } + + private static List getProperties(Class intrface) { + List props = classMap.get(intrface); + if (props != null) { + return props; + } + props = new ArrayList<>(); + Method[] methods = intrface.getMethods(); + boolean isCompletionStatus = false; + for (Method method : methods) { + if (method.getName().startsWith("set") && !method.getName().equals("setAuditExceptionHandler")) { + if (method.getName().equals("setCompletionStatus")) { + isCompletionStatus = true; + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + Annotation[] annotations = method.getDeclaredAnnotations(); + List constraints = new ArrayList<>(); + boolean isRequired = false; + for (Annotation annotation : annotations) { + if (annotation instanceof Constraint) { + constraints.add((Constraint) annotation); + } + if (annotation instanceof Required) { + isRequired = true; + } + } + props.add(new Property(name, isRequired, constraints)); + } + } + if (!isCompletionStatus) { + props.add(new Property("completionStatus", false, new ArrayList<>())); + } + + classMap.putIfAbsent(intrface, props); + return classMap.get(intrface); + } + + private static Class getClass(String className) { + try { + Class intrface = Class.forName(className); + if (AuditEvent.class.isAssignableFrom(intrface)) { + return intrface; + } + logger.error(className + " is not an AuditEvent"); + } catch (ClassNotFoundException cnfe) { + logger.error("Unable to locate class {}", className); + } + return null; + } + + private static class AuditProxy implements InvocationHandler { + + private final AuditMessage msg; + private final Class intrface; + private AuditExceptionHandler auditExceptionHandler; + + AuditProxy(AuditMessage msg, Class intrface, AuditExceptionHandler auditExceptionHandler) { + this.msg = msg; + this.intrface = intrface; + this.auditExceptionHandler = auditExceptionHandler; + } + + public AuditMessage getMessage() { + return msg; + } + + @Override + public Object invoke(Object o, Method method, Object[] objects) { + if (method.getName().equals("toString") && method.getParameterCount() == 0) { + return msg.toString(); + } + + if (method.getName().equals("logEvent")) { + + runMessageAction(() -> validateEvent(intrface, msg), msg, auditExceptionHandler); + + logEvent(msg, auditExceptionHandler); + return null; + } + + if (method.getName().equals("setCompletionStatus")) { + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("Missing completion status"); + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + msg.put(name, objects[0].toString()); + return null; + } + + if (method.getName().equals("setAuditExceptionHandler")) { + if (objects == null || objects[0] == null) { + auditExceptionHandler = NOOP_EXCEPTION_HANDLER; + } else if (objects[0] instanceof AuditExceptionHandler) { + auditExceptionHandler = (AuditExceptionHandler) objects[0]; + } else { + throw new IllegalArgumentException(objects[0] + " is not an " + AuditExceptionHandler.class.getName()); + } + return null; + } + + if (method.getName().startsWith("set")) { + runMessageAction(() -> setProperty(method, objects), msg, auditExceptionHandler); + return null; + } + + return null; + } + + @SuppressWarnings("unchecked") + private void setProperty(Method method, Object[] objects) { + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("No value to be set for " + name); + } + + StringBuilder errors = new StringBuilder(); + Annotation[] annotations = method.getDeclaredAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof Constraints) { + Constraints constraints = (Constraints) annotation; + validateConstraints(false, constraints.value(), name, objects[0].toString(), + errors); + } else if (annotation instanceof Constraint) { + Constraint constraint = (Constraint) annotation; + constraintPlugins.validateConstraint(false, constraint.constraintType(), + name, objects[0].toString(), constraint.constraintValue(), errors); + } + } + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + + String result; + if (objects[0] instanceof List) { + result = StringUtils.join(objects, ", "); + } else if (objects[0] instanceof Map) { + StructuredDataMessage extra = new StructuredDataMessage(name, null, null); + extra.putAll((Map) objects[0]); + msg.addContent(name, extra); + return; + } else { + result = objects[0].toString(); + } + + msg.put(name, result); + } + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + AuditMessage msg, StringBuilder errors) { + String value = isRequestContext ? ThreadContext.get(name) : msg.get(name); + validateConstraints(isRequestContext, constraints, name, value, errors); + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + String value, StringBuilder errors) { + for (Constraint constraint : constraints) { + constraintPlugins.validateConstraint(isRequestContext, constraint.constraintType(), name, value, + constraint.constraintValue(), errors); + } + } + + private static void validateContextConstraints(Class intrface, StringBuilder buffer) { + RequestContextConstraints reqCtxConstraints = intrface.getAnnotation(RequestContextConstraints.class); + if (reqCtxConstraints != null) { + for (RequestContext ctx : reqCtxConstraints.value()) { + validateContextConstraint(ctx, buffer); + } + } else { + RequestContext ctx = intrface.getAnnotation(RequestContext.class); + validateContextConstraint(ctx, buffer); + } + } + + private static void validateContextConstraint(RequestContext constraint, StringBuilder errors) { + if (constraint == null) { + // the request context is not mandatory + return; + } + + String value = ThreadContext.get(constraint.key()); + if (value != null) { + validateConstraints(true, constraint.constraints(), constraint.key(), value, errors); + } else if (constraint.required()) { + appendNewline(errors); + errors.append("ThreadContext does not contain required key ").append(constraint.key()); + } + } + + private static boolean isBlank(String value) { + return value != null && value.length() > 0; + } + + private static class Property { + private final String name; + private final boolean isRequired; + private final Constraint[] constraints; + + public Property(String name, boolean isRequired, List constraints) { + this.name = name; + this.constraints = constraints.toArray(new Constraint[0]); + this.isRequired = isRequired; + } + } + +} diff --git a/Java/logging-log4j-audit-LogEventFactory_102/metadata.json b/Java/logging-log4j-audit-LogEventFactory_102/metadata.json new file mode 100644 index 000000000..7649dc1ae --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_102/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-LogEventFactory_102", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 103, + "npe_method": "getEventName", + "deref_field": "eventName", + "npe_class": "LogEventFactory", + "repo": "logging-log4j-audit", + "bug_id": "LogEventFactory_102" + } +} diff --git a/Java/logging-log4j-audit-LogEventFactory_102/npe.json b/Java/logging-log4j-audit-LogEventFactory_102/npe.json new file mode 100644 index 000000000..a16a4b1e3 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_102/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 103, + "npe_method": "getEventName", + "deref_field": "eventName", + "npe_class": "LogEventFactory" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-LogEventFactory_107/Dockerfile b/Java/logging-log4j-audit-LogEventFactory_107/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_107/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-LogEventFactory_107/buggy.java b/Java/logging-log4j-audit-LogEventFactory_107/buggy.java new file mode 100644 index 000000000..948a9a057 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_107/buggy.java @@ -0,0 +1,420 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.audit.annotation.Constraint; +import org.apache.logging.log4j.audit.annotation.Constraints; +import org.apache.logging.log4j.audit.annotation.EventName; +import org.apache.logging.log4j.audit.annotation.MaxLength; +import org.apache.logging.log4j.audit.annotation.RequestContext; +import org.apache.logging.log4j.audit.annotation.RequestContextConstraints; +import org.apache.logging.log4j.audit.annotation.Required; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.exception.ConstraintValidationException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins; +import org.apache.logging.log4j.message.StructuredDataMessage; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.logging.log4j.catalog.api.util.StringUtils.appendNewline; + +/** + * Handles logging generated Events. Every Event extends the AuditProxy, which handles construction of the + * Event and logging of the Event. + */ +public class LogEventFactory { + + private static final Logger logger = LogManager.getLogger(LogEventFactory.class); + + private static final AuditLogger AUDIT_LOGGER = new AuditLogger(); + + private static final int DEFAULT_MAX_LENGTH = 32; + + private static final AuditExceptionHandler DEFAULT_HANDLER = (message, ex) -> { + throw new AuditException("Error logging event " + message.getId().getName(), ex); + }; + + private static final AuditExceptionHandler NOOP_EXCEPTION_HANDLER = (message, ex) -> { + }; + + private static AuditExceptionHandler defaultExceptionHandler = DEFAULT_HANDLER; + + private static final ConcurrentMap, List> classMap = new ConcurrentHashMap<>(); + + private static final ConstraintPlugins constraintPlugins = ConstraintPlugins.getInstance(); + + public static void setDefaultHandler(AuditExceptionHandler exceptionHandler) { + defaultExceptionHandler = (exceptionHandler == null) ? NOOP_EXCEPTION_HANDLER : exceptionHandler; + } + + static void resetDefaultHandler() { + defaultExceptionHandler = DEFAULT_HANDLER; + } + + /** + * Constructs an Event object from its interface. + * @param intrface The Event interface. + * @param The Event type. + * @return Returns an instance of the Event. + */ + @SuppressWarnings("unchecked") + public static T getEvent(Class intrface) { + + Class[] interfaces = new Class[] { intrface }; + + AuditMessage msg = buildAuditMessage(intrface); + AuditEvent audit = (AuditEvent) Proxy.newProxyInstance(intrface.getClassLoader(), interfaces, + new AuditProxy(msg, intrface, defaultExceptionHandler)); + + return (T) audit; + } + + private static String getEventName(Class intrface) { + EventName eventName = intrface.getAnnotation(EventName.class); + return eventName != null ? eventName.value() : NamingUtils.lowerFirst(intrface.getSimpleName()); + } + +private static int getMaxLength(java.lang.Class intrface) { + org.apache.logging.log4j.audit.annotation.MaxLength maxLength = intrface.getAnnotation(org.apache.logging.log4j.audit.annotation.MaxLength.class); + return /* NPEX_NULL_EXP */ + maxLength.value(); +} + + private static AuditMessage buildAuditMessage(Class intrface) { + String eventName = getEventName(intrface); + int msgLength = getMaxLength(intrface); + return new AuditMessage(eventName, msgLength); + } + + /** + * + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited using the default error handler. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + */ + public static void logEvent(Class intrface, Map properties) { + logEvent(intrface, properties, DEFAULT_HANDLER); + } + + /** + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(Class intrface, Map properties, AuditExceptionHandler handler) { + AuditMessage msg = buildAuditMessage(intrface); + + if (properties != null) { + for (Map.Entry entry : properties.entrySet()) { + msg.put(entry.getKey(), entry.getValue()); + } + } + + validateEvent(intrface, msg); + logEvent(msg, handler); + } + + private static void validateEvent(Class intrface, AuditMessage msg) { + StringBuilder errors = new StringBuilder(); + validateContextConstraints(intrface, errors); + + List props = getProperties(intrface); + Map propertyMap = new HashMap<>(); + + for (Property property : props) { + propertyMap.put(property.name, property); + if (property.isRequired && !msg.containsKey(property.name)) { + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append("Required attribute ").append(property.name).append(" is missing from ").append(msg.getId().getName()); + } + if (msg.containsKey(property.name)) { + validateConstraints(false, property.constraints, property.name, msg, errors); + } + } + + msg.forEach((key, value) -> { + if (!propertyMap.containsKey(key)) { + if (errors.length() > 0) { + errors.append("Attribute ").append(key).append(" is not defined for ").append(msg.getId().getName()); + } + } + }); + + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + } + + /** + * Used to Log the actual AuditMessage. + * @param msg The AuditMessage. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(AuditMessage msg, AuditExceptionHandler handler) { + runMessageAction(() -> AUDIT_LOGGER.logEvent(msg), msg, handler); + } + + private static void runMessageAction(Runnable action, AuditMessage msg, AuditExceptionHandler handler) { + try { + action.run(); + } catch (Throwable ex) { + if (handler == null) { + handler = defaultExceptionHandler; + } + handler.handleException(msg, ex); + } + } + + public static List getPropertyNames(String className) { + Class intrface = getClass(className); + List names; + if (intrface != null) { + List props = getProperties(intrface); + names = new ArrayList<>(props.size()); + for (Property prop : props) { + names.add(prop.name); + } + } else { + names = new ArrayList<>(); + } + return names; + } + + private static List getProperties(Class intrface) { + List props = classMap.get(intrface); + if (props != null) { + return props; + } + props = new ArrayList<>(); + Method[] methods = intrface.getMethods(); + boolean isCompletionStatus = false; + for (Method method : methods) { + if (method.getName().startsWith("set") && !method.getName().equals("setAuditExceptionHandler")) { + if (method.getName().equals("setCompletionStatus")) { + isCompletionStatus = true; + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + Annotation[] annotations = method.getDeclaredAnnotations(); + List constraints = new ArrayList<>(); + boolean isRequired = false; + for (Annotation annotation : annotations) { + if (annotation instanceof Constraint) { + constraints.add((Constraint) annotation); + } + if (annotation instanceof Required) { + isRequired = true; + } + } + props.add(new Property(name, isRequired, constraints)); + } + } + if (!isCompletionStatus) { + props.add(new Property("completionStatus", false, new ArrayList<>())); + } + + classMap.putIfAbsent(intrface, props); + return classMap.get(intrface); + } + + private static Class getClass(String className) { + try { + Class intrface = Class.forName(className); + if (AuditEvent.class.isAssignableFrom(intrface)) { + return intrface; + } + logger.error(className + " is not an AuditEvent"); + } catch (ClassNotFoundException cnfe) { + logger.error("Unable to locate class {}", className); + } + return null; + } + + private static class AuditProxy implements InvocationHandler { + + private final AuditMessage msg; + private final Class intrface; + private AuditExceptionHandler auditExceptionHandler; + + AuditProxy(AuditMessage msg, Class intrface, AuditExceptionHandler auditExceptionHandler) { + this.msg = msg; + this.intrface = intrface; + this.auditExceptionHandler = auditExceptionHandler; + } + + public AuditMessage getMessage() { + return msg; + } + + @Override + public Object invoke(Object o, Method method, Object[] objects) { + if (method.getName().equals("toString") && method.getParameterCount() == 0) { + return msg.toString(); + } + + if (method.getName().equals("logEvent")) { + + runMessageAction(() -> validateEvent(intrface, msg), msg, auditExceptionHandler); + + logEvent(msg, auditExceptionHandler); + return null; + } + + if (method.getName().equals("setCompletionStatus")) { + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("Missing completion status"); + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + msg.put(name, objects[0].toString()); + return null; + } + + if (method.getName().equals("setAuditExceptionHandler")) { + if (objects == null || objects[0] == null) { + auditExceptionHandler = NOOP_EXCEPTION_HANDLER; + } else if (objects[0] instanceof AuditExceptionHandler) { + auditExceptionHandler = (AuditExceptionHandler) objects[0]; + } else { + throw new IllegalArgumentException(objects[0] + " is not an " + AuditExceptionHandler.class.getName()); + } + return null; + } + + if (method.getName().startsWith("set")) { + runMessageAction(() -> setProperty(method, objects), msg, auditExceptionHandler); + return null; + } + + return null; + } + + @SuppressWarnings("unchecked") + private void setProperty(Method method, Object[] objects) { + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("No value to be set for " + name); + } + + StringBuilder errors = new StringBuilder(); + Annotation[] annotations = method.getDeclaredAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof Constraints) { + Constraints constraints = (Constraints) annotation; + validateConstraints(false, constraints.value(), name, objects[0].toString(), + errors); + } else if (annotation instanceof Constraint) { + Constraint constraint = (Constraint) annotation; + constraintPlugins.validateConstraint(false, constraint.constraintType(), + name, objects[0].toString(), constraint.constraintValue(), errors); + } + } + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + + String result; + if (objects[0] instanceof List) { + result = StringUtils.join(objects, ", "); + } else if (objects[0] instanceof Map) { + StructuredDataMessage extra = new StructuredDataMessage(name, null, null); + extra.putAll((Map) objects[0]); + msg.addContent(name, extra); + return; + } else { + result = objects[0].toString(); + } + + msg.put(name, result); + } + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + AuditMessage msg, StringBuilder errors) { + String value = isRequestContext ? ThreadContext.get(name) : msg.get(name); + validateConstraints(isRequestContext, constraints, name, value, errors); + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + String value, StringBuilder errors) { + for (Constraint constraint : constraints) { + constraintPlugins.validateConstraint(isRequestContext, constraint.constraintType(), name, value, + constraint.constraintValue(), errors); + } + } + + private static void validateContextConstraints(Class intrface, StringBuilder buffer) { + RequestContextConstraints reqCtxConstraints = intrface.getAnnotation(RequestContextConstraints.class); + if (reqCtxConstraints != null) { + for (RequestContext ctx : reqCtxConstraints.value()) { + validateContextConstraint(ctx, buffer); + } + } else { + RequestContext ctx = intrface.getAnnotation(RequestContext.class); + validateContextConstraint(ctx, buffer); + } + } + + private static void validateContextConstraint(RequestContext constraint, StringBuilder errors) { + if (constraint == null) { + // the request context is not mandatory + return; + } + + String value = ThreadContext.get(constraint.key()); + if (value != null) { + validateConstraints(true, constraint.constraints(), constraint.key(), value, errors); + } else if (constraint.required()) { + appendNewline(errors); + errors.append("ThreadContext does not contain required key ").append(constraint.key()); + } + } + + private static boolean isBlank(String value) { + return value != null && value.length() > 0; + } + + private static class Property { + private final String name; + private final boolean isRequired; + private final Constraint[] constraints; + + public Property(String name, boolean isRequired, List constraints) { + this.name = name; + this.constraints = constraints.toArray(new Constraint[0]); + this.isRequired = isRequired; + } + } + +} diff --git a/Java/logging-log4j-audit-LogEventFactory_107/metadata.json b/Java/logging-log4j-audit-LogEventFactory_107/metadata.json new file mode 100644 index 000000000..aa92312f1 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_107/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-LogEventFactory_107", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 108, + "npe_method": "getMaxLength", + "deref_field": "maxLength", + "npe_class": "LogEventFactory", + "repo": "logging-log4j-audit", + "bug_id": "LogEventFactory_107" + } +} diff --git a/Java/logging-log4j-audit-LogEventFactory_107/npe.json b/Java/logging-log4j-audit-LogEventFactory_107/npe.json new file mode 100644 index 000000000..b18beb7d5 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_107/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 108, + "npe_method": "getMaxLength", + "deref_field": "maxLength", + "npe_class": "LogEventFactory" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-LogEventFactory_137/Dockerfile b/Java/logging-log4j-audit-LogEventFactory_137/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_137/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-LogEventFactory_137/buggy.java b/Java/logging-log4j-audit-LogEventFactory_137/buggy.java new file mode 100644 index 000000000..083ee86f7 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_137/buggy.java @@ -0,0 +1,429 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.audit.annotation.Constraint; +import org.apache.logging.log4j.audit.annotation.Constraints; +import org.apache.logging.log4j.audit.annotation.EventName; +import org.apache.logging.log4j.audit.annotation.MaxLength; +import org.apache.logging.log4j.audit.annotation.RequestContext; +import org.apache.logging.log4j.audit.annotation.RequestContextConstraints; +import org.apache.logging.log4j.audit.annotation.Required; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.exception.ConstraintValidationException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins; +import org.apache.logging.log4j.message.StructuredDataMessage; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.logging.log4j.catalog.api.util.StringUtils.appendNewline; + +/** + * Handles logging generated Events. Every Event extends the AuditProxy, which handles construction of the + * Event and logging of the Event. + */ +public class LogEventFactory { + + private static final Logger logger = LogManager.getLogger(LogEventFactory.class); + + private static final AuditLogger AUDIT_LOGGER = new AuditLogger(); + + private static final int DEFAULT_MAX_LENGTH = 32; + + private static final AuditExceptionHandler DEFAULT_HANDLER = (message, ex) -> { + throw new AuditException("Error logging event " + message.getId().getName(), ex); + }; + + private static final AuditExceptionHandler NOOP_EXCEPTION_HANDLER = (message, ex) -> { + }; + + private static AuditExceptionHandler defaultExceptionHandler = DEFAULT_HANDLER; + + private static final ConcurrentMap, List> classMap = new ConcurrentHashMap<>(); + + private static final ConstraintPlugins constraintPlugins = ConstraintPlugins.getInstance(); + + public static void setDefaultHandler(AuditExceptionHandler exceptionHandler) { + defaultExceptionHandler = (exceptionHandler == null) ? NOOP_EXCEPTION_HANDLER : exceptionHandler; + } + + static void resetDefaultHandler() { + defaultExceptionHandler = DEFAULT_HANDLER; + } + + /** + * Constructs an Event object from its interface. + * @param intrface The Event interface. + * @param The Event type. + * @return Returns an instance of the Event. + */ + @SuppressWarnings("unchecked") + public static T getEvent(Class intrface) { + + Class[] interfaces = new Class[] { intrface }; + + AuditMessage msg = buildAuditMessage(intrface); + AuditEvent audit = (AuditEvent) Proxy.newProxyInstance(intrface.getClassLoader(), interfaces, + new AuditProxy(msg, intrface, defaultExceptionHandler)); + + return (T) audit; + } + + private static String getEventName(Class intrface) { + EventName eventName = intrface.getAnnotation(EventName.class); + return eventName != null ? eventName.value() : NamingUtils.lowerFirst(intrface.getSimpleName()); + } + + private static int getMaxLength(Class intrface) { + MaxLength maxLength = intrface.getAnnotation(MaxLength.class); + return maxLength == null ? DEFAULT_MAX_LENGTH : maxLength.value(); + } + + private static AuditMessage buildAuditMessage(Class intrface) { + String eventName = getEventName(intrface); + int msgLength = getMaxLength(intrface); + return new AuditMessage(eventName, msgLength); + } + + /** + * + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited using the default error handler. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + */ + public static void logEvent(Class intrface, Map properties) { + logEvent(intrface, properties, DEFAULT_HANDLER); + } + + /** + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + * @param handler Class that gets control when an exception occurs logging the event. + */ +/** + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited. + * + * @param intrface + * The Event interface. + * @param properties + * The properties to be included in the event. + * @param handler + * Class that gets control when an exception occurs logging the event. + */ +public static void logEvent(java.lang.Class intrface, java.util.Map properties, org.apache.logging.log4j.audit.AuditExceptionHandler handler) { + org.apache.logging.log4j.audit.AuditMessage msg = org.apache.logging.log4j.audit.LogEventFactory.buildAuditMessage(intrface); + { + for (java.util.Map.Entry entry : /* NPEX_NULL_EXP */ + properties.entrySet()) { + msg.put(entry.getKey(), entry.getValue()); + } + } + org.apache.logging.log4j.audit.LogEventFactory.validateEvent(intrface, msg); + org.apache.logging.log4j.audit.LogEventFactory.logEvent(msg, handler); +} + + private static void validateEvent(Class intrface, AuditMessage msg) { + StringBuilder errors = new StringBuilder(); + validateContextConstraints(intrface, errors); + + List props = getProperties(intrface); + Map propertyMap = new HashMap<>(); + + for (Property property : props) { + propertyMap.put(property.name, property); + if (property.isRequired && !msg.containsKey(property.name)) { + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append("Required attribute ").append(property.name).append(" is missing from ").append(msg.getId().getName()); + } + if (msg.containsKey(property.name)) { + validateConstraints(false, property.constraints, property.name, msg, errors); + } + } + + msg.forEach((key, value) -> { + if (!propertyMap.containsKey(key)) { + if (errors.length() > 0) { + errors.append("Attribute ").append(key).append(" is not defined for ").append(msg.getId().getName()); + } + } + }); + + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + } + + /** + * Used to Log the actual AuditMessage. + * @param msg The AuditMessage. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(AuditMessage msg, AuditExceptionHandler handler) { + runMessageAction(() -> AUDIT_LOGGER.logEvent(msg), msg, handler); + } + + private static void runMessageAction(Runnable action, AuditMessage msg, AuditExceptionHandler handler) { + try { + action.run(); + } catch (Throwable ex) { + if (handler == null) { + handler = defaultExceptionHandler; + } + handler.handleException(msg, ex); + } + } + + public static List getPropertyNames(String className) { + Class intrface = getClass(className); + List names; + if (intrface != null) { + List props = getProperties(intrface); + names = new ArrayList<>(props.size()); + for (Property prop : props) { + names.add(prop.name); + } + } else { + names = new ArrayList<>(); + } + return names; + } + + private static List getProperties(Class intrface) { + List props = classMap.get(intrface); + if (props != null) { + return props; + } + props = new ArrayList<>(); + Method[] methods = intrface.getMethods(); + boolean isCompletionStatus = false; + for (Method method : methods) { + if (method.getName().startsWith("set") && !method.getName().equals("setAuditExceptionHandler")) { + if (method.getName().equals("setCompletionStatus")) { + isCompletionStatus = true; + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + Annotation[] annotations = method.getDeclaredAnnotations(); + List constraints = new ArrayList<>(); + boolean isRequired = false; + for (Annotation annotation : annotations) { + if (annotation instanceof Constraint) { + constraints.add((Constraint) annotation); + } + if (annotation instanceof Required) { + isRequired = true; + } + } + props.add(new Property(name, isRequired, constraints)); + } + } + if (!isCompletionStatus) { + props.add(new Property("completionStatus", false, new ArrayList<>())); + } + + classMap.putIfAbsent(intrface, props); + return classMap.get(intrface); + } + + private static Class getClass(String className) { + try { + Class intrface = Class.forName(className); + if (AuditEvent.class.isAssignableFrom(intrface)) { + return intrface; + } + logger.error(className + " is not an AuditEvent"); + } catch (ClassNotFoundException cnfe) { + logger.error("Unable to locate class {}", className); + } + return null; + } + + private static class AuditProxy implements InvocationHandler { + + private final AuditMessage msg; + private final Class intrface; + private AuditExceptionHandler auditExceptionHandler; + + AuditProxy(AuditMessage msg, Class intrface, AuditExceptionHandler auditExceptionHandler) { + this.msg = msg; + this.intrface = intrface; + this.auditExceptionHandler = auditExceptionHandler; + } + + public AuditMessage getMessage() { + return msg; + } + + @Override + public Object invoke(Object o, Method method, Object[] objects) { + if (method.getName().equals("toString") && method.getParameterCount() == 0) { + return msg.toString(); + } + + if (method.getName().equals("logEvent")) { + + runMessageAction(() -> validateEvent(intrface, msg), msg, auditExceptionHandler); + + logEvent(msg, auditExceptionHandler); + return null; + } + + if (method.getName().equals("setCompletionStatus")) { + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("Missing completion status"); + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + msg.put(name, objects[0].toString()); + return null; + } + + if (method.getName().equals("setAuditExceptionHandler")) { + if (objects == null || objects[0] == null) { + auditExceptionHandler = NOOP_EXCEPTION_HANDLER; + } else if (objects[0] instanceof AuditExceptionHandler) { + auditExceptionHandler = (AuditExceptionHandler) objects[0]; + } else { + throw new IllegalArgumentException(objects[0] + " is not an " + AuditExceptionHandler.class.getName()); + } + return null; + } + + if (method.getName().startsWith("set")) { + runMessageAction(() -> setProperty(method, objects), msg, auditExceptionHandler); + return null; + } + + return null; + } + + @SuppressWarnings("unchecked") + private void setProperty(Method method, Object[] objects) { + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("No value to be set for " + name); + } + + StringBuilder errors = new StringBuilder(); + Annotation[] annotations = method.getDeclaredAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof Constraints) { + Constraints constraints = (Constraints) annotation; + validateConstraints(false, constraints.value(), name, objects[0].toString(), + errors); + } else if (annotation instanceof Constraint) { + Constraint constraint = (Constraint) annotation; + constraintPlugins.validateConstraint(false, constraint.constraintType(), + name, objects[0].toString(), constraint.constraintValue(), errors); + } + } + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + + String result; + if (objects[0] instanceof List) { + result = StringUtils.join(objects, ", "); + } else if (objects[0] instanceof Map) { + StructuredDataMessage extra = new StructuredDataMessage(name, null, null); + extra.putAll((Map) objects[0]); + msg.addContent(name, extra); + return; + } else { + result = objects[0].toString(); + } + + msg.put(name, result); + } + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + AuditMessage msg, StringBuilder errors) { + String value = isRequestContext ? ThreadContext.get(name) : msg.get(name); + validateConstraints(isRequestContext, constraints, name, value, errors); + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + String value, StringBuilder errors) { + for (Constraint constraint : constraints) { + constraintPlugins.validateConstraint(isRequestContext, constraint.constraintType(), name, value, + constraint.constraintValue(), errors); + } + } + + private static void validateContextConstraints(Class intrface, StringBuilder buffer) { + RequestContextConstraints reqCtxConstraints = intrface.getAnnotation(RequestContextConstraints.class); + if (reqCtxConstraints != null) { + for (RequestContext ctx : reqCtxConstraints.value()) { + validateContextConstraint(ctx, buffer); + } + } else { + RequestContext ctx = intrface.getAnnotation(RequestContext.class); + validateContextConstraint(ctx, buffer); + } + } + + private static void validateContextConstraint(RequestContext constraint, StringBuilder errors) { + if (constraint == null) { + // the request context is not mandatory + return; + } + + String value = ThreadContext.get(constraint.key()); + if (value != null) { + validateConstraints(true, constraint.constraints(), constraint.key(), value, errors); + } else if (constraint.required()) { + appendNewline(errors); + errors.append("ThreadContext does not contain required key ").append(constraint.key()); + } + } + + private static boolean isBlank(String value) { + return value != null && value.length() > 0; + } + + private static class Property { + private final String name; + private final boolean isRequired; + private final Constraint[] constraints; + + public Property(String name, boolean isRequired, List constraints) { + this.name = name; + this.constraints = constraints.toArray(new Constraint[0]); + this.isRequired = isRequired; + } + } + +} diff --git a/Java/logging-log4j-audit-LogEventFactory_137/metadata.json b/Java/logging-log4j-audit-LogEventFactory_137/metadata.json new file mode 100644 index 000000000..48d47f2bc --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_137/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-LogEventFactory_137", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 149, + "npe_method": "logEvent", + "deref_field": "properties", + "npe_class": "LogEventFactory", + "repo": "logging-log4j-audit", + "bug_id": "LogEventFactory_137" + } +} diff --git a/Java/logging-log4j-audit-LogEventFactory_137/npe.json b/Java/logging-log4j-audit-LogEventFactory_137/npe.json new file mode 100644 index 000000000..87c24a8db --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_137/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 149, + "npe_method": "logEvent", + "deref_field": "properties", + "npe_class": "LogEventFactory" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-LogEventFactory_378/Dockerfile b/Java/logging-log4j-audit-LogEventFactory_378/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_378/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-LogEventFactory_378/buggy.java b/Java/logging-log4j-audit-LogEventFactory_378/buggy.java new file mode 100644 index 000000000..2b18f84bf --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_378/buggy.java @@ -0,0 +1,417 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.audit.annotation.Constraint; +import org.apache.logging.log4j.audit.annotation.Constraints; +import org.apache.logging.log4j.audit.annotation.EventName; +import org.apache.logging.log4j.audit.annotation.MaxLength; +import org.apache.logging.log4j.audit.annotation.RequestContext; +import org.apache.logging.log4j.audit.annotation.RequestContextConstraints; +import org.apache.logging.log4j.audit.annotation.Required; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.exception.ConstraintValidationException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins; +import org.apache.logging.log4j.message.StructuredDataMessage; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.logging.log4j.catalog.api.util.StringUtils.appendNewline; + +/** + * Handles logging generated Events. Every Event extends the AuditProxy, which handles construction of the + * Event and logging of the Event. + */ +public class LogEventFactory { + + private static final Logger logger = LogManager.getLogger(LogEventFactory.class); + + private static final AuditLogger AUDIT_LOGGER = new AuditLogger(); + + private static final int DEFAULT_MAX_LENGTH = 32; + + private static final AuditExceptionHandler DEFAULT_HANDLER = (message, ex) -> { + throw new AuditException("Error logging event " + message.getId().getName(), ex); + }; + + private static final AuditExceptionHandler NOOP_EXCEPTION_HANDLER = (message, ex) -> { + }; + + private static AuditExceptionHandler defaultExceptionHandler = DEFAULT_HANDLER; + + private static final ConcurrentMap, List> classMap = new ConcurrentHashMap<>(); + + private static final ConstraintPlugins constraintPlugins = ConstraintPlugins.getInstance(); + + public static void setDefaultHandler(AuditExceptionHandler exceptionHandler) { + defaultExceptionHandler = (exceptionHandler == null) ? NOOP_EXCEPTION_HANDLER : exceptionHandler; + } + + static void resetDefaultHandler() { + defaultExceptionHandler = DEFAULT_HANDLER; + } + + /** + * Constructs an Event object from its interface. + * @param intrface The Event interface. + * @param The Event type. + * @return Returns an instance of the Event. + */ + @SuppressWarnings("unchecked") + public static T getEvent(Class intrface) { + + Class[] interfaces = new Class[] { intrface }; + + AuditMessage msg = buildAuditMessage(intrface); + AuditEvent audit = (AuditEvent) Proxy.newProxyInstance(intrface.getClassLoader(), interfaces, + new AuditProxy(msg, intrface, defaultExceptionHandler)); + + return (T) audit; + } + + private static String getEventName(Class intrface) { + EventName eventName = intrface.getAnnotation(EventName.class); + return eventName != null ? eventName.value() : NamingUtils.lowerFirst(intrface.getSimpleName()); + } + + private static int getMaxLength(Class intrface) { + MaxLength maxLength = intrface.getAnnotation(MaxLength.class); + return maxLength == null ? DEFAULT_MAX_LENGTH : maxLength.value(); + } + + private static AuditMessage buildAuditMessage(Class intrface) { + String eventName = getEventName(intrface); + int msgLength = getMaxLength(intrface); + return new AuditMessage(eventName, msgLength); + } + + /** + * + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited using the default error handler. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + */ + public static void logEvent(Class intrface, Map properties) { + logEvent(intrface, properties, DEFAULT_HANDLER); + } + + /** + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(Class intrface, Map properties, AuditExceptionHandler handler) { + AuditMessage msg = buildAuditMessage(intrface); + + if (properties != null) { + for (Map.Entry entry : properties.entrySet()) { + msg.put(entry.getKey(), entry.getValue()); + } + } + + validateEvent(intrface, msg); + logEvent(msg, handler); + } + + private static void validateEvent(Class intrface, AuditMessage msg) { + StringBuilder errors = new StringBuilder(); + validateContextConstraints(intrface, errors); + + List props = getProperties(intrface); + Map propertyMap = new HashMap<>(); + + for (Property property : props) { + propertyMap.put(property.name, property); + if (property.isRequired && !msg.containsKey(property.name)) { + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append("Required attribute ").append(property.name).append(" is missing from ").append(msg.getId().getName()); + } + if (msg.containsKey(property.name)) { + validateConstraints(false, property.constraints, property.name, msg, errors); + } + } + + msg.forEach((key, value) -> { + if (!propertyMap.containsKey(key)) { + if (errors.length() > 0) { + errors.append("Attribute ").append(key).append(" is not defined for ").append(msg.getId().getName()); + } + } + }); + + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + } + + /** + * Used to Log the actual AuditMessage. + * @param msg The AuditMessage. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(AuditMessage msg, AuditExceptionHandler handler) { + runMessageAction(() -> AUDIT_LOGGER.logEvent(msg), msg, handler); + } + + private static void runMessageAction(Runnable action, AuditMessage msg, AuditExceptionHandler handler) { + try { + action.run(); + } catch (Throwable ex) { + if (handler == null) { + handler = defaultExceptionHandler; + } + handler.handleException(msg, ex); + } + } + + public static List getPropertyNames(String className) { + Class intrface = getClass(className); + List names; + if (intrface != null) { + List props = getProperties(intrface); + names = new ArrayList<>(props.size()); + for (Property prop : props) { + names.add(prop.name); + } + } else { + names = new ArrayList<>(); + } + return names; + } + + private static List getProperties(Class intrface) { + List props = classMap.get(intrface); + if (props != null) { + return props; + } + props = new ArrayList<>(); + Method[] methods = intrface.getMethods(); + boolean isCompletionStatus = false; + for (Method method : methods) { + if (method.getName().startsWith("set") && !method.getName().equals("setAuditExceptionHandler")) { + if (method.getName().equals("setCompletionStatus")) { + isCompletionStatus = true; + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + Annotation[] annotations = method.getDeclaredAnnotations(); + List constraints = new ArrayList<>(); + boolean isRequired = false; + for (Annotation annotation : annotations) { + if (annotation instanceof Constraint) { + constraints.add((Constraint) annotation); + } + if (annotation instanceof Required) { + isRequired = true; + } + } + props.add(new Property(name, isRequired, constraints)); + } + } + if (!isCompletionStatus) { + props.add(new Property("completionStatus", false, new ArrayList<>())); + } + + classMap.putIfAbsent(intrface, props); + return classMap.get(intrface); + } + + private static Class getClass(String className) { + try { + Class intrface = Class.forName(className); + if (AuditEvent.class.isAssignableFrom(intrface)) { + return intrface; + } + logger.error(className + " is not an AuditEvent"); + } catch (ClassNotFoundException cnfe) { + logger.error("Unable to locate class {}", className); + } + return null; + } + + private static class AuditProxy implements InvocationHandler { + + private final AuditMessage msg; + private final Class intrface; + private AuditExceptionHandler auditExceptionHandler; + + AuditProxy(AuditMessage msg, Class intrface, AuditExceptionHandler auditExceptionHandler) { + this.msg = msg; + this.intrface = intrface; + this.auditExceptionHandler = auditExceptionHandler; + } + + public AuditMessage getMessage() { + return msg; + } + + @Override + public Object invoke(Object o, Method method, Object[] objects) { + if (method.getName().equals("toString") && method.getParameterCount() == 0) { + return msg.toString(); + } + + if (method.getName().equals("logEvent")) { + + runMessageAction(() -> validateEvent(intrface, msg), msg, auditExceptionHandler); + + logEvent(msg, auditExceptionHandler); + return null; + } + + if (method.getName().equals("setCompletionStatus")) { + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("Missing completion status"); + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + msg.put(name, objects[0].toString()); + return null; + } + + if (method.getName().equals("setAuditExceptionHandler")) { + if (objects == null || objects[0] == null) { + auditExceptionHandler = NOOP_EXCEPTION_HANDLER; + } else if (objects[0] instanceof AuditExceptionHandler) { + auditExceptionHandler = (AuditExceptionHandler) objects[0]; + } else { + throw new IllegalArgumentException(objects[0] + " is not an " + AuditExceptionHandler.class.getName()); + } + return null; + } + + if (method.getName().startsWith("set")) { + runMessageAction(() -> setProperty(method, objects), msg, auditExceptionHandler); + return null; + } + + return null; + } + + @SuppressWarnings("unchecked") + private void setProperty(Method method, Object[] objects) { + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("No value to be set for " + name); + } + + StringBuilder errors = new StringBuilder(); + Annotation[] annotations = method.getDeclaredAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof Constraints) { + Constraints constraints = (Constraints) annotation; + validateConstraints(false, constraints.value(), name, objects[0].toString(), + errors); + } else if (annotation instanceof Constraint) { + Constraint constraint = (Constraint) annotation; + constraintPlugins.validateConstraint(false, constraint.constraintType(), + name, objects[0].toString(), constraint.constraintValue(), errors); + } + } + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + + String result; + if (objects[0] instanceof List) { + result = StringUtils.join(objects, ", "); + } else if (objects[0] instanceof Map) { + StructuredDataMessage extra = new StructuredDataMessage(name, null, null); + extra.putAll((Map) objects[0]); + msg.addContent(name, extra); + return; + } else { + result = objects[0].toString(); + } + + msg.put(name, result); + } + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + AuditMessage msg, StringBuilder errors) { + String value = isRequestContext ? ThreadContext.get(name) : msg.get(name); + validateConstraints(isRequestContext, constraints, name, value, errors); + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + String value, StringBuilder errors) { + for (Constraint constraint : constraints) { + constraintPlugins.validateConstraint(isRequestContext, constraint.constraintType(), name, value, + constraint.constraintValue(), errors); + } + } + +private static void validateContextConstraints(java.lang.Class intrface, java.lang.StringBuilder buffer) { + org.apache.logging.log4j.audit.annotation.RequestContextConstraints reqCtxConstraints = intrface.getAnnotation(org.apache.logging.log4j.audit.annotation.RequestContextConstraints.class); + { + for (org.apache.logging.log4j.audit.annotation.RequestContext ctx : /* NPEX_NULL_EXP */ + reqCtxConstraints.value()) { + org.apache.logging.log4j.audit.LogEventFactory.validateContextConstraint(ctx, buffer); + } + } +} + + private static void validateContextConstraint(RequestContext constraint, StringBuilder errors) { + if (constraint == null) { + // the request context is not mandatory + return; + } + + String value = ThreadContext.get(constraint.key()); + if (value != null) { + validateConstraints(true, constraint.constraints(), constraint.key(), value, errors); + } else if (constraint.required()) { + appendNewline(errors); + errors.append("ThreadContext does not contain required key ").append(constraint.key()); + } + } + + private static boolean isBlank(String value) { + return value != null && value.length() > 0; + } + + private static class Property { + private final String name; + private final boolean isRequired; + private final Constraint[] constraints; + + public Property(String name, boolean isRequired, List constraints) { + this.name = name; + this.constraints = constraints.toArray(new Constraint[0]); + this.isRequired = isRequired; + } + } + +} diff --git a/Java/logging-log4j-audit-LogEventFactory_378/metadata.json b/Java/logging-log4j-audit-LogEventFactory_378/metadata.json new file mode 100644 index 000000000..4dacda963 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_378/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-LogEventFactory_378", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 380, + "npe_method": "validateContextConstraints", + "deref_field": "reqCtxConstraints", + "npe_class": "LogEventFactory", + "repo": "logging-log4j-audit", + "bug_id": "LogEventFactory_378" + } +} diff --git a/Java/logging-log4j-audit-LogEventFactory_378/npe.json b/Java/logging-log4j-audit-LogEventFactory_378/npe.json new file mode 100644 index 000000000..e4c56137b --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_378/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 380, + "npe_method": "validateContextConstraints", + "deref_field": "reqCtxConstraints", + "npe_class": "LogEventFactory" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-LogEventFactory_389/Dockerfile b/Java/logging-log4j-audit-LogEventFactory_389/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_389/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-LogEventFactory_389/buggy.java b/Java/logging-log4j-audit-LogEventFactory_389/buggy.java new file mode 100644 index 000000000..6f5d12cb2 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_389/buggy.java @@ -0,0 +1,417 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.audit.annotation.Constraint; +import org.apache.logging.log4j.audit.annotation.Constraints; +import org.apache.logging.log4j.audit.annotation.EventName; +import org.apache.logging.log4j.audit.annotation.MaxLength; +import org.apache.logging.log4j.audit.annotation.RequestContext; +import org.apache.logging.log4j.audit.annotation.RequestContextConstraints; +import org.apache.logging.log4j.audit.annotation.Required; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.exception.ConstraintValidationException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins; +import org.apache.logging.log4j.message.StructuredDataMessage; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.logging.log4j.catalog.api.util.StringUtils.appendNewline; + +/** + * Handles logging generated Events. Every Event extends the AuditProxy, which handles construction of the + * Event and logging of the Event. + */ +public class LogEventFactory { + + private static final Logger logger = LogManager.getLogger(LogEventFactory.class); + + private static final AuditLogger AUDIT_LOGGER = new AuditLogger(); + + private static final int DEFAULT_MAX_LENGTH = 32; + + private static final AuditExceptionHandler DEFAULT_HANDLER = (message, ex) -> { + throw new AuditException("Error logging event " + message.getId().getName(), ex); + }; + + private static final AuditExceptionHandler NOOP_EXCEPTION_HANDLER = (message, ex) -> { + }; + + private static AuditExceptionHandler defaultExceptionHandler = DEFAULT_HANDLER; + + private static final ConcurrentMap, List> classMap = new ConcurrentHashMap<>(); + + private static final ConstraintPlugins constraintPlugins = ConstraintPlugins.getInstance(); + + public static void setDefaultHandler(AuditExceptionHandler exceptionHandler) { + defaultExceptionHandler = (exceptionHandler == null) ? NOOP_EXCEPTION_HANDLER : exceptionHandler; + } + + static void resetDefaultHandler() { + defaultExceptionHandler = DEFAULT_HANDLER; + } + + /** + * Constructs an Event object from its interface. + * @param intrface The Event interface. + * @param The Event type. + * @return Returns an instance of the Event. + */ + @SuppressWarnings("unchecked") + public static T getEvent(Class intrface) { + + Class[] interfaces = new Class[] { intrface }; + + AuditMessage msg = buildAuditMessage(intrface); + AuditEvent audit = (AuditEvent) Proxy.newProxyInstance(intrface.getClassLoader(), interfaces, + new AuditProxy(msg, intrface, defaultExceptionHandler)); + + return (T) audit; + } + + private static String getEventName(Class intrface) { + EventName eventName = intrface.getAnnotation(EventName.class); + return eventName != null ? eventName.value() : NamingUtils.lowerFirst(intrface.getSimpleName()); + } + + private static int getMaxLength(Class intrface) { + MaxLength maxLength = intrface.getAnnotation(MaxLength.class); + return maxLength == null ? DEFAULT_MAX_LENGTH : maxLength.value(); + } + + private static AuditMessage buildAuditMessage(Class intrface) { + String eventName = getEventName(intrface); + int msgLength = getMaxLength(intrface); + return new AuditMessage(eventName, msgLength); + } + + /** + * + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited using the default error handler. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + */ + public static void logEvent(Class intrface, Map properties) { + logEvent(intrface, properties, DEFAULT_HANDLER); + } + + /** + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(Class intrface, Map properties, AuditExceptionHandler handler) { + AuditMessage msg = buildAuditMessage(intrface); + + if (properties != null) { + for (Map.Entry entry : properties.entrySet()) { + msg.put(entry.getKey(), entry.getValue()); + } + } + + validateEvent(intrface, msg); + logEvent(msg, handler); + } + + private static void validateEvent(Class intrface, AuditMessage msg) { + StringBuilder errors = new StringBuilder(); + validateContextConstraints(intrface, errors); + + List props = getProperties(intrface); + Map propertyMap = new HashMap<>(); + + for (Property property : props) { + propertyMap.put(property.name, property); + if (property.isRequired && !msg.containsKey(property.name)) { + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append("Required attribute ").append(property.name).append(" is missing from ").append(msg.getId().getName()); + } + if (msg.containsKey(property.name)) { + validateConstraints(false, property.constraints, property.name, msg, errors); + } + } + + msg.forEach((key, value) -> { + if (!propertyMap.containsKey(key)) { + if (errors.length() > 0) { + errors.append("Attribute ").append(key).append(" is not defined for ").append(msg.getId().getName()); + } + } + }); + + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + } + + /** + * Used to Log the actual AuditMessage. + * @param msg The AuditMessage. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(AuditMessage msg, AuditExceptionHandler handler) { + runMessageAction(() -> AUDIT_LOGGER.logEvent(msg), msg, handler); + } + + private static void runMessageAction(Runnable action, AuditMessage msg, AuditExceptionHandler handler) { + try { + action.run(); + } catch (Throwable ex) { + if (handler == null) { + handler = defaultExceptionHandler; + } + handler.handleException(msg, ex); + } + } + + public static List getPropertyNames(String className) { + Class intrface = getClass(className); + List names; + if (intrface != null) { + List props = getProperties(intrface); + names = new ArrayList<>(props.size()); + for (Property prop : props) { + names.add(prop.name); + } + } else { + names = new ArrayList<>(); + } + return names; + } + + private static List getProperties(Class intrface) { + List props = classMap.get(intrface); + if (props != null) { + return props; + } + props = new ArrayList<>(); + Method[] methods = intrface.getMethods(); + boolean isCompletionStatus = false; + for (Method method : methods) { + if (method.getName().startsWith("set") && !method.getName().equals("setAuditExceptionHandler")) { + if (method.getName().equals("setCompletionStatus")) { + isCompletionStatus = true; + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + Annotation[] annotations = method.getDeclaredAnnotations(); + List constraints = new ArrayList<>(); + boolean isRequired = false; + for (Annotation annotation : annotations) { + if (annotation instanceof Constraint) { + constraints.add((Constraint) annotation); + } + if (annotation instanceof Required) { + isRequired = true; + } + } + props.add(new Property(name, isRequired, constraints)); + } + } + if (!isCompletionStatus) { + props.add(new Property("completionStatus", false, new ArrayList<>())); + } + + classMap.putIfAbsent(intrface, props); + return classMap.get(intrface); + } + + private static Class getClass(String className) { + try { + Class intrface = Class.forName(className); + if (AuditEvent.class.isAssignableFrom(intrface)) { + return intrface; + } + logger.error(className + " is not an AuditEvent"); + } catch (ClassNotFoundException cnfe) { + logger.error("Unable to locate class {}", className); + } + return null; + } + + private static class AuditProxy implements InvocationHandler { + + private final AuditMessage msg; + private final Class intrface; + private AuditExceptionHandler auditExceptionHandler; + + AuditProxy(AuditMessage msg, Class intrface, AuditExceptionHandler auditExceptionHandler) { + this.msg = msg; + this.intrface = intrface; + this.auditExceptionHandler = auditExceptionHandler; + } + + public AuditMessage getMessage() { + return msg; + } + + @Override + public Object invoke(Object o, Method method, Object[] objects) { + if (method.getName().equals("toString") && method.getParameterCount() == 0) { + return msg.toString(); + } + + if (method.getName().equals("logEvent")) { + + runMessageAction(() -> validateEvent(intrface, msg), msg, auditExceptionHandler); + + logEvent(msg, auditExceptionHandler); + return null; + } + + if (method.getName().equals("setCompletionStatus")) { + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("Missing completion status"); + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + msg.put(name, objects[0].toString()); + return null; + } + + if (method.getName().equals("setAuditExceptionHandler")) { + if (objects == null || objects[0] == null) { + auditExceptionHandler = NOOP_EXCEPTION_HANDLER; + } else if (objects[0] instanceof AuditExceptionHandler) { + auditExceptionHandler = (AuditExceptionHandler) objects[0]; + } else { + throw new IllegalArgumentException(objects[0] + " is not an " + AuditExceptionHandler.class.getName()); + } + return null; + } + + if (method.getName().startsWith("set")) { + runMessageAction(() -> setProperty(method, objects), msg, auditExceptionHandler); + return null; + } + + return null; + } + + @SuppressWarnings("unchecked") + private void setProperty(Method method, Object[] objects) { + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("No value to be set for " + name); + } + + StringBuilder errors = new StringBuilder(); + Annotation[] annotations = method.getDeclaredAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof Constraints) { + Constraints constraints = (Constraints) annotation; + validateConstraints(false, constraints.value(), name, objects[0].toString(), + errors); + } else if (annotation instanceof Constraint) { + Constraint constraint = (Constraint) annotation; + constraintPlugins.validateConstraint(false, constraint.constraintType(), + name, objects[0].toString(), constraint.constraintValue(), errors); + } + } + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + + String result; + if (objects[0] instanceof List) { + result = StringUtils.join(objects, ", "); + } else if (objects[0] instanceof Map) { + StructuredDataMessage extra = new StructuredDataMessage(name, null, null); + extra.putAll((Map) objects[0]); + msg.addContent(name, extra); + return; + } else { + result = objects[0].toString(); + } + + msg.put(name, result); + } + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + AuditMessage msg, StringBuilder errors) { + String value = isRequestContext ? ThreadContext.get(name) : msg.get(name); + validateConstraints(isRequestContext, constraints, name, value, errors); + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + String value, StringBuilder errors) { + for (Constraint constraint : constraints) { + constraintPlugins.validateConstraint(isRequestContext, constraint.constraintType(), name, value, + constraint.constraintValue(), errors); + } + } + + private static void validateContextConstraints(Class intrface, StringBuilder buffer) { + RequestContextConstraints reqCtxConstraints = intrface.getAnnotation(RequestContextConstraints.class); + if (reqCtxConstraints != null) { + for (RequestContext ctx : reqCtxConstraints.value()) { + validateContextConstraint(ctx, buffer); + } + } else { + RequestContext ctx = intrface.getAnnotation(RequestContext.class); + validateContextConstraint(ctx, buffer); + } + } + +private static void validateContextConstraint(org.apache.logging.log4j.audit.annotation.RequestContext constraint, java.lang.StringBuilder errors) { + { + java.lang.String value = org.apache.logging.log4j.ThreadContext.get(/* NPEX_NULL_EXP */ + constraint.key()); + if (value != null) { + org.apache.logging.log4j.audit.LogEventFactory.validateConstraints(true, constraint.constraints(), constraint.key(), value, errors); + } else if (constraint.required()) { + org.apache.logging.log4j.catalog.api.util.StringUtils.appendNewline(errors); + errors.append("ThreadContext does not contain required key ").append(constraint.key()); + } + } +} + + private static boolean isBlank(String value) { + return value != null && value.length() > 0; + } + + private static class Property { + private final String name; + private final boolean isRequired; + private final Constraint[] constraints; + + public Property(String name, boolean isRequired, List constraints) { + this.name = name; + this.constraints = constraints.toArray(new Constraint[0]); + this.isRequired = isRequired; + } + } + +} diff --git a/Java/logging-log4j-audit-LogEventFactory_389/metadata.json b/Java/logging-log4j-audit-LogEventFactory_389/metadata.json new file mode 100644 index 000000000..6c180c009 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_389/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-LogEventFactory_389", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 391, + "npe_method": "validateContextConstraint", + "deref_field": "constraint", + "npe_class": "LogEventFactory", + "repo": "logging-log4j-audit", + "bug_id": "LogEventFactory_389" + } +} diff --git a/Java/logging-log4j-audit-LogEventFactory_389/npe.json b/Java/logging-log4j-audit-LogEventFactory_389/npe.json new file mode 100644 index 000000000..8966ee4f6 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_389/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 391, + "npe_method": "validateContextConstraint", + "deref_field": "constraint", + "npe_class": "LogEventFactory" +} \ No newline at end of file diff --git a/Java/logging-log4j-audit-LogEventFactory_395/Dockerfile b/Java/logging-log4j-audit-LogEventFactory_395/Dockerfile new file mode 100644 index 000000000..bc0881741 --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_395/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:logging-log4j-audit + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/logging-log4j-audit-LogEventFactory_395/buggy.java b/Java/logging-log4j-audit-LogEventFactory_395/buggy.java new file mode 100644 index 000000000..a958226ad --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_395/buggy.java @@ -0,0 +1,416 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.audit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.audit.annotation.Constraint; +import org.apache.logging.log4j.audit.annotation.Constraints; +import org.apache.logging.log4j.audit.annotation.EventName; +import org.apache.logging.log4j.audit.annotation.MaxLength; +import org.apache.logging.log4j.audit.annotation.RequestContext; +import org.apache.logging.log4j.audit.annotation.RequestContextConstraints; +import org.apache.logging.log4j.audit.annotation.Required; +import org.apache.logging.log4j.audit.exception.AuditException; +import org.apache.logging.log4j.audit.exception.ConstraintValidationException; +import org.apache.logging.log4j.audit.util.NamingUtils; +import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins; +import org.apache.logging.log4j.message.StructuredDataMessage; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.logging.log4j.catalog.api.util.StringUtils.appendNewline; + +/** + * Handles logging generated Events. Every Event extends the AuditProxy, which handles construction of the + * Event and logging of the Event. + */ +public class LogEventFactory { + + private static final Logger logger = LogManager.getLogger(LogEventFactory.class); + + private static final AuditLogger AUDIT_LOGGER = new AuditLogger(); + + private static final int DEFAULT_MAX_LENGTH = 32; + + private static final AuditExceptionHandler DEFAULT_HANDLER = (message, ex) -> { + throw new AuditException("Error logging event " + message.getId().getName(), ex); + }; + + private static final AuditExceptionHandler NOOP_EXCEPTION_HANDLER = (message, ex) -> { + }; + + private static AuditExceptionHandler defaultExceptionHandler = DEFAULT_HANDLER; + + private static final ConcurrentMap, List> classMap = new ConcurrentHashMap<>(); + + private static final ConstraintPlugins constraintPlugins = ConstraintPlugins.getInstance(); + + public static void setDefaultHandler(AuditExceptionHandler exceptionHandler) { + defaultExceptionHandler = (exceptionHandler == null) ? NOOP_EXCEPTION_HANDLER : exceptionHandler; + } + + static void resetDefaultHandler() { + defaultExceptionHandler = DEFAULT_HANDLER; + } + + /** + * Constructs an Event object from its interface. + * @param intrface The Event interface. + * @param The Event type. + * @return Returns an instance of the Event. + */ + @SuppressWarnings("unchecked") + public static T getEvent(Class intrface) { + + Class[] interfaces = new Class[] { intrface }; + + AuditMessage msg = buildAuditMessage(intrface); + AuditEvent audit = (AuditEvent) Proxy.newProxyInstance(intrface.getClassLoader(), interfaces, + new AuditProxy(msg, intrface, defaultExceptionHandler)); + + return (T) audit; + } + + private static String getEventName(Class intrface) { + EventName eventName = intrface.getAnnotation(EventName.class); + return eventName != null ? eventName.value() : NamingUtils.lowerFirst(intrface.getSimpleName()); + } + + private static int getMaxLength(Class intrface) { + MaxLength maxLength = intrface.getAnnotation(MaxLength.class); + return maxLength == null ? DEFAULT_MAX_LENGTH : maxLength.value(); + } + + private static AuditMessage buildAuditMessage(Class intrface) { + String eventName = getEventName(intrface); + int msgLength = getMaxLength(intrface); + return new AuditMessage(eventName, msgLength); + } + + /** + * + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited using the default error handler. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + */ + public static void logEvent(Class intrface, Map properties) { + logEvent(intrface, properties, DEFAULT_HANDLER); + } + + /** + * This method is used to construct and AuditMessage from a set of properties and the Event interface + * that represents the event being audited. + * @param intrface The Event interface. + * @param properties The properties to be included in the event. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(Class intrface, Map properties, AuditExceptionHandler handler) { + AuditMessage msg = buildAuditMessage(intrface); + + if (properties != null) { + for (Map.Entry entry : properties.entrySet()) { + msg.put(entry.getKey(), entry.getValue()); + } + } + + validateEvent(intrface, msg); + logEvent(msg, handler); + } + + private static void validateEvent(Class intrface, AuditMessage msg) { + StringBuilder errors = new StringBuilder(); + validateContextConstraints(intrface, errors); + + List props = getProperties(intrface); + Map propertyMap = new HashMap<>(); + + for (Property property : props) { + propertyMap.put(property.name, property); + if (property.isRequired && !msg.containsKey(property.name)) { + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append("Required attribute ").append(property.name).append(" is missing from ").append(msg.getId().getName()); + } + if (msg.containsKey(property.name)) { + validateConstraints(false, property.constraints, property.name, msg, errors); + } + } + + msg.forEach((key, value) -> { + if (!propertyMap.containsKey(key)) { + if (errors.length() > 0) { + errors.append("Attribute ").append(key).append(" is not defined for ").append(msg.getId().getName()); + } + } + }); + + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + } + + /** + * Used to Log the actual AuditMessage. + * @param msg The AuditMessage. + * @param handler Class that gets control when an exception occurs logging the event. + */ + public static void logEvent(AuditMessage msg, AuditExceptionHandler handler) { + runMessageAction(() -> AUDIT_LOGGER.logEvent(msg), msg, handler); + } + + private static void runMessageAction(Runnable action, AuditMessage msg, AuditExceptionHandler handler) { + try { + action.run(); + } catch (Throwable ex) { + if (handler == null) { + handler = defaultExceptionHandler; + } + handler.handleException(msg, ex); + } + } + + public static List getPropertyNames(String className) { + Class intrface = getClass(className); + List names; + if (intrface != null) { + List props = getProperties(intrface); + names = new ArrayList<>(props.size()); + for (Property prop : props) { + names.add(prop.name); + } + } else { + names = new ArrayList<>(); + } + return names; + } + + private static List getProperties(Class intrface) { + List props = classMap.get(intrface); + if (props != null) { + return props; + } + props = new ArrayList<>(); + Method[] methods = intrface.getMethods(); + boolean isCompletionStatus = false; + for (Method method : methods) { + if (method.getName().startsWith("set") && !method.getName().equals("setAuditExceptionHandler")) { + if (method.getName().equals("setCompletionStatus")) { + isCompletionStatus = true; + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + Annotation[] annotations = method.getDeclaredAnnotations(); + List constraints = new ArrayList<>(); + boolean isRequired = false; + for (Annotation annotation : annotations) { + if (annotation instanceof Constraint) { + constraints.add((Constraint) annotation); + } + if (annotation instanceof Required) { + isRequired = true; + } + } + props.add(new Property(name, isRequired, constraints)); + } + } + if (!isCompletionStatus) { + props.add(new Property("completionStatus", false, new ArrayList<>())); + } + + classMap.putIfAbsent(intrface, props); + return classMap.get(intrface); + } + + private static Class getClass(String className) { + try { + Class intrface = Class.forName(className); + if (AuditEvent.class.isAssignableFrom(intrface)) { + return intrface; + } + logger.error(className + " is not an AuditEvent"); + } catch (ClassNotFoundException cnfe) { + logger.error("Unable to locate class {}", className); + } + return null; + } + + private static class AuditProxy implements InvocationHandler { + + private final AuditMessage msg; + private final Class intrface; + private AuditExceptionHandler auditExceptionHandler; + + AuditProxy(AuditMessage msg, Class intrface, AuditExceptionHandler auditExceptionHandler) { + this.msg = msg; + this.intrface = intrface; + this.auditExceptionHandler = auditExceptionHandler; + } + + public AuditMessage getMessage() { + return msg; + } + + @Override + public Object invoke(Object o, Method method, Object[] objects) { + if (method.getName().equals("toString") && method.getParameterCount() == 0) { + return msg.toString(); + } + + if (method.getName().equals("logEvent")) { + + runMessageAction(() -> validateEvent(intrface, msg), msg, auditExceptionHandler); + + logEvent(msg, auditExceptionHandler); + return null; + } + + if (method.getName().equals("setCompletionStatus")) { + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("Missing completion status"); + } + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + msg.put(name, objects[0].toString()); + return null; + } + + if (method.getName().equals("setAuditExceptionHandler")) { + if (objects == null || objects[0] == null) { + auditExceptionHandler = NOOP_EXCEPTION_HANDLER; + } else if (objects[0] instanceof AuditExceptionHandler) { + auditExceptionHandler = (AuditExceptionHandler) objects[0]; + } else { + throw new IllegalArgumentException(objects[0] + " is not an " + AuditExceptionHandler.class.getName()); + } + return null; + } + + if (method.getName().startsWith("set")) { + runMessageAction(() -> setProperty(method, objects), msg, auditExceptionHandler); + return null; + } + + return null; + } + + @SuppressWarnings("unchecked") + private void setProperty(Method method, Object[] objects) { + String name = NamingUtils.lowerFirst(NamingUtils.getMethodShortName(method.getName())); + if (objects == null || objects[0] == null) { + throw new IllegalArgumentException("No value to be set for " + name); + } + + StringBuilder errors = new StringBuilder(); + Annotation[] annotations = method.getDeclaredAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof Constraints) { + Constraints constraints = (Constraints) annotation; + validateConstraints(false, constraints.value(), name, objects[0].toString(), + errors); + } else if (annotation instanceof Constraint) { + Constraint constraint = (Constraint) annotation; + constraintPlugins.validateConstraint(false, constraint.constraintType(), + name, objects[0].toString(), constraint.constraintValue(), errors); + } + } + if (errors.length() > 0) { + throw new ConstraintValidationException(errors.toString()); + } + + String result; + if (objects[0] instanceof List) { + result = StringUtils.join(objects, ", "); + } else if (objects[0] instanceof Map) { + StructuredDataMessage extra = new StructuredDataMessage(name, null, null); + extra.putAll((Map) objects[0]); + msg.addContent(name, extra); + return; + } else { + result = objects[0].toString(); + } + + msg.put(name, result); + } + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + AuditMessage msg, StringBuilder errors) { + String value = isRequestContext ? ThreadContext.get(name) : msg.get(name); + validateConstraints(isRequestContext, constraints, name, value, errors); + } + + private static void validateConstraints(boolean isRequestContext, Constraint[] constraints, String name, + String value, StringBuilder errors) { + for (Constraint constraint : constraints) { + constraintPlugins.validateConstraint(isRequestContext, constraint.constraintType(), name, value, + constraint.constraintValue(), errors); + } + } + + private static void validateContextConstraints(Class intrface, StringBuilder buffer) { + RequestContextConstraints reqCtxConstraints = intrface.getAnnotation(RequestContextConstraints.class); + if (reqCtxConstraints != null) { + for (RequestContext ctx : reqCtxConstraints.value()) { + validateContextConstraint(ctx, buffer); + } + } else { + RequestContext ctx = intrface.getAnnotation(RequestContext.class); + validateContextConstraint(ctx, buffer); + } + } + +private static void validateContextConstraint(org.apache.logging.log4j.audit.annotation.RequestContext constraint, java.lang.StringBuilder errors) { + if (constraint == null) { + // the request context is not mandatory + return; + } + java.lang.String value = org.apache.logging.log4j.ThreadContext.get(constraint.key()); + { + org.apache.logging.log4j.audit.LogEventFactory.validateConstraints(true, constraint.constraints(), constraint.key(), /* NPEX_NULL_EXP */ + value, errors); + } +} + + private static boolean isBlank(String value) { + return value != null && value.length() > 0; + } + + private static class Property { + private final String name; + private final boolean isRequired; + private final Constraint[] constraints; + + public Property(String name, boolean isRequired, List constraints) { + this.name = name; + this.constraints = constraints.toArray(new Constraint[0]); + this.isRequired = isRequired; + } + } + +} diff --git a/Java/logging-log4j-audit-LogEventFactory_395/metadata.json b/Java/logging-log4j-audit-LogEventFactory_395/metadata.json new file mode 100644 index 000000000..99a1ae79e --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_395/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "logging-log4j-audit-LogEventFactory_395", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 396, + "npe_method": "validateContextConstraint", + "deref_field": "value", + "npe_class": "LogEventFactory", + "repo": "logging-log4j-audit", + "bug_id": "LogEventFactory_395" + } +} diff --git a/Java/logging-log4j-audit-LogEventFactory_395/npe.json b/Java/logging-log4j-audit-LogEventFactory_395/npe.json new file mode 100644 index 000000000..dc8b50b8d --- /dev/null +++ b/Java/logging-log4j-audit-LogEventFactory_395/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/LogEventFactory.java", + "line": 396, + "npe_method": "validateContextConstraint", + "deref_field": "value", + "npe_class": "LogEventFactory" +} \ No newline at end of file