db-d2/primevul-codebert-embeddings huggingface dataset:
Commit message: None
CVE: CVE-2016-3861
CWE: CWE-119
Vulnerability description: LibUtils in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, 6.x before 2016-09-01, and 7.0 before 2016-09-01 mishandles conversions between Unicode character encodings with different encoding widths, which allows remote attackers to execute arbitrary code or cause a denial of service (heap-based buffer overflow) via a crafted file, aka internal bug 29250543.

Project: Android

status_t Parcel::readBoolVector(std::vector<bool>* val) const {
 int32_t size;
 status_t status = readInt32(&size);

 if (status != OK) {
 return status;
 }

 if (size < 0) {
 return UNEXPECTED_NULL;
 }

    val->resize(size);

 /* C++ bool handling means a vector of bools isn't necessarily addressable
     * (we might use individual bits)
     */
 bool data;
 for (int32_t i = 0; i < size; ++i) {
        status = readBool(&data);
 (*val)[i] = data;

 if (status != OK) {
 return status;
 }
 }

 return OK;
}

Project: Android

char16_t Parcel::readChar() const
{
 return char16_t(readInt32());
}

Project: Android

status_t Parcel::readDoubleVector(std::vector<double>* val) const {
 return readTypedVector(val, &Parcel::readDouble);
}

Project: Android

int32_t Parcel::readExceptionCode() const
{
    binder::Status status;
    status.readFromParcel(*this);
 return status.exceptionCode();
}

Project: Android

status_t Parcel::readFloatVector(std::vector<float>* val) const {
 return readTypedVector(val, &Parcel::readFloat);
}

Project: Android

status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<ScopedFd>>* val) const {
 return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
}

Project: Android

status_t Parcel::writeByte(int8_t val)
{
 return writeInt32(int32_t(val));
}

Project: Android

status_t Parcel::writeByteVector(const std::vector<int8_t>& val) {
 return writeByteVectorInternal(this, val);
}

Project: Android

status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
{
 return writeTypedVector(val, &Parcel::writeInt64);
}

Project: Android

status_t Parcel::writeString16Vector(
 const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val)
{
 return writeNullableTypedVector(val, &Parcel::writeString16);
}

Project: Android

status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) {
 return writeTypedVector(val, &Parcel::writeUtf8AsUtf16);
}
Commit message: None
CVE: CVE-2016-3861
CWE: CWE-119
Vulnerability description: LibUtils in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, 6.x before 2016-09-01, and 7.0 before 2016-09-01 mishandles conversions between Unicode character encodings with different encoding widths, which allows remote attackers to execute arbitrary code or cause a denial of service (heap-based buffer overflow) via a crafted file, aka internal bug 29250543.

Project: Android

StringPiece16::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece16& str,
 const StringPiece16& allowedChars) {
 const auto endIter = str.end();
 for (auto iter = str.begin(); iter != endIter; ++iter) {
 char16_t c = *iter;
 if ((c >= u'a' && c <= u'z') ||
 (c >= u'A' && c <= u'Z') ||
 (c >= u'0' && c <= u'9')) {
 continue;
 }

 bool match = false;
 for (char16_t i : allowedChars) {
 if (c == i) {
                match = true;
 break;
 }
 }

 if (!match) {
 return iter;
 }
 }
 return endIter;
}

Project: Android

Maybe<std::u16string> getFullyQualifiedClassName(const StringPiece16& package,
 const StringPiece16& className) {
 if (className.empty()) {
 return {};
 }

 if (util::isJavaClassName(className)) {
 return className.toString();
 }

 if (package.empty()) {
 return {};
 }

 if (className.data()[0] != u'.') {
 return {};
 }

    std::u16string result(package.data(), package.size());
    result.append(className.data(), className.size());
 if (!isJavaClassName(result)) {
 return {};
 }
 return result;
}

Project: Android

