<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Thrown exception jumps to wrong catch, resulting in incorrectly unhandled exceptions"
   href="https://bugs.llvm.org/show_bug.cgi?id=42221">42221</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Thrown exception jumps to wrong catch, resulting in incorrectly unhandled exceptions
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>lld
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Windows NT
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>COFF
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>akrieger@fb.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>We've recently seen a fairly reliably reproducible error cause by what seems to
be bad exception handling codegen. Unfortunately, the code in question is part
of a large complex project and a minimal repro case was not able to be
generated.

>From observations in the VS debugger, we see the following call stack / code
structure and steps when handling exceptions. The following is my best attempt
to describe the issue.

The 'entry point' to the stack is in one translation unit:

MetadataStorage.cpp:
```
std::string MetadataStorage::getString(const std::string& key) {
  std::string sql = dbqueries::MetadataGetValue::getSql();
  auto stmt = db_->prepareRead(sql);                                         
#1
  stmt->bind(dbqueries::MetadataGetValue::PLACEHOLDER_KEY, key);

  if (!stmt->step()) {
    throw MetadataStorage::KeyNotFoundError(key);
  }

  return stmt->getText(dbqueries::MetadataGetValue::COLUMN_VALUE);
}
```

Call #1 is where the problem occurs. #1 goes to `SqliteData::prepareRead` in
the next file,
where we call `db_.prepare(sql)` (#3):

SqliteDatabase.cpp:
```
SqliteDatabase::SqliteDatabase(const std::string& filename, int flags) try
    : db_(filename, flags),
      dbFilename_(filename) {
} catch (const sqlite::SQLiteException& e) {
  throw clientdb::DatabaseException(e.what(), e.getExtendedErrorCode());     
#2
}

SqliteDatabase::SqliteDatabase(sqlite3* db) : db_(db), dbFilename_("") {}

std::unique_ptr<clientdb::ReadStatement> SqliteDatabase::prepareRead(
    const std::string& sql) {
  try { 
    return std::make_unique<SqliteReadStatement>(db_.prepare(sql));          
#3
  } catch (const sqlite::SQLiteException& e) {
    throw clientdb::DatabaseException(e.what(), e.getExtendedErrorCode());   
#4
  }
}
```

`db_.prepare(sql)` goes to a third TU:
Database.cpp:
```
Statement Database::prepare(const std::string& sql) {
  sqlite3_stmt* stmt;
  int ret = sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr);
  if (ret != SQLITE_OK) {
    std::string strerr = sqlite3_errmsg(db_);
    int errCode = sqlite3_extended_errcode(db_);
    sqlite3_finalize(stmt);
    throw SQLiteException(strerr, errCode);                                  
#5
  }
  return Statement(*this, stmt);
}
```

What we see is the call stack goes roughly like this:
#1
#3
#5

At #5, `SQLiteException` is thrown. We would expect the catch in `prepareRead`
to fire and statement #4 to execute. Instead, the VS debugger shows control
passes to #2 (an identically formed exception handler in the same TU). From
here, the exception handling logic eventually calls terminate() and thus
abort().

Repros with: lld 7.0.0, lld 8.0.0
Does not repro with: MS link.exe, lld 9.0.0 latest snapshot (see notes below),

Notes:
- The first time this bug presented, it was masked by solving an (undetected)
multiple symbols issue in unrelated TUs linked into the final binary. The
functions were defined in a header but not marked inline. link.exe correctly
warned about this. Making them be marked inline seemed to 'resolve' the
problem, but it has since returned, in exactly the same stack and behavior.
- lld 9.0.0 most recent snapshot does _not_ reproduce the issue. However, the
fix bisects to <a href="https://reviews.llvm.org/D59797">https://reviews.llvm.org/D59797</a>, which looks completely
unrelated to exception handling. In conjunction with the previous fix about
inlining/not inlining functions, it's possible there was a symbol ordering
change which just masks the underlying issue and doesn't solve it.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>