/**
 * @name Call to memory access function may overflow buffer
 * @description Incorrect use of a function that accesses a memory
 *              buffer may read or write data past the end of that
 *              buffer.
 * @kind problem
 * @id cpp/overflow-buffer
 * @problem.severity recommendation
 * @tags security
 *       external/cwe/cwe-119
 *       external/cwe/cwe-121
 *       external/cwe/cwe-122
 *       external/cwe/cwe-126
 */

import semmle.code.cpp.security.BufferWrite
import semmle.code.cpp.security.BufferAccess

bindingset[num, singular, plural]
string plural(int num, string singular, string plural) {
  if num = 1 then result = num + singular else result = num + plural
}

from
  BufferAccess ba, string bufferDesc, int accessSize, int accessType, Element bufferAlloc,
  int bufferSize, string message
where
  accessSize = ba.getSize() and
  bufferSize = getBufferSize(ba.getBuffer(bufferDesc, accessType), bufferAlloc) and
  (
    accessSize > bufferSize
    or
    accessSize <= 0 and accessType = 3
  ) and
  if accessType = 1
  then
    message =
      "This '" + ba.getName() + "' operation accesses " + plural(accessSize, " byte", " bytes") +
        " but the $@ is only " + plural(bufferSize, " byte", " bytes") + "."
  else
    if accessType = 2
    then
      message =
        "This '" + ba.getName() + "' operation may access " + plural(accessSize, " byte", " bytes") +
          " but the $@ is only " + plural(bufferSize, " byte", " bytes") + "."
    else (
      if accessSize > 0
      then
        message =
          "This array indexing operation accesses byte offset " + (accessSize - 1) +
            " but the $@ is only " + plural(bufferSize, " byte", " bytes") + "."
      else
        message =
          "This array indexing operation accesses a negative index " +
            ((accessSize / ba.getActualType().getSize()) - 1) + " on the $@."
    )
select ba, message, bufferAlloc, bufferDesc