static Maybe<char16_t> parseUnicodeCodepoint(const char16_t** start, const char16_t* end) {
 char16_t code = 0;
 for (size_t i = 0; i < 4 && *start != end; i++, (*start)++) {
 char16_t c = **start;
 int a;
 if (c >= '0' && c <= '9') {
            a = c - '0';
 } else if (c >= 'a' && c <= 'f') {
            a = c - 'a' + 10;
 } else if (c >= 'A' && c <= 'F') {
            a = c - 'A' + 10;
 } else {
 return make_nothing<char16_t>();
 }
        code = (code << 4) | a;
 }
 return make_value(code);
}
Commit message: None
CVE: CVE-2016-3760
CWE: CWE-20
Vulnerability description: Bluetooth in Android 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-07-01 allows local users to gain privileges by establishing a pairing that remains present during a session of the primary user, aka internal bug 27410683.

Project: Android

static void acl_state_changed_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
 bt_acl_state_t state)
{
    jbyteArray addr;
 int i;
 if (!checkCallbackThread()) {
       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
 return;
 }
 if (!bd_addr) {
        ALOGE("Address is null in %s", __FUNCTION__);
 return;
 }
    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
 if (addr == NULL) {
       ALOGE("Address allocation failed in %s", __FUNCTION__);
 return;
 }
    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);

    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_aclStateChangeCallback, (jint) status,
                                addr, (jint)state);
    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
    callbackEnv->DeleteLocalRef(addr);
}

Project: Android

static bool cleanupNative(JNIEnv *env, jobject obj) {
    ALOGV("%s:",__FUNCTION__);

    jboolean result = JNI_FALSE;
 if (!sBluetoothInterface) return result;

    sBluetoothInterface->cleanup();
    ALOGI("%s: return from cleanup",__FUNCTION__);

    env->DeleteGlobalRef(sJniCallbacksObj);
    env->DeleteGlobalRef(sJniAdapterServiceObj);

     return JNI_TRUE;
 }

Project: Android

static jboolean configHciSnoopLogNative(JNIEnv* env, jobject obj, jboolean enable) {
    ALOGV("%s:",__FUNCTION__);

    jboolean result = JNI_FALSE;

 if (!sBluetoothInterface) return result;

 int ret = sBluetoothInterface->config_hci_snoop_log(enable);

    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;

 return result;
}

Project: Android

static void energy_info_recv_callback(bt_activity_energy_info *p_energy_info)
{
 if (!checkCallbackThread()) {
       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
 return;
 }

    callbackEnv->CallVoidMethod(sJniAdapterServiceObj, method_energyInfo, p_energy_info->status,
        p_energy_info->ctrl_state, p_energy_info->tx_time, p_energy_info->rx_time,
        p_energy_info->idle_time, p_energy_info->energy_used);

    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
}
Commit message: None
CVE: CVE-2016-2464
CWE: CWE-20
Vulnerability description: libvpx in libwebm in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-06-01 allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted mkv file, aka internal bug 23167726.

Project: Android
File: mkvparser.cc

const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
 const CuePoint::TrackPosition& tp) const {
  assert(m_pSegment);
 const long long tc = cp.GetTimeCode();

 if (tp.m_block > 0) {
 const long block = static_cast<long>(tp.m_block);
 const long index = block - 1;

 while (index >= m_entries_count) {
 long long pos;
 long len;

 const long status = Parse(pos, len);

 if (status < 0) // TODO: can this happen?
 return NULL;

 if (status > 0) // nothing remains to be parsed
 return NULL;
 }

 const BlockEntry* const pEntry = m_entries[index];
    assert(pEntry);
    assert(!pEntry->EOS());

 const Block* const pBlock = pEntry->GetBlock();
    assert(pBlock);

 if ((pBlock->GetTrackNumber() == tp.m_track) &&
 (pBlock->GetTimeCode(this) == tc)) {
 return pEntry;
 }
 }

 long index = 0;

 for (;;) {
 if (index >= m_entries_count) {
 long long pos;
 long len;

 const long status = Parse(pos, len);

 if (status < 0) // TODO: can this happen?
 return NULL;

 if (status > 0) // nothing remains to be parsed
 return NULL;

      assert(m_entries);
      assert(index < m_entries_count);
 }

 const BlockEntry* const pEntry = m_entries[index];
    assert(pEntry);
    assert(!pEntry->EOS());

 const Block* const pBlock = pEntry->GetBlock();
    assert(pBlock);

 if (pBlock->GetTrackNumber() != tp.m_track) {
 ++index;
 continue;
 }

 const long long tc_ = pBlock->GetTimeCode(this);

 if (tc_ < tc) {
 ++index;
 continue;
 }

 if (tc_ > tc)
 return NULL;

 const Tracks* const pTracks = m_pSegment->GetTracks();
    assert(pTracks);

 const long tn = static_cast<long>(tp.m_track);
 const Track* const pTrack = pTracks->GetTrackByNumber(tn);

 if (pTrack == NULL)
 return NULL;

 const long long type = pTrack->GetType();

 if (type == 2) // audio
 return pEntry;

 if (type != 1) // not video
 return NULL;

 if (!pBlock->IsKey())
 return NULL;

 return pEntry;
 }
}

