Merge changes from topic "no_staticlinking_to_stubs"
* changes: Prevent statically linking to a lib providing stable C APIs Add GetPathString
This commit is contained in:
commit
06938a0a16
4 changed files with 123 additions and 28 deletions
|
@ -19,6 +19,7 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
|
||||
|
@ -135,6 +136,13 @@ type BaseModuleContext interface {
|
|||
// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
|
||||
GetTagPath() []blueprint.DependencyTag
|
||||
|
||||
// GetPathString is supposed to be called in visit function passed in WalkDeps()
|
||||
// and returns a multi-line string showing the modules and dependency tags
|
||||
// among them along the top-down dependency path from a start module to current child module.
|
||||
// skipFirst when set to true, the output doesn't include the start module,
|
||||
// which is already printed when this function is used along with ModuleErrorf().
|
||||
GetPathString(skipFirst bool) string
|
||||
|
||||
AddMissingDependencies(missingDeps []string)
|
||||
|
||||
Target() Target
|
||||
|
@ -1734,6 +1742,41 @@ func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
|
|||
return b.tagPath
|
||||
}
|
||||
|
||||
// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
|
||||
// a dependency tag.
|
||||
var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`)
|
||||
|
||||
// PrettyPrintTag returns string representation of the tag, but prefers
|
||||
// custom String() method if available.
|
||||
func PrettyPrintTag(tag blueprint.DependencyTag) string {
|
||||
// Use tag's custom String() method if available.
|
||||
if stringer, ok := tag.(fmt.Stringer); ok {
|
||||
return stringer.String()
|
||||
}
|
||||
|
||||
// Otherwise, get a default string representation of the tag's struct.
|
||||
tagString := fmt.Sprintf("%#v", tag)
|
||||
|
||||
// Remove the boilerplate from BaseDependencyTag as it adds no value.
|
||||
tagString = tagCleaner.ReplaceAllString(tagString, "")
|
||||
return tagString
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) GetPathString(skipFirst bool) string {
|
||||
sb := strings.Builder{}
|
||||
tagPath := b.GetTagPath()
|
||||
walkPath := b.GetWalkPath()
|
||||
if !skipFirst {
|
||||
sb.WriteString(walkPath[0].String())
|
||||
}
|
||||
for i, m := range walkPath[1:] {
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(fmt.Sprintf(" via tag %s\n", PrettyPrintTag(tagPath[i])))
|
||||
sb.WriteString(fmt.Sprintf(" -> %s", m.String()))
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
|
||||
m.bp.VisitAllModuleVariants(func(module blueprint.Module) {
|
||||
visit(module.(Module))
|
||||
|
|
69
apex/apex.go
69
apex/apex.go
|
@ -18,7 +18,6 @@ import (
|
|||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -1811,24 +1810,6 @@ func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int {
|
|||
return intVer
|
||||
}
|
||||
|
||||
// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
|
||||
// a dependency tag.
|
||||
var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`)
|
||||
|
||||
func PrettyPrintTag(tag blueprint.DependencyTag) string {
|
||||
// Use tag's custom String() method if available.
|
||||
if stringer, ok := tag.(fmt.Stringer); ok {
|
||||
return stringer.String()
|
||||
}
|
||||
|
||||
// Otherwise, get a default string representation of the tag's struct.
|
||||
tagString := fmt.Sprintf("%#v", tag)
|
||||
|
||||
// Remove the boilerplate from BaseDependencyTag as it adds no value.
|
||||
tagString = tagCleaner.ReplaceAllString(tagString, "")
|
||||
return tagString
|
||||
}
|
||||
|
||||
// Ensures that the dependencies are marked as available for this APEX
|
||||
func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
|
||||
// Let's be practical. Availability for test, host, and the VNDK apex isn't important
|
||||
|
@ -1863,14 +1844,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
|
|||
if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
|
||||
return true
|
||||
}
|
||||
message := ""
|
||||
tagPath := ctx.GetTagPath()
|
||||
// Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf().
|
||||
walkPath := ctx.GetWalkPath()[1:]
|
||||
for i, m := range walkPath {
|
||||
message = fmt.Sprintf("%s\n via tag %s\n -> %s", message, PrettyPrintTag(tagPath[i]), m.String())
|
||||
}
|
||||
ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message)
|
||||
ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, ctx.GetPathString(true))
|
||||
// Visit this module's dependencies to check and report any issues with their availability.
|
||||
return true
|
||||
})
|
||||
|
@ -1886,6 +1860,44 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) {
|
|||
}
|
||||
}
|
||||
|
||||
// Ensures that a lib providing stub isn't statically linked
|
||||
func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) {
|
||||
// Practically, we only care about regular APEXes on the device.
|
||||
if ctx.Host() || a.testApex || a.vndkApex {
|
||||
return
|
||||
}
|
||||
|
||||
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
|
||||
if ccm, ok := to.(*cc.Module); ok {
|
||||
apexName := ctx.ModuleName()
|
||||
fromName := ctx.OtherModuleName(from)
|
||||
toName := ctx.OtherModuleName(to)
|
||||
|
||||
// If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither
|
||||
// do any of its dependencies.
|
||||
if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
|
||||
// As soon as the dependency graph crosses the APEX boundary, don't go further.
|
||||
return false
|
||||
}
|
||||
|
||||
// The dynamic linker and crash_dump tool in the runtime APEX is the only exception to this rule.
|
||||
// It can't make the static dependencies dynamic because it can't
|
||||
// do the dynamic linking for itself.
|
||||
if apexName == "com.android.runtime" && (fromName == "linker" || fromName == "crash_dump") {
|
||||
return false
|
||||
}
|
||||
|
||||
isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !android.DirectlyInApex(apexName, toName)
|
||||
if isStubLibraryFromOtherApex && !externalDep {
|
||||
ctx.ModuleErrorf("%q required by %q is a native library providing stub. "+
|
||||
"It shouldn't be included in this APEX via static linking. Dependency path: %s", to.String(), fromName, ctx.GetPathString(false))
|
||||
}
|
||||
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
|
||||
switch a.properties.ApexType {
|
||||
|
@ -1923,6 +1935,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
|
||||
a.checkApexAvailability(ctx)
|
||||
a.checkUpdatable(ctx)
|
||||
a.checkStaticLinkingToStubLibraries(ctx)
|
||||
|
||||
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
|
||||
|
||||
|
@ -2134,7 +2147,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
|
||||
}
|
||||
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
|
||||
ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName)
|
||||
ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4774,6 +4774,42 @@ func TestTestFor(t *testing.T) {
|
|||
ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
|
||||
}
|
||||
|
||||
func TestNoStaticLinkingToStubsLib(t *testing.T) {
|
||||
testApexError(t, `.*required by "mylib" is a native library providing stub.*`, `
|
||||
apex {
|
||||
name: "myapex",
|
||||
key: "myapex.key",
|
||||
native_shared_libs: ["mylib"],
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "myapex.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "mylib",
|
||||
srcs: ["mylib.cpp"],
|
||||
static_libs: ["otherlib"],
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
apex_available: [ "myapex" ],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "otherlib",
|
||||
srcs: ["mylib.cpp"],
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
stubs: {
|
||||
versions: ["1", "2", "3"],
|
||||
},
|
||||
apex_available: [ "myapex" ],
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
run := func() int {
|
||||
setUp()
|
||||
|
|
3
cc/cc.go
3
cc/cc.go
|
@ -2862,6 +2862,9 @@ func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu
|
|||
return false
|
||||
}
|
||||
}
|
||||
} else if ctx.OtherModuleDependencyTag(dep) == llndkImplDep {
|
||||
// We don't track beyond LLNDK
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue