168d75effSDimitry Andric //===-- ubsan_monitor.cpp ---------------------------------------*- C++ -*-===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // Hooks which allow a monitor process to inspect UBSan's diagnostics.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "ubsan_monitor.h"
1468d75effSDimitry Andric 
1568d75effSDimitry Andric using namespace __ubsan;
1668d75effSDimitry Andric 
UndefinedBehaviorReport(const char * IssueKind,Location & Loc,InternalScopedString & Msg)1768d75effSDimitry Andric UndefinedBehaviorReport::UndefinedBehaviorReport(const char *IssueKind,
1868d75effSDimitry Andric                                                  Location &Loc,
1968d75effSDimitry Andric                                                  InternalScopedString &Msg)
20fe6060f1SDimitry Andric     : IssueKind(IssueKind), Loc(Loc) {
2168d75effSDimitry Andric   // We have the common sanitizer reporting lock, so it's safe to register a
2268d75effSDimitry Andric   // new UB report.
2368d75effSDimitry Andric   RegisterUndefinedBehaviorReport(this);
2468d75effSDimitry Andric 
2568d75effSDimitry Andric   // Make a copy of the diagnostic.
26*5f757f3fSDimitry Andric   if (Msg.length())
27*5f757f3fSDimitry Andric     Buffer.Append(Msg.data());
2868d75effSDimitry Andric 
2968d75effSDimitry Andric   // Let the monitor know that a report is available.
3068d75effSDimitry Andric   __ubsan_on_report();
3168d75effSDimitry Andric }
3268d75effSDimitry Andric 
3368d75effSDimitry Andric static UndefinedBehaviorReport *CurrentUBR;
3468d75effSDimitry Andric 
RegisterUndefinedBehaviorReport(UndefinedBehaviorReport * UBR)3568d75effSDimitry Andric void __ubsan::RegisterUndefinedBehaviorReport(UndefinedBehaviorReport *UBR) {
3668d75effSDimitry Andric   CurrentUBR = UBR;
3768d75effSDimitry Andric }
3868d75effSDimitry Andric 
3968d75effSDimitry Andric SANITIZER_WEAK_DEFAULT_IMPL
__ubsan_on_report(void)4068d75effSDimitry Andric void __ubsan::__ubsan_on_report(void) {}
4168d75effSDimitry Andric 
__ubsan_get_current_report_data(const char ** OutIssueKind,const char ** OutMessage,const char ** OutFilename,unsigned * OutLine,unsigned * OutCol,char ** OutMemoryAddr)4268d75effSDimitry Andric void __ubsan::__ubsan_get_current_report_data(const char **OutIssueKind,
4368d75effSDimitry Andric                                               const char **OutMessage,
4468d75effSDimitry Andric                                               const char **OutFilename,
4568d75effSDimitry Andric                                               unsigned *OutLine,
4668d75effSDimitry Andric                                               unsigned *OutCol,
4768d75effSDimitry Andric                                               char **OutMemoryAddr) {
4868d75effSDimitry Andric   if (!OutIssueKind || !OutMessage || !OutFilename || !OutLine || !OutCol ||
4968d75effSDimitry Andric       !OutMemoryAddr)
5068d75effSDimitry Andric     UNREACHABLE("Invalid arguments passed to __ubsan_get_current_report_data");
5168d75effSDimitry Andric 
5268d75effSDimitry Andric   InternalScopedString &Buf = CurrentUBR->Buffer;
5368d75effSDimitry Andric 
5468d75effSDimitry Andric   // Ensure that the first character of the diagnostic text can't start with a
5568d75effSDimitry Andric   // lowercase letter.
56fe6060f1SDimitry Andric   char FirstChar = *Buf.data();
5768d75effSDimitry Andric   if (FirstChar >= 'a' && FirstChar <= 'z')
58fe6060f1SDimitry Andric     *Buf.data() += 'A' - 'a';
5968d75effSDimitry Andric 
6068d75effSDimitry Andric   *OutIssueKind = CurrentUBR->IssueKind;
6168d75effSDimitry Andric   *OutMessage = Buf.data();
6268d75effSDimitry Andric   if (!CurrentUBR->Loc.isSourceLocation()) {
6368d75effSDimitry Andric     *OutFilename = "<unknown>";
6468d75effSDimitry Andric     *OutLine = *OutCol = 0;
6568d75effSDimitry Andric   } else {
6668d75effSDimitry Andric     SourceLocation SL = CurrentUBR->Loc.getSourceLocation();
6768d75effSDimitry Andric     *OutFilename = SL.getFilename();
6868d75effSDimitry Andric     *OutLine = SL.getLine();
6968d75effSDimitry Andric     *OutCol = SL.getColumn();
7068d75effSDimitry Andric   }
7168d75effSDimitry Andric 
7268d75effSDimitry Andric   if (CurrentUBR->Loc.isMemoryLocation())
7368d75effSDimitry Andric     *OutMemoryAddr = (char *)CurrentUBR->Loc.getMemoryLocation();
7468d75effSDimitry Andric   else
7568d75effSDimitry Andric     *OutMemoryAddr = nullptr;
7668d75effSDimitry Andric }
77