Project: Android
File: mkvparser.cc

void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
  rhs.m_tag_name = m_tag_name;
  rhs.m_tag_string = m_tag_string;
}

Project: Android
File: mkvparser.cc

Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size,
 long long element_start, long long element_size)
 : m_pSegment(pSegment),
      m_start(payload_start),
      m_size(payload_size),
      m_element_start(element_start),
      m_element_size(element_size),
      m_tags(NULL),
      m_tags_size(0),
      m_tags_count(0) {}
Commit message: [glib] Fix CVE-2009-3607
CVE: CVE-2009-3607
CWE: CWE-189
Vulnerability description: Integer overflow in the create_surface_from_thumbnail_data function in glib/poppler-page.cc in Poppler 0.x allows remote attackers to cause a denial of service (memory corruption) or possibly execute arbitrary code via a crafted PDF document that triggers a heap-based buffer overflow.  NOTE: some of these details are obtained from third party information.

Project: poppler
File: poppler-page.cc

create_surface_from_thumbnail_data (guchar *data,
				    gint    width,
				    gint    height,
 				    gint    rowstride)
 {
   guchar *cairo_pixels;
  gint cairo_stride;
   cairo_surface_t *surface;
   int j;
 
  surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
  if (cairo_surface_status (surface))
    return NULL;

  cairo_pixels = cairo_image_surface_get_data (surface);
  cairo_stride = cairo_image_surface_get_stride (surface);
 
   for (j = height; j; j--) {
     guchar *p = data;
     guchar *q = cairo_pixels;
     guchar *end = p + 3 * width;

     while (p < end) {
 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
       q[0] = p[2];
       q[1] = p[1];
       q[2] = p[0];
#else
       q[1] = p[0];
       q[2] = p[1];
       q[3] = p[2];
#endif
      p += 3;
      q += 4;
     }
 
     data += rowstride;
    cairo_pixels += cairo_stride;
   }
 
   return surface;
}
Commit message: Be paranoid, use gmallocn or gmallocn3 in all gmalloc with *
CVE: CVE-2009-3605
CWE: CWE-189
Vulnerability description: Multiple integer overflows in Poppler 0.10.5 and earlier allow remote attackers to cause a denial of service (application crash) or possibly execute arbitrary code via a crafted PDF file, related to (1) glib/poppler-page.cc; (2) ArthurOutputDev.cc, (3) CairoOutputDev.cc, (4) GfxState.cc, (5) JBIG2Stream.cc, (6) PSOutputDev.cc, and (7) SplashOutputDev.cc in poppler/; and (8) SplashBitmap.cc, (9) Splash.cc, and (10) SplashFTFont.cc in splash/.  NOTE: this may overlap CVE-2009-0791.

Project: poppler

JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap):
  JBIG2Segment(segNumA)
{
  w = bitmap->w;
  h = bitmap->h;
  line = bitmap->line;

  if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) {
    error(-1, "invalid width/height");
    data = NULL;
     return;
   }
  data = (Guchar *)gmallocn(h, line + 1);
   memcpy(data, bitmap->data, h * line);
   data[h * line] = 0;
 }
