mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
Merge branch 'main' into redsun82/rust-regenerate-models
This commit is contained in:
@@ -39,6 +39,8 @@ import java.util.stream.Stream;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.semmle.js.extractor.tsconfig.TsConfigJson;
|
||||
import com.semmle.js.extractor.tsconfig.CompilerOptions;
|
||||
import com.semmle.js.dependencies.AsyncFetcher;
|
||||
import com.semmle.js.dependencies.DependencyResolver;
|
||||
import com.semmle.js.dependencies.packument.PackageJson;
|
||||
@@ -745,6 +747,26 @@ public class AutoBuild {
|
||||
.filter(p -> !isFileTooLarge(p))
|
||||
.sorted(PATH_ORDERING)
|
||||
.collect(Collectors.toCollection(() -> new LinkedHashSet<>()));
|
||||
// gather all output directories specified in tsconfig.json files
|
||||
final List<Path> outDirs = new ArrayList<>();
|
||||
for (Path cfg : tsconfigFiles) {
|
||||
try {
|
||||
String txt = new WholeIO().read(cfg);
|
||||
TsConfigJson root = new Gson().fromJson(txt, TsConfigJson.class);
|
||||
if (root != null && root.getCompilerOptions() != null) {
|
||||
if (root.getCompilerOptions().getOutDir() == null) {
|
||||
// no outDir specified, so skip this tsconfig.json
|
||||
continue;
|
||||
}
|
||||
Path odir = cfg.getParent().resolve(root.getCompilerOptions().getOutDir()).toAbsolutePath().normalize();
|
||||
outDirs.add(odir);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore malformed tsconfig or missing fields
|
||||
}
|
||||
}
|
||||
// exclude files in output directories as configured in tsconfig.json
|
||||
filesToExtract.removeIf(f -> outDirs.stream().anyMatch(od -> f.startsWith(od)));
|
||||
|
||||
DependencyInstallationResult dependencyInstallationResult = DependencyInstallationResult.empty;
|
||||
if (!tsconfigFiles.isEmpty()) {
|
||||
@@ -796,9 +818,19 @@ public class AutoBuild {
|
||||
*/
|
||||
private boolean isFileDerivedFromTypeScriptFile(Path path, Set<Path> extractedFiles) {
|
||||
String name = path.getFileName().toString();
|
||||
if (!name.endsWith(".js"))
|
||||
// only skip JS variants when a corresponding TS/TSX file was already extracted
|
||||
if (!(name.endsWith(".js")
|
||||
|| name.endsWith(".cjs")
|
||||
|| name.endsWith(".mjs")
|
||||
|| name.endsWith(".jsx")
|
||||
|| name.endsWith(".cjsx")
|
||||
|| name.endsWith(".mjsx"))) {
|
||||
return false;
|
||||
String stem = name.substring(0, name.length() - ".js".length());
|
||||
}
|
||||
// strip off extension
|
||||
int dot = name.lastIndexOf('.');
|
||||
String stem = dot != -1 ? name.substring(0, dot) : name;
|
||||
// if a TS/TSX file with same base name was extracted, skip this file
|
||||
for (String ext : FileType.TYPESCRIPT.getExtensions()) {
|
||||
if (extractedFiles.contains(path.getParent().resolve(stem + ext))) {
|
||||
return true;
|
||||
@@ -1154,7 +1186,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path>
|
||||
}
|
||||
|
||||
// extract TypeScript projects from 'tsconfig.json'
|
||||
if (typeScriptMode == TypeScriptMode.FULL
|
||||
if (typeScriptMode != TypeScriptMode.NONE
|
||||
&& treatAsTSConfig(file.getFileName().toString())
|
||||
&& !excludes.contains(file)
|
||||
&& isFileIncluded(file)) {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.semmle.js.extractor.tsconfig;
|
||||
|
||||
public class CompilerOptions {
|
||||
private String outDir;
|
||||
|
||||
public String getOutDir() {
|
||||
return outDir;
|
||||
}
|
||||
|
||||
public void setOutDir(String outDir) {
|
||||
this.outDir = outDir;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.semmle.js.extractor.tsconfig;
|
||||
|
||||
public class TsConfigJson {
|
||||
private CompilerOptions compilerOptions;
|
||||
|
||||
public CompilerOptions getCompilerOptions() {
|
||||
return compilerOptions;
|
||||
}
|
||||
|
||||
public void setCompilerOptions(CompilerOptions compilerOptions) {
|
||||
this.compilerOptions = compilerOptions;
|
||||
}
|
||||
}
|
||||
@@ -135,6 +135,7 @@ public class AutoBuildTests {
|
||||
FileExtractors extractors) {
|
||||
for (Path f : files) {
|
||||
actual.add(f.toString());
|
||||
extractedFiles.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +176,7 @@ public class AutoBuildTests {
|
||||
|
||||
@Test
|
||||
public void basicTest() throws IOException {
|
||||
addFile(true, LGTM_SRC, "tst.js");
|
||||
addFile(false, LGTM_SRC, "tst.js");
|
||||
addFile(true, LGTM_SRC, "tst.ts");
|
||||
addFile(true, LGTM_SRC, "tst.html");
|
||||
addFile(true, LGTM_SRC, "tst.xsjs");
|
||||
@@ -203,6 +204,43 @@ public class AutoBuildTests {
|
||||
runTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipJsFilesDerivedFromTypeScriptFiles() throws IOException {
|
||||
// JS-derived files (.js, .cjs, .mjs, .jsx, .cjsx, .mjsx) should be skipped when TS indexing
|
||||
envVars.put("LGTM_INDEX_TYPESCRIPT", "basic");
|
||||
// Add TypeScript sources
|
||||
addFile(true, LGTM_SRC, "foo.ts");
|
||||
addFile(true, LGTM_SRC, "bar.tsx");
|
||||
// Add derived JS variants (should be skipped)
|
||||
addFile(false, LGTM_SRC, "foo.js");
|
||||
addFile(false, LGTM_SRC, "bar.jsx");
|
||||
addFile(false, LGTM_SRC, "foo.cjs");
|
||||
addFile(false, LGTM_SRC, "foo.mjs");
|
||||
addFile(false, LGTM_SRC, "bar.cjsx");
|
||||
addFile(false, LGTM_SRC, "bar.mjsx");
|
||||
// A normal JS file without TS counterpart should be extracted
|
||||
addFile(true, LGTM_SRC, "normal.js");
|
||||
runTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipFilesInTsconfigOutDir() throws IOException {
|
||||
envVars.put("LGTM_INDEX_TYPESCRIPT", "basic");
|
||||
// Files under outDir in tsconfig.json should be excluded
|
||||
// Create tsconfig.json with outDir set to "dist"
|
||||
addFile(true, LGTM_SRC, "tsconfig.json");
|
||||
Path config = Paths.get(LGTM_SRC.toString(), "tsconfig.json");
|
||||
Files.write(config,
|
||||
"{\"compilerOptions\":{\"outDir\":\"dist\"}}".getBytes(StandardCharsets.UTF_8));
|
||||
// Add files outside outDir (should be extracted)
|
||||
addFile(true, LGTM_SRC, "src", "app.ts");
|
||||
addFile(true, LGTM_SRC, "main.js");
|
||||
// Add files under dist/outDir (should be skipped)
|
||||
addFile(false, LGTM_SRC, "dist", "generated.js");
|
||||
addFile(false, LGTM_SRC, "dist", "sub", "x.js");
|
||||
runTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includeFile() throws IOException {
|
||||
envVars.put("LGTM_INDEX_INCLUDE", "tst.js");
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The JavaScript extractor now skips generated JavaScript files if the original TypeScript files are already present. It also skips any files in the output directory specified in the `compilerOptions` part of the `tsconfig.json` file.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Improved data flow tracking through middleware to handle default value and similar patterns.
|
||||
* Added `req._parsedUrl` as a remote input source.
|
||||
@@ -925,7 +925,7 @@ module Routing {
|
||||
private DataFlow::Node getAnAccessPathRhs(Node base, int n, string path) {
|
||||
// Assigned in the body of a route handler function, which is a middleware
|
||||
exists(RouteHandler handler | base = handler |
|
||||
result = AccessPath::getAnAssignmentTo(handler.getParameter(n).ref(), path) and
|
||||
result = AccessPath::getAnAssignmentTo(handler.getParameter(n).ref(), path).getALocalSource() and
|
||||
(
|
||||
exists(handler.getAContinuationInvocation())
|
||||
or
|
||||
|
||||
@@ -618,9 +618,9 @@ module Express {
|
||||
kind = "body" and
|
||||
this = ref.getAPropertyRead("body")
|
||||
or
|
||||
// `req.path`
|
||||
// `req.path` and `req._parsedUrl`
|
||||
kind = "url" and
|
||||
this = ref.getAPropertyRead("path")
|
||||
this = ref.getAPropertyRead(["path", "_parsedUrl"])
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
| apollo.serverSide.ts:8:39:8:64 | get(fil ... => {}) | apollo.serverSide.ts:7:36:7:44 | { files } | apollo.serverSide.ts:8:43:8:50 | file.url | The $@ of this request depends on a $@. | apollo.serverSide.ts:8:43:8:50 | file.url | URL | apollo.serverSide.ts:7:36:7:44 | { files } | user-provided value |
|
||||
| apollo.serverSide.ts:18:37:18:62 | get(fil ... => {}) | apollo.serverSide.ts:17:34:17:42 | { files } | apollo.serverSide.ts:18:41:18:48 | file.url | The $@ of this request depends on a $@. | apollo.serverSide.ts:18:41:18:48 | file.url | URL | apollo.serverSide.ts:17:34:17:42 | { files } | user-provided value |
|
||||
| axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | axiosInterceptors.serverSide.js:19:21:19:28 | req.body | axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | The $@ of this request depends on a $@. | axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | endpoint | axiosInterceptors.serverSide.js:19:21:19:28 | req.body | user-provided value |
|
||||
| serverSide2.js:17:28:17:47 | axios.get(targetUrl) | serverSide2.js:10:25:10:31 | req.url | serverSide2.js:17:38:17:46 | targetUrl | The $@ of this request depends on a $@. | serverSide2.js:17:38:17:46 | targetUrl | URL | serverSide2.js:10:25:10:31 | req.url | user-provided value |
|
||||
| serverSide2.js:20:29:20:49 | axios.g ... etUrl1) | serverSide2.js:9:43:9:56 | req._parsedUrl | serverSide2.js:20:39:20:48 | targetUrl1 | The $@ of this request depends on a $@. | serverSide2.js:20:39:20:48 | targetUrl1 | URL | serverSide2.js:9:43:9:56 | req._parsedUrl | user-provided value |
|
||||
| serverSide2.js:23:29:23:49 | axios.g ... etUrl2) | serverSide2.js:22:24:22:30 | req.url | serverSide2.js:23:39:23:48 | targetUrl2 | The $@ of this request depends on a $@. | serverSide2.js:23:39:23:48 | targetUrl2 | URL | serverSide2.js:22:24:22:30 | req.url | user-provided value |
|
||||
| serverSide2.js:26:29:26:49 | axios.g ... etUrl3) | serverSide2.js:11:24:11:30 | req.url | serverSide2.js:26:39:26:48 | targetUrl3 | The $@ of this request depends on a $@. | serverSide2.js:26:39:26:48 | targetUrl3 | URL | serverSide2.js:11:24:11:30 | req.url | user-provided value |
|
||||
| serverSide.js:18:5:18:20 | request(tainted) | serverSide.js:14:29:14:35 | req.url | serverSide.js:18:13:18:19 | tainted | The $@ of this request depends on a $@. | serverSide.js:18:13:18:19 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
|
||||
| serverSide.js:20:5:20:24 | request.get(tainted) | serverSide.js:14:29:14:35 | req.url | serverSide.js:20:17:20:23 | tainted | The $@ of this request depends on a $@. | serverSide.js:20:17:20:23 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
|
||||
| serverSide.js:24:5:24:20 | request(options) | serverSide.js:14:29:14:35 | req.url | serverSide.js:23:19:23:25 | tainted | The $@ of this request depends on a $@. | serverSide.js:23:19:23:25 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
|
||||
@@ -63,6 +67,18 @@ edges
|
||||
| axiosInterceptors.serverSide.js:19:21:19:28 | req.body | axiosInterceptors.serverSide.js:19:11:19:17 | { url } | provenance | |
|
||||
| axiosInterceptors.serverSide.js:20:5:20:25 | userProvidedUrl | axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | provenance | |
|
||||
| axiosInterceptors.serverSide.js:20:23:20:25 | url | axiosInterceptors.serverSide.js:20:5:20:25 | userProvidedUrl | provenance | |
|
||||
| serverSide2.js:9:34:9:63 | qs.pars ... .query) | serverSide2.js:19:24:19:51 | req.par ... rsedUrl | provenance | |
|
||||
| serverSide2.js:9:43:9:56 | req._parsedUrl | serverSide2.js:9:34:9:63 | qs.pars ... .query) | provenance | |
|
||||
| serverSide2.js:10:25:10:31 | req.url | serverSide2.js:16:23:16:41 | req.parsedQuery.url | provenance | |
|
||||
| serverSide2.js:11:24:11:30 | req.url | serverSide2.js:25:24:25:41 | req.SomeObject.url | provenance | |
|
||||
| serverSide2.js:16:11:16:41 | targetUrl | serverSide2.js:17:38:17:46 | targetUrl | provenance | |
|
||||
| serverSide2.js:16:23:16:41 | req.parsedQuery.url | serverSide2.js:16:11:16:41 | targetUrl | provenance | |
|
||||
| serverSide2.js:19:11:19:55 | targetUrl1 | serverSide2.js:20:39:20:48 | targetUrl1 | provenance | |
|
||||
| serverSide2.js:19:24:19:51 | req.par ... rsedUrl | serverSide2.js:19:11:19:55 | targetUrl1 | provenance | |
|
||||
| serverSide2.js:22:11:22:36 | targetUrl2 | serverSide2.js:23:39:23:48 | targetUrl2 | provenance | |
|
||||
| serverSide2.js:22:24:22:30 | req.url | serverSide2.js:22:11:22:36 | targetUrl2 | provenance | |
|
||||
| serverSide2.js:25:11:25:47 | targetUrl3 | serverSide2.js:26:39:26:48 | targetUrl3 | provenance | |
|
||||
| serverSide2.js:25:24:25:41 | req.SomeObject.url | serverSide2.js:25:11:25:47 | targetUrl3 | provenance | |
|
||||
| serverSide.js:14:9:14:52 | tainted | serverSide.js:18:13:18:19 | tainted | provenance | |
|
||||
| serverSide.js:14:9:14:52 | tainted | serverSide.js:20:17:20:23 | tainted | provenance | |
|
||||
| serverSide.js:14:9:14:52 | tainted | serverSide.js:23:19:23:25 | tainted | provenance | |
|
||||
@@ -163,6 +179,22 @@ nodes
|
||||
| axiosInterceptors.serverSide.js:19:21:19:28 | req.body | semmle.label | req.body |
|
||||
| axiosInterceptors.serverSide.js:20:5:20:25 | userProvidedUrl | semmle.label | userProvidedUrl |
|
||||
| axiosInterceptors.serverSide.js:20:23:20:25 | url | semmle.label | url |
|
||||
| serverSide2.js:9:34:9:63 | qs.pars ... .query) | semmle.label | qs.pars ... .query) |
|
||||
| serverSide2.js:9:43:9:56 | req._parsedUrl | semmle.label | req._parsedUrl |
|
||||
| serverSide2.js:10:25:10:31 | req.url | semmle.label | req.url |
|
||||
| serverSide2.js:11:24:11:30 | req.url | semmle.label | req.url |
|
||||
| serverSide2.js:16:11:16:41 | targetUrl | semmle.label | targetUrl |
|
||||
| serverSide2.js:16:23:16:41 | req.parsedQuery.url | semmle.label | req.parsedQuery.url |
|
||||
| serverSide2.js:17:38:17:46 | targetUrl | semmle.label | targetUrl |
|
||||
| serverSide2.js:19:11:19:55 | targetUrl1 | semmle.label | targetUrl1 |
|
||||
| serverSide2.js:19:24:19:51 | req.par ... rsedUrl | semmle.label | req.par ... rsedUrl |
|
||||
| serverSide2.js:20:39:20:48 | targetUrl1 | semmle.label | targetUrl1 |
|
||||
| serverSide2.js:22:11:22:36 | targetUrl2 | semmle.label | targetUrl2 |
|
||||
| serverSide2.js:22:24:22:30 | req.url | semmle.label | req.url |
|
||||
| serverSide2.js:23:39:23:48 | targetUrl2 | semmle.label | targetUrl2 |
|
||||
| serverSide2.js:25:11:25:47 | targetUrl3 | semmle.label | targetUrl3 |
|
||||
| serverSide2.js:25:24:25:41 | req.SomeObject.url | semmle.label | req.SomeObject.url |
|
||||
| serverSide2.js:26:39:26:48 | targetUrl3 | semmle.label | targetUrl3 |
|
||||
| serverSide.js:14:9:14:52 | tainted | semmle.label | tainted |
|
||||
| serverSide.js:14:19:14:42 | url.par ... , true) | semmle.label | url.par ... , true) |
|
||||
| serverSide.js:14:29:14:35 | req.url | semmle.label | req.url |
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
const express = require('express');
|
||||
const axios = require('axios');
|
||||
const qs = require('qs');
|
||||
|
||||
const app = express();
|
||||
const PORT = 3000;
|
||||
|
||||
app.use((req, res, next) => {
|
||||
req.parsedQueryFromParsedUrl = qs.parse(req._parsedUrl.query); // $Source[js/request-forgery]
|
||||
req.parsedQuery.url = req.url || {}; // $Source[js/request-forgery]
|
||||
req.SomeObject.url = req.url; // $Source[js/request-forgery]
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/proxy', async (req, res) => {
|
||||
const targetUrl = req.parsedQuery.url;
|
||||
const response = await axios.get(targetUrl); // $Alert[js/request-forgery]
|
||||
|
||||
const targetUrl1 = req.parsedQueryFromParsedUrl.url;
|
||||
const response1 = await axios.get(targetUrl1); // $Alert[js/request-forgery]
|
||||
|
||||
const targetUrl2 = req.url || {}; // $Source[js/request-forgery]
|
||||
const response2 = await axios.get(targetUrl2); // $Alert[js/request-forgery]
|
||||
|
||||
const targetUrl3 = req.SomeObject.url || {};
|
||||
const response3 = await axios.get(targetUrl3); // $Alert[js/request-forgery]
|
||||
});
|
||||
@@ -1,29 +1,29 @@
|
||||
multiplePathResolutions
|
||||
| main.rs:218:14:218:17 | libc | file://:0:0:0:0 | Crate(libc@0.2.173) |
|
||||
| main.rs:218:14:218:17 | libc | file://:0:0:0:0 | Crate(libc@0.2.172) |
|
||||
| main.rs:218:14:218:17 | libc | file://:0:0:0:0 | Crate(libc@0.2.174) |
|
||||
| main.rs:218:14:218:25 | ...::malloc | file://:0:0:0:0 | fn malloc |
|
||||
| main.rs:218:14:218:25 | ...::malloc | file://:0:0:0:0 | fn malloc |
|
||||
| main.rs:219:13:219:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.173) |
|
||||
| main.rs:219:13:219:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.172) |
|
||||
| main.rs:219:13:219:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.174) |
|
||||
| main.rs:219:13:219:24 | ...::malloc | file://:0:0:0:0 | fn malloc |
|
||||
| main.rs:219:13:219:24 | ...::malloc | file://:0:0:0:0 | fn malloc |
|
||||
| main.rs:220:13:220:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.173) |
|
||||
| main.rs:220:13:220:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.172) |
|
||||
| main.rs:220:13:220:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.174) |
|
||||
| main.rs:220:13:220:31 | ...::aligned_alloc | file://:0:0:0:0 | fn aligned_alloc |
|
||||
| main.rs:220:13:220:31 | ...::aligned_alloc | file://:0:0:0:0 | fn aligned_alloc |
|
||||
| main.rs:221:13:221:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.173) |
|
||||
| main.rs:221:13:221:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.172) |
|
||||
| main.rs:221:13:221:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.174) |
|
||||
| main.rs:221:13:221:31 | ...::aligned_alloc | file://:0:0:0:0 | fn aligned_alloc |
|
||||
| main.rs:221:13:221:31 | ...::aligned_alloc | file://:0:0:0:0 | fn aligned_alloc |
|
||||
| main.rs:222:13:222:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.173) |
|
||||
| main.rs:222:13:222:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.172) |
|
||||
| main.rs:222:13:222:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.174) |
|
||||
| main.rs:222:13:222:24 | ...::calloc | file://:0:0:0:0 | fn calloc |
|
||||
| main.rs:222:13:222:24 | ...::calloc | file://:0:0:0:0 | fn calloc |
|
||||
| main.rs:223:13:223:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.173) |
|
||||
| main.rs:223:13:223:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.172) |
|
||||
| main.rs:223:13:223:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.174) |
|
||||
| main.rs:223:13:223:24 | ...::calloc | file://:0:0:0:0 | fn calloc |
|
||||
| main.rs:223:13:223:24 | ...::calloc | file://:0:0:0:0 | fn calloc |
|
||||
| main.rs:224:13:224:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.173) |
|
||||
| main.rs:224:13:224:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.172) |
|
||||
| main.rs:224:13:224:16 | libc | file://:0:0:0:0 | Crate(libc@0.2.174) |
|
||||
| main.rs:224:13:224:25 | ...::realloc | file://:0:0:0:0 | fn realloc |
|
||||
| main.rs:224:13:224:25 | ...::realloc | file://:0:0:0:0 | fn realloc |
|
||||
|
||||
@@ -4,9 +4,9 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.173"
|
||||
version = "0.2.174"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb"
|
||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||
|
||||
[[package]]
|
||||
name = "test"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
qltest_use_nightly: true
|
||||
qltest_dependencies:
|
||||
- libc = { version = "0.2.11" }
|
||||
- libc = { version = "0.2.174" }
|
||||
|
||||
Reference in New Issue
Block a user