r-lang-0001: namespace.R getNamespaceUsers() O(N*I) match() linear scan and namespaceImportMethods() O(G*V) %in% double scan; fix: hash env + reverse index. Unit test: 5.4x (namespace users) and 5.6x (import methods) speedup. PASS. Octave: MOAD-0002 through 0005 all CLEAN (single-threaded, no ThreadLocal, no credential logging found, no concurrent cache races).
46 lines
2.3 KiB
Diff
46 lines
2.3 KiB
Diff
# UNDF: (leave blank — assigned later)
|
|
--- a/src/library/base/R/namespace.R
|
|
+++ b/src/library/base/R/namespace.R
|
|
@@ -76,10 +76,11 @@ getNamespaceInfo <- function(ns, which)
|
|
getNamespaceUsers <- function(ns) {
|
|
nsname <- getNamespaceName(asNamespace(ns))
|
|
users <- character()
|
|
- for (n in loadedNamespaces()) {
|
|
- inames <- names(getNamespaceImports(n))
|
|
- if (match(nsname, inames, 0L))
|
|
- users <- c(n, users)
|
|
- }
|
|
+ # CWE-407 fix: inames is rebuilt as a vector each iteration; match() is O(|inames|).
|
|
+ # Total complexity was O(N * I) where N = loadedNamespaces(), I = avg imports per ns.
|
|
+ # Fix: build a named environment (hash-backed) once per outer iteration, O(1) lookup.
|
|
+ for (n in loadedNamespaces()) {
|
|
+ inames_set <- new.env(hash = TRUE, parent = emptyenv())
|
|
+ for (nm in names(getNamespaceImports(n))) assign(nm, TRUE, envir = inames_set)
|
|
+ if (exists(nsname, envir = inames_set, inherits = FALSE))
|
|
+ users <- c(n, users)
|
|
+ }
|
|
users
|
|
}
|
|
|
|
@@ -1136,9 +1137,11 @@ namespaceImportMethods <- function(self, ns, vars, from = NULL)
|
|
for(i in seq_along(allFuns)) {
|
|
## import methods tables if asked for
|
|
## or if the corresponding generic was imported
|
|
g <- allFuns[[i]]
|
|
p <- allPackages[[i]]
|
|
- if(exists(g, envir = self, inherits = FALSE) # already imported
|
|
- || g %in% vars) { # requested explicitly
|
|
+ # CWE-407 fix: g %in% vars is O(|vars|) per iteration — O(|allFuns| * |vars|) total.
|
|
+ # Fix: convert vars to a hash-backed environment once before the loop.
|
|
+ if(exists(g, envir = self, inherits = FALSE) # already imported
|
|
+ || exists(g, envir = vars_set, inherits = FALSE)) { # requested explicitly
|
|
tbl <- methods:::.TableMetaName(g, p)
|
|
if(is.null(.mergeImportMethods(self, ns, tbl))) { # a new methods table
|
|
allVars <- c(allVars, tbl) # import it;else, was merged
|
|
@@ -1148,7 +1151,8 @@ namespaceImportMethods <- function(self, ns, vars, from = NULL)
|
|
}
|
|
}
|
|
- if(g %in% vars && !exists(g, envir = self, inherits = FALSE)) {
|
|
+ if(exists(g, envir = vars_set, inherits = FALSE) &&
|
|
+ !exists(g, envir = self, inherits = FALSE)) {
|
|
if(!is.null(f <- get0(g, envir = ns)) && methods::is(f, "genericFunction")) {
|