Commit message: None
CVE: CVE-2017-16853
CWE: CWE-347
Vulnerability description: The DynamicMetadataProvider class in saml/saml2/metadata/impl/DynamicMetadataProvider.cpp in OpenSAML-C in OpenSAML before 2.6.1 fails to properly configure itself with the MetadataFilter plugins and does not perform critical security checks such as signature verification, enforcement of validity periods, and other checks specific to deployments, aka CPPOST-105.

Project: shibboleth

 DynamicMetadataProvider::DynamicMetadataProvider(const DOMElement* e)
    : AbstractMetadataProvider(e), MetadataProvider(e),
       m_validate(XMLHelper::getAttrBool(e, false, validate)),
         m_id(XMLHelper::getAttrString(e, "Dynamic", id)),
         m_lock(RWLock::create()),
        m_refreshDelayFactor(0.75),
        m_minCacheDuration(XMLHelper::getAttrInt(e, 600, minCacheDuration)),
        m_maxCacheDuration(XMLHelper::getAttrInt(e, 28800, maxCacheDuration)),
        m_shutdown(false),
        m_cleanupInterval(XMLHelper::getAttrInt(e, 1800, cleanupInterval)),
        m_cleanupTimeout(XMLHelper::getAttrInt(e, 1800, cleanupTimeout)),
         m_cleanup_wait(nullptr), m_cleanup_thread(nullptr)
 {
     if (m_minCacheDuration > m_maxCacheDuration) {
        Category::getInstance(SAML_LOGCAT ".Metadata.Dynamic").error(
             "minCacheDuration setting exceeds maxCacheDuration setting, lowering to match it"
             );
         m_minCacheDuration = m_maxCacheDuration;
    }

    const XMLCh* delay = e ? e->getAttributeNS(nullptr, refreshDelayFactor) : nullptr;
    if (delay && *delay) {
        auto_ptr_char temp(delay);
        m_refreshDelayFactor = atof(temp.get());
        if (m_refreshDelayFactor <= 0.0 || m_refreshDelayFactor >= 1.0) {
            Category::getInstance(SAML_LOGCAT ".MetadataProvider.Dynamic").error(
                "invalid refreshDelayFactor setting, using default"
                );
            m_refreshDelayFactor = 0.75;
        }
    }

    if (m_cleanupInterval > 0) {
        if (m_cleanupTimeout < 0)
            m_cleanupTimeout = 0;
        m_cleanup_wait = CondWait::create();
        m_cleanup_thread = Thread::create(&cleanup_fn, this);
    }
}
Commit message: CVE-2015-5330: ldb_dn_escape_value: use known string length, not strlen()

ldb_dn_escape_internal() reports the number of bytes it copied, so
lets use that number, rather than using strlen() and hoping a zero got
in the right place.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11599

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Pair-programmed-with: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
CVE: CVE-2015-5330
CWE: CWE-200
Vulnerability description: ldb before 1.1.24, as used in the AD LDAP server in Samba 4.x before 4.1.22, 4.2.x before 4.2.7, and 4.3.x before 4.3.3, mishandles string lengths, which allows remote attackers to obtain sensitive information from daemon heap memory by sending crafted packets and then reading (1) an error message or (2) a database value.

Project: samba
File: ldb_dn.c

 char *ldb_dn_escape_value(TALLOC_CTX *mem_ctx, struct ldb_val value)
 {
        char *dst;
       size_t len;
        if (!value.length)
                return NULL;
 
	/* allocate destination string, it will be at most 3 times the source */
	dst = talloc_array(mem_ctx, char, value.length * 3 + 1);
	if ( ! dst) {
		talloc_free(dst);
                return NULL;
        }
 
       len = ldb_dn_escape_internal(dst, (const char *)value.data, value.length);
 
       dst = talloc_realloc(mem_ctx, dst, char, len + 1);
       if ( ! dst) {
               talloc_free(dst);
               return NULL;
       }
       dst[len] = '\0';
        return dst;
 }
