Skip to content

Loaders

mert tiftikci edited this page Nov 24, 2020 · 1 revision

These functions are responsible for sourcing a script into the provided environment. They have two parameters where the first one is the file path of the script and the second one is the environment. These functions return a boolean value which controls the usage of default sourcing. A couple of loaders are provided below which are used in certain circumstances as examples.

Line Ignoring Loader

loader <- function(file, envir) {
  # Parse file instead of sourcing
  parsed <- parse(file)
  if(length(parsed) == 0) {
    return()
  }
  
  # Execute lines one by one into the given environment
  for (i in 1:length(parsed)) {
    exp <- parsed[[i]]
    object_call <- class(exp) == "name"
    
    if(!object_call && length(exp) > 1) {
      if(exp[[1]] == "setwd"){
        next
      } else if(exp[[1]] == '<-' && length(exp[[3]]) > 1 && exp[[3]][[1]] == "readdata") {
        next
      }
    }
    
    # Run the expression into the given environment
    withTimeout(expr = exp, substitute = F, envir = envir, timeout = 1.5, onTimeout = "error")
  }
  
  # Consider the only injected when False normal source is tested as well
  return(T)
}

Code Injection Loader

loader <- function(file, envir) {
  # Parse file instead of sourcing
  parsed <- parse(file)
  if(length(parsed) == 0) {
    return()
  }
  
  # Inject following lines as a start of each script in order to ensure same randomness
  withTimeout(expr = parse(text="RNGversion(\"3.3.1\")"), substitute = F,
              envir = envir, timeout = 1.5, onTimeout = "error")
  withTimeout(expr = parse(text="set.seed(20200501)"), substitute = F,
              envir = envir, timeout = 1.5, onTimeout = "error")
  
  # Execute lines one by one into the given environment
  for (i in 1:length(parsed)) {
    exp <- parsed[[i]]
    object_call <- class(exp) == "name"
    
    if(!object_call && length(exp) > 1 && length(exp[[1]]) > 1) {
      # Calling these functions by the scripts were forbidden since they contain RNG operations.
      # If these were allowed, each call would change the random state therefore change the correct answer.
      if(any(exp[[1]][[1]] == c("make_grade_matrix", "fundreturn", "fundreturn_aftertax")))
        next
    }
    
    # Run the expression into the given environment
    withTimeout(expr = exp, substitute = F, envir = envir, timeout = 1.5, onTimeout = "error")
  }
  
  # Consider the only injected when False normal source is tested as well
  return(T)
}

Code Altering

loader <- function(file, envir) {
  # Parse file instead of sourcing
  parsed <- parse(file)
  if(length(parsed) == 0) {
    return()
  }
  
  # Execute lines one by one into the given environment
  for (i in 1:length(parsed)) {
    exp <- parsed[[i]]
    object_call <- class(exp) == "name"
    
    if(!object_call) {
      if(exp[[1]] == "setwd") {
        next
      }
      
      # parameter of load function in scripts is changed to match with the location within the server
      if(exp[[1]] == "load") {
        exp[[2]] <- "path/to/data/folder/distance2.RData"
      }
    }
    
    # Run the expression into the given environment
    withTimeout(expr = exp, substitute = F, envir = envir, timeout = 1.5, onTimeout = "error")
  }
  
  # Consider the only injected when False normal source is tested as well
  return(T)
}

Here in the following example is used to change the value of a variable which should be defined at the beginning of the students to use later on for the given task. Normally, asking questions as a function and testing them with different arguments should suffice but here students have not learned about the functions yet. Therefore changing different inputs is only possible by altering the data by code injection.

loader <- function(file, envir) {
  set.seed(2011400222)
  hundred1 <- round(rnorm(20, 9, 0.5), 2)
  names(hundred1) <- letters[sample(20)]
  
  # Parse file instead of sourcing
  parsed <- parse(file)
  if(length(parsed) == 0) {
    return()
  }
  
  # Execute lines one by one into the given environment
  for (i in 1:length(parsed)) {
    expression <- parsed[[i]]
    object_call <- class(expression) == "name"
    
    # Run the expression into the given environment
    withTimeout(expr = expression, substitute = F, envir = envir, timeout = 1.5, onTimeout = "error")
    
    # Change the variable as a test
    if(!object_call && length(expression) > 1 && class(expression[[2]]) != "name") {
      if(expression[[2]][[1]] == "names" && expression[[2]][[2]] == "hundred") {
        assign("hundred", hundred1, envir = envir)
      }
    }
  }
  
  # Consider the only injected when False normal source is tested as well
  return(T)
}

Clone this wiki locally