Commit message: CVE-2015-5296: libcli/smb: make sure we require signing when we demand encryption on a session

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11536

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
CVE: CVE-2015-5296
CWE: CWE-20
Vulnerability description: Samba 3.x and 4.x before 4.1.22, 4.2.x before 4.2.7, and 4.3.x before 4.3.3 supports connections that are encrypted but unsigned, which allows man-in-the-middle attackers to conduct encrypted-to-unencrypted downgrade attacks by modifying the client-server data stream, related to clidfs.c, libsmb_server.c, and smbXcli_base.c.

Project: samba
File: smbXcli_base.c

uint8_t smb2cli_session_security_mode(struct smbXcli_session *session)
{
	struct smbXcli_conn *conn = session->conn;
	uint8_t security_mode = 0;

	if (conn == NULL) {
		return security_mode;
	}

	security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
        if (conn->mandatory_signing) {
                security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
        }
       if (session->smb2->should_sign) {
               security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
       }
 
        return security_mode;
 }
Commit message: None
CVE: CVE-2019-13638
CWE: CWE-78
Vulnerability description: GNU patch through 2.7.6 is vulnerable to OS shell command injection that can be exploited by opening a crafted patch file that contains an ed style diff payload with shell metacharacters. The ed editor does not need to be present on the vulnerable system. This is different from CVE-2018-1000156.

Project: savannah

do_ed_script (char const *inname, char const *outname,
	      bool *outname_needs_removal, FILE *ofp)
{
    static char const editor_program[] = EDITOR_PROGRAM;

    file_offset beginning_of_this_line;
    size_t chars_read;
    FILE *tmpfp = 0;
    char const *tmpname;
    int tmpfd;
    pid_t pid;

    if (! dry_run && ! skip_rest_of_patch)
      {
	/* Write ed script to a temporary file.  This causes ed to abort on
	   invalid commands such as when line numbers or ranges exceed the
	   number of available lines.  When ed reads from a pipe, it rejects
	   invalid commands and treats the next line as a new command, which
	   can lead to arbitrary command execution.  */

	tmpfd = make_tempfile (&tmpname, 'e', NULL, O_RDWR | O_BINARY, 0);
	if (tmpfd == -1)
	  pfatal ("Can't create temporary file %s", quotearg (tmpname));
	tmpfp = fdopen (tmpfd, "w+b");
	if (! tmpfp)
	  pfatal ("Can't open stream for file %s", quotearg (tmpname));
      }

    for (;;) {
	char ed_command_letter;
	beginning_of_this_line = file_tell (pfp);
	chars_read = get_line ();
	if (! chars_read) {
	    next_intuit_at(beginning_of_this_line,p_input_line);
	    break;
	}
	ed_command_letter = get_ed_command_letter (buf);
	if (ed_command_letter) {
	    if (tmpfp)
		if (! fwrite (buf, sizeof *buf, chars_read, tmpfp))
		    write_fatal ();
	    if (ed_command_letter != 'd' && ed_command_letter != 's') {
	        p_pass_comments_through = true;
		while ((chars_read = get_line ()) != 0) {
		    if (tmpfp)
			if (! fwrite (buf, sizeof *buf, chars_read, tmpfp))
			    write_fatal ();
		    if (chars_read == 2  &&  strEQ (buf, ".\n"))
			break;
		}
		p_pass_comments_through = false;
	    }
	}
	else {
	    next_intuit_at(beginning_of_this_line,p_input_line);
	    break;
	}
    }
    if (!tmpfp)
      return;
    if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) == 0
	|| fflush (tmpfp) != 0)
      write_fatal ();

    if (lseek (tmpfd, 0, SEEK_SET) == -1)
      pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname));

    if (! dry_run && ! skip_rest_of_patch) {
	int exclusive = *outname_needs_removal ? 0 : O_EXCL;
	*outname_needs_removal = true;
	if (inerrno != ENOENT)
	  {
 	    *outname_needs_removal = true;
 	    copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
 	  }
 	fflush (stdout);
 
 	pid = fork();
	fflush (stdout);

 	else if (pid == 0)
 	  {
 	    dup2 (tmpfd, 0);
	    assert (outname[0] != '!' && outname[0] != '-');
	    execlp (editor_program, editor_program, "-", outname, (char  *) NULL);
 	    _exit (2);
 	  }
 	else
	  }
	else
	  {
	    int wstatus;
	    if (waitpid (pid, &wstatus, 0) == -1
	        || ! WIFEXITED (wstatus)
		|| WEXITSTATUS (wstatus) != 0)
	      fatal ("%s FAILED", editor_program);
	  }
    }
Commit message: xkb: Handle xkb formated string output safely (CVE-2017-13723)

Generating strings for XKB data used a single shared static buffer,
which offered several opportunities for errors. Use a ring of
resizable buffers instead, to avoid problems when strings end up
longer than anticipated.

Reviewed-by: Michal Srb <msrb@suse.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Julien Cristau <jcristau@debian.org>
CVE: CVE-2017-13723
CWE: CWE-119
Vulnerability description: In X.Org Server (aka xserver and xorg-server) before 1.19.4, a local attacker authenticated to the X server could overflow a global buffer, causing crashes of the X server or potentially other problems by injecting large or malformed XKB related atoms and accessing them via xkbcomp.

Project: xserver
File: xkbtext.c

 tbGetBuffer(unsigned size)
 {
    struct textBuffer *tb;
 
    tb = &textBuffer[textBufferIndex];
    textBufferIndex = (textBufferIndex + 1) % NUM_BUFFER;

    if (size > tb->size) {
        free(tb->buffer);
        tb->buffer = xnfalloc(size);
        tb->size = size;
    }
    return tb->buffer;
 }
Commit message: None
CVE: CVE-2015-1345
CWE: CWE-119
Vulnerability description: The bmexec_trans function in kwset.c in grep 2.19 through 2.21 allows local users to cause a denial of service (out-of-bounds heap read and crash) via crafted input when using the -F option.

Project: savannah

bmexec_trans (kwset_t kwset, char const *text, size_t size)
{
  unsigned char const *d1;
  char const *ep, *sp, *tp;
  int d;
  int len = kwset->mind;
  char const *trans = kwset->trans;

  if (len == 0)
    return 0;
  if (len > size)
    return -1;
  if (len == 1)
    {
      tp = memchr_kwset (text, size, kwset);
      return tp ? tp - text : -1;
    }

  d1 = kwset->delta;
  sp = kwset->target + len;
  tp = text + len;
  char gc1 = kwset->gc1;
  char gc2 = kwset->gc2;

  /* Significance of 12: 1 (initial offset) + 10 (skip loop) + 1 (md2). */
  if (size > 12 * len)
    /* 11 is not a bug, the initial offset happens only once. */
    for (ep = text + size - 11 * len; tp <= ep; )
      {
        char const *tp0 = tp;
        d = d1[U(tp[-1])], tp += d;
        d = d1[U(tp[-1])], tp += d;
        if (d != 0)
          {
            d = d1[U(tp[-1])], tp += d;
            d = d1[U(tp[-1])], tp += d;
            d = d1[U(tp[-1])], tp += d;
            if (d != 0)
              {
                d = d1[U(tp[-1])], tp += d;
                d = d1[U(tp[-1])], tp += d;
                d = d1[U(tp[-1])], tp += d;
                if (d != 0)
                  {
                    d = d1[U(tp[-1])], tp += d;
                    d = d1[U(tp[-1])], tp += d;

                    /* As a heuristic, prefer memchr to seeking by
                       delta1 when the latter doesn't advance much.  */
                    int advance_heuristic = 16 * sizeof (long);
                    if (advance_heuristic <= tp - tp0)
                      goto big_advance;
                    tp--;
                    tp = memchr_kwset (tp, text + size - tp, kwset);
                     if (! tp)
                       return -1;
                     tp++;
                    if (ep <= tp)
                      break;
                   }
               }
           }
      big_advance:;
      }

  /* Now we have only a few characters left to search.  We
     carefully avoid ever producing an out-of-bounds pointer. */
  ep = text + size;
  d = d1[U(tp[-1])];
  while (d <= ep - tp)
    {
      d = d1[U((tp += d)[-1])];
      if (d != 0)
        continue;
      if (bm_delta2_search (&tp, ep, sp, len, trans, gc1, gc2, NULL, kwset))
        return tp - text;
    }

  return -1;
}